RPC框架原理简介

article/2025/9/26 19:00:45

什么是RPC框架?

RPC,全称为Remote Procedure Call,即远程过程调用,是一种计算机通信协议。
比如现在有两台机器:A机器和B机器,并且分别部署了应用A和应用B。假设此时位于A机器上的A应用想要调用位于B机器上的B应用提供的函数或是方法,由于A应用和B应用不在一个内存空间里面,所以不能直接调用,此时就需要通过网络来表达调用的方式和传输调用的数据。也即所谓的远程调用。

RPC 功能目标

RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。 为实现该目标,RPC 框架需提供一种透明调用机制让使用者不必显式的区分本地调用和远程调用。 下面我们将具体细化 stub 结构的实现。

因为在几个进程内(应用分布在不同的机器上),无法共用内存空间,或者在一台机器内通过本地调用无法完成相关的需求,比如不同的系统之间的通讯,甚至不同组织之间的通讯。此外由于机器的横向扩展,需要在多台机器组成的集群上部署应用等等。

RPC 调用分类

RPC 调用分以下两种:

  • 同步调用
    客户方等待调用执行完成并返回结果。
  • 异步调用
    客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。 若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。

异步和同步的区分在于是否等待服务端执行完成并返回结果。

RPC框架的实现原理

主要有以下几个步骤:

1、建立通信

首先要解决通讯的问题:即A机器想要调用B机器,首先得建立起通信连接。主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有相关的数据都在这个连接里面进行传输交换。

通常这个连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。

2、服务寻址

解决寻址的问题:即A机器上的应用A要调用B机器上的应用B,那么此时对于A来说如何告知底层的RPC框架所要调用的服务具体在哪里呢?

通常情况下我们需要提供B机器(主机名或IP地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。比如基于Web服务协议栈的RPC,就需要提供一个endpoint URI,或者是从UDDI服务上进行查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。

3、网络传输

3.1、序列化

当A机器上的应用发起一个RPC调用时,调用方法和其入参等信息需要通过底层的网络协议如TCP传输到B机器,由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给B机器。

3.2、反序列化

当B机器接收到A机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式,然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用, 通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。

4、服务调用

B机器进行本地调用(通过代理Proxy)之后得到了返回值,此时还需要再把返回值发送回A机器,同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,而当A机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,最后再交给A机器上的应用进行相关处理(一般是业务逻辑处理操作)。

通常,经过以上四个步骤之后,一次完整的RPC调用算是完成了,另外可能因为网络抖动等原因需要重试等。

RPC 核心组件

一个完整的RPC架构里面包含了四个核心的组件,分别是Client,Client Stub,Server以及Server Stub,这个Stub可以理解为存根。

  • 客户端(Client):服务调用方(服务消费者)
  • 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端
  • 服务端(Server):服务的真正提供者
  • 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理

RPC调用过程

  1. 服务消费者(client客户端)通过本地调用的方式调用服务
  2. 客户端存根(client stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体
  3. 客户端存根(client stub)找到远程的服务地址,并且将消息通过sockets网络发送给服务端
  4. 服务端存根(server stub)收到消息后进行解码(反序列化操作)
  5. 服务端存根(server stub)根据解码结果调用本地的服务进行相关处理
  6. 本地服务执行具体业务逻辑
  7. 将处理结果返回给服务端存根(server stub)
  8. 服务端存根(server stub)将返回结果重新打包成消息(序列化)并通过网络发送至消费方
  9. 服务端(server)通过sockets将消息发送到客户端;
  10. 客户端存根(client stub)接收到消息,并进行解码(反序列化
  11. 服务消费方得到最终结果

在这里插入图片描述
而RPC框架的实现目标则是将上面的第2-10步完好地封装起来,也就是把调用、编码/解码的过程给封装起来,让用户感觉上像调用本地服务一样的调用远程服务。
注意:无论是何种类型的数据,最终都需要转换成二进制流在网络上进行传输,数据的发送方需要将对象转换为二进制流,而数据的接收方则需要把二进制流再恢复为对象。

RPC框架需要解决的问题?

  1. 如何确定客户端和服务端之间的通信协议?
  2. 如何更高效地进行网络通信?
  3. 服务端提供的服务如何暴露给客户端?
  4. 客户端如何发现这些暴露的服务?
  5. 如何更高效地对请求对象和响应结果进行序列化和反序列化操作?

使用了哪些技术?

8.1、动态代理

生成Client Stub(客户端存根)和Server Stub(服务端存根)的时候需要用到java动态代理技术,可以使用jdk提供的原生的动态代理机制,也可以使用开源的:Cglib代理,Javassist字节码生成技术。

8.2、序列化

在网络中,所有的数据都将会被转化为字节进行传送,所以为了能够使参数对象在网络中进行传输,需要对这些参数进行序列化和反序列化操作。

序列化:把对象转换为字节序列的过程称为对象的序列化,也就是编码的过程。
反序列化:把字节序列恢复为对象的过程称为对象的反序列化,也就是解码的过程。

目前比较高效的开源序列化框架:如Kryo、fastjson和Protobuf等。

8.3、NIO通信

出于并发性能的考虑,传统的阻塞式 IO 显然不太合适,因此我们需要异步的 IO,即 NIO。
Java 提供了 NIO 的解决方案,Java 7 也提供了更优秀的 NIO.2 支持。可以选择Netty或者mina来解决NIO数据传输的问题。

8.4、服务注册中心

可选:Redis、Zookeeper、Consul 、Etcd。
一般使用ZooKeeper提供服务注册与发现功能,解决单点故障以及分布式部署的问题(注册中心)。

RPC 异常处理

无论 RPC 怎样努力把远程调用伪装的像本地调用,但它们依然有很大的不同点,而且有一些异常情况是在本地调用时绝对不会碰到的。 在说异常处理之前,我们先比较下本地调用和 RPC 调用的一些差异:

  1. 本地调用一定会执行,而远程调用则不一定,调用消息可能因为网络原因并未发送到服务方。
  2. 本地调用只会抛出接口声明的异常,而远程调用还会跑出 RPC 框架运行时的其他异常。
  3. 本地调用和远程调用的性能可能差距很大,这取决于 RPC 固有消耗所占的比重。

正是这些区别决定了使用 RPC 时需要更多考量。 当调用远程接口抛出异常时,异常可能是一个业务异常, 也可能是 RPC 框架抛出的运行时异常(如:网络中断等)。 业务异常表明服务方已经执行了调用,可能因为某些原因导致未能正常执行, 而 RPC 运行时异常则有可能服务方根本没有执行,对调用方而言的异常处理策略自然需要区分。

由于 RPC 固有的消耗相对本地调用高出几个数量级,本地调用的固有消耗是纳秒级,而 RPC 的固有消耗是在毫秒级。 那么对于过于轻量的计算任务就并不合适导出远程接口由独立的进程提供服务, 只有花在计算任务上时间远远高于 RPC 的固有消耗才值得导出为远程接口提供服务。

RPC 结构拆解

如下图所示。
在这里插入图片描述
RPC 服务方通过 RpcServer 去导出(export)远程接口方法,而客户方通过 RpcClient 去引入(import)远程接口方法。 客户方像调用本地方法一样去调用远程接口方法,RPC 框架提供接口的代理实现,实际的调用将委托给代理 RpcProxy 。 代理封装调用信息并将调用转交给 RpcInvoker 去实际执行。 在客户端的 RpcInvoker 通过连接器 RpcConnector 去维持与服务端的通道 RpcChannel, 并使用 RpcProtocol 执行协议编码(encode)并将编码后的请求消息通过通道发送给服务方。

RPC 服务端接收器 RpcAcceptor 接收客户端的调用请求,同样使用 RpcProtocol 执行协议解码(decode)。 解码后的调用信息传递给 RpcProcessor 去控制处理调用过程,最后再委托调用给 RpcInvoker 去实际执行并返回调用结果。

RPC 组件职责

上面我们进一步拆解了 RPC 实现结构的各个组件组成部分,下面我们详细说明下每个组件的职责划分。

  1. RpcServer
    负责导出(export)远程接口
  2. RpcClient
    负责导入(import)远程接口的代理实现
  3. RpcProxy
    远程接口的代理实现
  4. RpcInvoker
    客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回
    服务方实现:负责调用服务端接口的具体实现并返回调用结果
  5. RpcProtocol
    负责协议编/解码
  6. RpcConnector
    负责维持客户方和服务方的连接通道和发送数据到服务方
  7. RpcAcceptor
    负责接收客户方请求并返回请求结果
  8. RpcProcessor
    负责在服务方控制调用过程,包括管理调用线程池、超时时间等
  9. RpcChannel
    数据传输通道

如何调用他人的远程服务

由于各服务部署在不同机器,服务间的调用免不了网络通信过程,服务消费方每调用一个服务都要写一坨网络通信相关的代码,不仅复杂而且极易出错。

如果有一种方式能让我们像调用本地服务一样调用远程服务,而让调用者对网络通信这些细节透明,那么将大大提高生产力,比如服务消费方在执行helloWorldService.sayHello(“test”)时,实质上调用的是远端的服务。这种方式其实就是RPC(Remote Procedure Call Protocol),在各大互联网公司中被广泛使用,如阿里巴巴的hsf、dubbo(开源)、Facebook的thrift(开源)、Google grpc(开源)、Twitter的finagle(开源)等、新浪微博的motan(开源)。
在这里插入图片描述

  • 注册中心,用于服务端注册远程服务以及客户端发现服务
  • 服务端,对外提供后台服务,将自己的服务信息注册到注册中心
  • 客户端,从注册中心获取远程服务的注册信息即地址列表,然后进行远程过程调用

目前主要的注册中心可以借由 zookeeper,eureka,consul,etcd 等开源框架实现。互联网公司也会因为自身业务的特性自研,如美团点评自研的 MNS,新浪微博自研的 vintage。

注册中心维护着一个服务配置中心节点树:
在这里插入图片描述

  1. 服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
  2. 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
  3. 当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
  4. 当某个服务的所有服务器都下线了,那么这个服务也就下线了。
  5. 同样,当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
  6. 服务提供方可以根据服务消费者的数量来作为服务下线的依据。

如何发布自己的服务

如何让别人使用我们的服务呢?有同学说很简单嘛,告诉使用者服务的IP以及端口就可以了啊。确实是这样,这里问题的关键在于怎么实现自动告知。

有没有一种方法能实现自动告知,即机器的增添、剔除对调用方透明,调用者不再需要写死服务提供方地址?当然可以,现如今zookeeper被广泛用于实现服务自动注册与发现功能!

简单来讲,zookeeper可以充当一个服务注册表(Service Registry),让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(ip+端口)去访问具体的服务提供者。如下图所示:

在这里插入图片描述
具体来说,zookeeper就是个分布式文件系统,每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /{service}/{version}/{ip:port}, 比如我们的HelloWorldService部署到两台机器,那么zookeeper上就会创建两条目录:分别为/HelloWorldService/1.0.0/100.19.20.01:16888 /HelloWorldService/1.0.0/100.19.20.02:16888。

zookeeper提供了“心跳检测”功能,它会定时向各个服务提供者发送一个请求(实际上建立的是一个 Socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除,比如100.19.20.02这台机器如果宕机了,那么zookeeper上的路径就会只剩/HelloWorldService/1.0.0/100.19.20.01:16888。

服务消费者会去监听相应路径(/HelloWorldService/1.0.0),一旦路径上的数据有任务变化(增加或减少),zookeeper都会通知服务消费方服务提供者地址列表已经发生改变,从而进行更新。

更为重要的是zookeeper与生俱来的容错容灾能力(比如leader选举),可以确保服务注册表的高可用性。

感知服务的下线

服务上线时自然要注册到注册中心,但下线时也得从注册中心中摘除。注册是一个主动的行为,这没有特别要注意的地方,但服务下线却是一个值得思考的问题。服务下线包含了主动下线和系统宕机等异常方式的下线。

4.1 临时节点+长连接

在 zookeeper 中存在持久化节点和临时节点的概念。持久化节点一经创建,只要不主动删除,便会一直持久化存在;临时节点的生命周期则是和客户端的连接同生共死的,应用连接到 zookeeper 时创建一个临时节点,使用长连接维持会话,这样无论何种方式服务发生下线,zookeeper 都可以感知到,进而删除临时节点。zookeeper 的这一特性和服务下线的需求契合的比较好,所以临时节点被广泛应用。

4.2 主动下线+心跳检测

并不是所有注册中心都有临时节点的概念,另外一种感知服务下线的方式是主动下线。例如在 eureka 中,会有 eureka-server 和 eureka-client 两个角色,其中 eureka-server 保存注册信息,地位等同于 zookeeper。当 eureka-client 需要关闭时,会发送一个通知给 eureka-server,从而让 eureka-server 摘除自己这个节点。但这么做最大的一个问题是,如果仅仅只有主动下线这么一个手段,一旦 eureka-client 非正常下线(如断电,断网),eureka-server 便会一直存在一个已经下线的服务节点,一旦被其他服务发现进而调用,便会带来问题。为了避免出现这样的情况,需要给 eureka-server 增加一个心跳检测功能,它会对服务提供者进行探测,比如每隔30s发送一个心跳,如果三次心跳结果都没有返回值,就认为该服务已下线。

开源的优秀RPC框架

阿里巴巴 Dubbo:https://github.com/alibaba/dubbo
新浪微博 Motan:https://github.com/weibocom/motan
gRPC:https://github.com/grpc/grpc
rpcx :https://github.com/smallnest/rpcx
Apache Thrift :https://thrift.apache.org/

参考

https://www.cnblogs.com/metoy/p/4321311.html
https://blog.csdn.net/John8169/article/details/80919829
https://www.jianshu.com/p/78f72ccf0377


http://chatgpt.dhexx.cn/article/BgMlbZke.shtml

相关文章

RPC通信原理

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 系列文章目录前言一、RPC是什么?二、RPC原理总…

RPC框架面试总结-RPC原理及实现

一、什么是RPC RPC是远程调用过程的简写,是一个协议,处于网络通信协议的第五层:会话层,其下就是TCP/IP协议,在建立在其基础上的通信会话协议。RPC定义了交互的模式,而应用程序使用这些模式,来访…

RPC原理与FastRPC实现

0. 起因 最近看文档,发现一些组件是通过FastRPC来进行沟通的,并且偶尔看到某些场景下在FastRPC上的时间消耗好像也蛮可观,恰好FastRPC是开源的,因此决定看看FastRPC具体的实现。 1. RPC简介 当初在学Java的时候,初遇…

RPC原理详解

转自:http://www.cnblogs.com/metoy/p/4321311.html RPC 功能目标 RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。 为实现该目标,RPC 框架需提供一种透…

RPC原理介绍

面向服务架构SOA 任何大型网站的发展都伴随着网站架构的演进。网站架构一般最初是单应用设计,然后逐渐经历面向对象设计和模块化设计的架构,最终发展到面向服务的服务化架构。在单应用设计架构体系当中,我们关注的是方法和实体;而…

RPC 原理与实现

文章目录 1. RPC 简介1.1 什么是RPCReference: LPC & IPC (本地过程调用) 1.2 为什么要用RPC1.2.1 系统架构的演进1.2.2 Web 服务的技术结构1.2.2 SOAP ( Simple Object Access Protocol)1.2.2 REST(Representational State Transfort&am…

RPC核心原理

了解RPC RPC全称Remote Procedure Call,即远程过程调用.其中远程需要跨机器,跨机器需要可靠的网络编程技术实现,无论是Java原生的网络编程模型还是Netty都会让代码中出现大量与业务无关的网络编程代码,RPC技术则是为了解决这个问题的.它帮助我们屏蔽网络编程的细节,实现调用远…

RPC原理(1)之深入RPC原理简介

一、RPC调用原理图 下面这张图是我们微服务一次Http调用请求图: 首先在请求的过程中我们知道是有三次握手,四次挥手的流程,具体流程如下: 1.浏览器请求服务器(订单服务),请求建立连接,首先客户端向服务器…

RPC原理简述

RPC(Remote Procedure Call):远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。 RPC 是一种技术思想而非一种规范或协议,常见 RPC 技术和框架有: 应…

RPC核心原理详解

什么是RPC? RPC的全称是Remote Procedure Call,即远程过程调用。简单解读字面上的意思,远程肯定是指要跨机器而非本机,所以需要用到网络编程才能实现,但是不是只要通过网络通信访问到另一台机器的应用程序&#xff0c…

RPC原理

RPC就是远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的思想。 原理 一个完整的RPC主要包括三部分: 服务注册中心(Registry),负责将本地服务发布成远程服务,管理远…

从零开始实现RPC框架 - RPC原理及实现

RPC概述 RPC(Remote Procedure Call)即远程过程调用,允许一台计算机调用另一台计算机上的程序得到结果,而代码中不需要做额外的编程,就像在本地调用一样。 现在互联网应用的量级越来越大,单台计算机的能力有限,需要借…

RPC介绍与原理

RPC介绍与原理 RPC介绍 RPC是什么 RPC(Remote Procedure Call)是一种进程间通信方式。简单地说就是能使应用像调用本地方法一样的调用远程的过程或服务,可以应用在分布式服务、分布式计算、远程服务调用等许多场景。说起 RPC 大家并不陌生…

RPC理论原理

目录 集群和分布式RPC通信原理 集群和分布式 集群:每一台服务器独立运行一个工程的所有模块。 分布式:一个工程拆分了很多模块,每一个模块独立部署运行在一个服务器主机上,所有服务器协同工作共同提供服务,每一台服务…

一文搞懂RPC原理

了解RPC: RPC(Remote Procedure Call Protocol)——远程过程调用协议: 一般用于实现部署在不同机器上的系统之间的方法调用,使得程序能够像访问本地资源一样,通过网络传输去访问远端系统资源。 描述&…

rpc简介及原理

1.RPC简介及原理介绍 RPC技术内部原理是通过两种技术的组合来实现的:本地方法调用 和 网络通信技术。 1.1 RPC简介 在上述本地过程调用的例子中,我们是在一台计算机上执行了计算机上的程序,完成调用。随着计算机技术的发展和需求场景的变化…

RPC原理解析

1.RPC原理解析 1.1 什么是RPC RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP/IP或UDP,为通信程序…

RPC实现原理

一、什么是RPC框架? RPC,全称为Remote Procedure Call,即远程过程调用,是一种计算机通信协议。 比如现在有两台机器:A机器和B机器,并且分别部署了应用A和应用B。假设此时位于A机器上的A应用想要调用位于B机…

什么是 RPC?RPC原理是什么?

什么是 RPC?RPC原理是什么? 什么是 RPC? RPC(Remote Procedure Call)—远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。比如两个不同的服务 A、B 部署在两台不同的机器…

【RK3399Pro学习笔记】三、Debian 9 安装 ROS (Thinker Edge R)

目录 配置源设置 Key安装初始化rosdep环境配置测试安装rosinstall卸载 平台:华硕 Thinker Edge R 瑞芯微 RK3399Pro 固件版本:Tinker_Edge_R-Debian-Stretch-V1.0.4-20200615 参考资料: RK3399(Debian9 - stretch) 安装 ROS Lunar —— WB8…