代码改变世界

详细介绍:RPC与RPC框架Dubbo详解

2026-01-16 15:26  tlnshuju  阅读(1)  评论(0)    收藏  举报

本文总结:本文介绍了RPC(远程过程调用)的基本概念、工作流程及与HTTP的区别。RPC允许程序像调用本地方法一样调用远程服务,通过提供者、调用方和注册中心三个角色实现。文章对比了RPC与HTTP在设计、协议性能、服务治理等方面的差异,并详细讲解了Dubbo框架的两种使用方式和核心特性。最后指出RPC适合微服务内部通信,而HTTP更适合对外API,实际项目中常结合两者优势使用。

前言

在介绍RPC之前,我们先设想一个场景:你在项目A写了一个非常nice好用的函数,你在项目B要调用这个函数,但是项目A和项目B是独立运行的,既不共享内存,也不共享进程,那该怎么做才能直接调用呢?可能很多人第一反应就是HTTP请求来建立连接,确实可行,但是HTTP请求的步骤有点繁琐,而RPC会更舒服一点,就像调用本地方法一样直接调用。

我补充一下,调用其它项目的方法主要常用的有4种:

1.复制代码和依赖、环境

2.HTTP 请求(提供一个接口,供其他项目调用)

3. RPC

4.把公共的代码打个jar 包,其他项目去引用(客户端 SDK)

1、首先是直接复制粘贴别的项目的方法,然而这可能引发环境依赖和代码问题,因为项目之间各自有独特的设置和条件。

2、另一个方法是使用 HTTP 请求,简单说就是提供方开发一个接口(地址、请求方法、参数、返回值),调用方使用 HTTP Client 之类的代码包去发送 HTTP 请求

3、RPC,本文会详细介绍

4、此外,还有一种常见的方法是将公共代码打包成一个jar 包,供其他项目引用,这种方法在项目中很常见

RPC介绍

什么是RPC呢?RPC(Remote Procedure Call)远程过程调用:允许程序调用另一个地址空间(通常是远程机器)上的函数或方法,就像调用本地函数一样简单。
想象你在一家餐厅点餐:

本地调用:你直接走进厨房告诉厨师做什么菜

RPC调用:你告诉服务员(客户端存根),服务员去厨房(服务器)让厨师做菜,然后服务员把菜端回来给你

RPC的一个关键优势在于,它可以使用多种底层协议进行远程调用,而不限于 HTTP 协议。虽然 HTTP 协议可以实现类似的功能,但考虑到性能,RPC 可以选择更原生的协议,如 TCP/IP。而且,还存在其他性能更高的协议,可以根据需要进行选择。

在微服务项目中,对于内部接口,使用 RPC可能会获得更好的性能。然而,选择使用Feign 还是 RPC 取决于具体的技术需求,没有绝对的优劣之分。需要注意的是,RPC和 HTTP 请求可以结合使用,因为 RPC 的底层协议可以是 HTTP,也可以是其他协议,如TCP/IP 或自定义协议。

Feign:本质上也是动态生成的 HTTP 客户端,但它在调用远程方法时更加精简了 HTTP 请求的步骤。尽管 Feign 使远程调用看起来像是调用本地方法,但实际上与RPC仍然有一些微小的区别。虽然两者都可以实现类似的功能,但它们在底层协议上存在差异。

总而言之:RPC它的最大作用在于模拟本地方法调用的体验。看上去是请求本地代码,实际上,它可能会请求到其他项目、其他服务器等等。这就是 RPC 的最大价值所在。你不需要了解它是如何在 HTTP Client 中怎么封装参数,只需直接调用现成的方法即可,这样可以大大减少沟通成本。

RPC工作流程

先引入一个简单的概念,为了实现 RPC,我们需要几个关键角色:

1、提供者(Producer/Provider): 首先,我们需要一个项目来提供方法,这个项目被称为提供者。它的主要任务是为其他人提供已经写好的代码,让其他人可以使用。举例来说,我们可以提供一个名为 invoke的方法。

2、调用方(invoker/Consumer): 一旦服务提供者提供了服务,调用方需要能够找到这个服务的位置。这就需要一个存储,用于存储已提供的方法,调用方需要知道提供者的地址和 invoke方法,这里需要一个公共的存储。

3、存储:这是一个公共存储,用于存储提供者提供的方法信息。调用方可以从这个存储中获取提供者的地址和方法信息。

这三个角色构成了整个 RPC 模型。

客户端调用 → 客户端存根 → 序列化 → 网络传输 →
服务器接收 → 反序列化 → 服务器存根 → 实际服务 →
返回结果(反向流程)

存储有时也会被称为注册中心,它管理着服务信息,包括提供者的IP 地址等等。调用方从这里获取信息,以便进行调用。

以购物系统为例:
用户购买商品:

步骤1:客户端发起调用

步骤2: 客户端存根处理(透明完成),(1)生成调用ID、( 2)序列化参数、( 3)添加头部信息

步骤3:网络传输,使用TCP/HTTP等协议发送数据包

步骤4:服务器存根处理,(1)反序列化请求、(2)查找对应的服务和方法、(3)调用真实业务逻辑

步骤5:业务处理,(1)检查库存、(2)扣减库存、(3)创建订单、(4)返回订单号

注意:需要注意的是在整个流程中,最终的调用并不是由注册中心来完成的。虽然注册中心会提供信息,但实际上调用方需要自己进行最后的调用动作。注册中心的作用是告诉调用方提供者的地址等信息,然后调用方会根据这些信息来完成最后的调用。

一般情况下,调用方会直接寻找提供者进行调用,而不是依赖注册中心来完成实际的调用过程。注册中心主要的功能是提供地址信息,而并不会承担将调用方所需的内容传送到提供者的角色。

RPC与HTTP区别

RPC和HTTP的主要区别可以从五个维度来看:

  1. 设计:RPC追求远程调用像本地调用一样透明,是方法调用导向;而HTTP是超文本传输协议,是资源操作导向。
  2. 协议性能:RPC向远程服务器发送请求时,未必要使用 HTTP 协议,比如还可以用 TCP/IP,性能更高。(内部服务更适用)。
  3. 服务治理:RPC框架如Dubbo、gRPC内置了服务发现、负载均衡、熔断降级等治理能力;HTTP需要借助API网关、注册中心等额外组件。
  4. 开发体验:RPC通过IDL定义接口,自动生成代码,强类型支持;HTTP需要手动处理请求构造和序列化。
  5. 适用场景:RPC适合微服务内部通信,对性能要求高的场景;HTTP适合对外提供API、需要浏览器直接访问的场景。

RPC框架Dubbo

Dubbo它是非常主流的 RPC 实现框架,当然,还有其他类似的框架,比如GRPC和 TRPC 、Thrift等等,这些都是不同的 RPC远程调用框架,Dubbo 和 GRPC是比较知名的。Dubbo 由阿里开发,而 GRPC 是由 Google 开发,TRPC 则是由腾讯开发。

有时间建议阅读 Dubbo 框架的官方文档,会帮助你更好地理解这个框架。

Dubbo的两种使用方式:

1、Spring Boot 代码(注解+ 编程式):写 Java 接口,服务提供者和消费者都去引用这个接口。

2、IDL(接口调用语言):创建一个公共的接口定义文件,服务提供者和消费者读取这个文件。优点是跨语言所有的框架都认识。

IDL 是什么呢?

IDL(接口定义语言)是一种约定俗成的语言,用于定义接口和数据结构的语法。它是一种人为约定的语言,通过这种语法,可以明确地定义接口和数据的结构,使各方在交流和协作时能够达成一致。这种约定的语言为不同的系统、平台或语言提供了一种统一的描述方式,使得不同环境下的应用程序能够理解和交互。

Dubbo底层用的是 Triple 协议:Triple 协议

可以自行通过Dubbo的git仓库git clone拉取它的源码阅读,下面是跑通Dubbo示例项目源码的要点:

zookeeper 注册中心:是通过内嵌的方式运行,更方便。

启动流程:最先启动注册中心,启动服务提供者,再启动服务消费者

Zookeeper 是什么呢?

有学过的话,就知道 Zookeeper 就是我们之前图中所提到的注册中心。Dubbo 的作用就是将你的提供者、调用方和注册中心这三者通过其框架整合在一起,从而完成整个远程过程调用(RPC)。因此,Dubbo 可以被视为一个实现了 RPC功能的框架,而Zookeeper 则是一个可作为注册中心的存储,Nacos 也可以作为注册中心。

Dubbo核心特性

服务治理能力

// 1. 负载均衡(4种策略)
@Reference(loadbalance = "random") // 随机(默认)
@Reference(loadbalance = "roundrobin") // 轮询
@Reference(loadbalance = "leastactive") // 最少活跃调用数
@Reference(loadbalance = "consistenthash") // 一致性哈希
// 2. 集群容错(6种模式)
@Reference(cluster = "failover") // 失败自动切换(默认)
@Reference(cluster = "failfast") // 快速失败,只发起一次调用
@Reference(cluster = "failsafe") // 失败安全,忽略异常
@Reference(cluster = "failback") // 失败自动恢复
@Reference(cluster = "forking") // 并行调用多个服务器
@Reference(cluster = "broadcast") // 广播调用所有提供者
// 3. 服务降级
@Reference(mock = "force:return null") // 强制降级
@Reference(mock = "fail:return null")  // 失败时降级

高级特性

# 1. 服务分组(实现接口多版本)
dubbo:
  service:
    group: userServiceV2  # 服务分组
# 2. 版本控制(灰度发布)
@Reference(version = "1.0.0")
# 3. 异步调用
@Reference(async = true)
# 调用方式:RpcContext.getContext().asyncCall()
# 4. 泛化调用(无需接口直接调用)
GenericService genericService = ...
Object result = genericService.$invoke("methodName",
  new String[]{"java.lang.String"}, new Object[]{"param"});

Dubbo与Cloud的对比

核心区别:Dubbo是RPC框架,专注服务调用;Spring Cloud是微服务全家桶。

Dubbo使用场景

适合场景:

  1. 大型分布式系统 - 阿里系电商架构验证
  2. 高并发场景 - 高性能RPC调用
  3. 复杂服务治理需求 - 内置丰富治理策略
  4. Java技术栈为主 - 对Java生态支持最好

不适合场景:

  1. 小型简单系统 - 杀鸡用牛刀
  2. 多语言混合架构 - 跨语言支持有限
  3. 云原生要求高 - 需要结合Dubbo 3.0或Service Mesh

实际项目中,通常对外用HTTP API,对内微服务间用RPC,结合两者优势使用。