远程过程调用(RPC)
2023-11-14 10:43:01 阿炯

RPC是远程过程调用(Remote Procedure Call)的缩写。是一种计算机通信协议,允许一个计算机程序调用另一个计算机上的子程序,而无需了解底层网络细节。通过RPC,一台计算机程序可以像调用本地程序一样调用远程程序,使得分布式应用程序的开发更加简单和高效。简言之:两台服务器A,B,A服务器上的应用想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

进程间通信(IPC)是在多任务操作系统或联网的计算机之间运行的程序和进程所用的通信技术。有两种类型的进程间通信(IPC):

1、本地过程调用(LPC)LPC用在多任务操作系统中,使得同时运行的任务能互相会话。这些任务共享内存空间使任务同步和互相发送信息。

2、远程过程调用(RPC)RPC类似于LPC,只是在网上工作。RPC开始是出现在Sun微系统公司和HP公司的运行UNⅨ操作系统的计算机中。

通过IPC和RPC,程序能利用其它程序或计算机处理的进程。客户机/服务器模式计算把远程过程调用与其它技术(如消息传递)一道,作为系统间通信的一种机制。客户机执行自己的任务,但靠服务器提供后端文件服务。RPC为客户机提供向后端服务器申请服务的通信机制。如果把客户机/服务器应用程序想作是一个分离的程序,服务器能运行数据访问部分,因为它离数据最近,客户机能运行数据表示和与用户交互的前端部分。这样,远程过程调用可看作是把分割的程序通过网络重组的部件。LPC有时也称耦合(Coupling)机制。

用这种方式分割程序,当用户要访问数据时就无需每次拷贝整个数据库或它的大部分程序到用户系统。其实,服务器只处理请求,甚至只执行一些数据计算,把得出的结果再发送给用户。因为当数据存放在一个地方时,数据库同步很容易实现,所以多个用户可同时访问相同的数据。

分布式计算环境是由一个通信系统——网络连接的计算机集群。很容易把这个网络看成一个计算平台,若是对等方式,其中任何一台计算机都能成为客户机或服务器。一些处理任务可被分成独立运行程序在不同的网络计算机上并行处理,而独立的程序被交给最适合这个任务的计算机处理。这种策略可利用计算机空闲资源,提高网络的效益。一个典型的企业网包括许多运行着不同操作系统的异构计算机系统。现在人们正努力使得远程过程调用独立,这意味着开发商就不用考虑底层的网络和网络上数据传输所用的协议,RPC工作于多种分布式计算环境。

RPC工具提供了一种编程语言和编译器,它们使用可看作是本地过程的可运行于客户机和服务器上的模块开发分布式应用程序。运行时设施(run-timefacility)使得分布式应用程序能在多机种异构系统上运行,这样使得底层体系结构和运输协议对于应用程序是透明的。程序员用接口定义语言(IDL)建立接口定义(interface definition)。IDL是程序员用来设计远程运行的过程的工具。IDL编译器把IDL接口定义转换成与客户机和服务器相连的占位程序(stub)。客户机上的占位程序可加入到服务器的过程,而服务器上的占位程序也可加入到客户机过程。位于客户机服务器的RPC运行时设施与占位程序合作,来提供RPC调用操作。

调用分以下两种:

1、同步调用:客户方等待调用执行完成并返回结果。

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

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

背景

RPC的概念与技术早在1981年由Nelson提出。1984年,Birrell和Nelson把其用于支持异构型分布式系统间的通讯。Birrell的RPC 模型引入存根进程( stub) 作为远程的本地代理,调用RPC运行时库来传输网络中的调用。Stub和RPC runtime屏蔽了网络调用所涉及的许多细节,特别是参数的编码/译码及网络通讯是由stub和RPC runtime完成的,因此这一模式被各类RPC所采用。由于分布式系统的异构性及分布式计算模式与计算任务的多样性,RPC作为网络通讯与委托计算的实现机制,在方法、协议、语义、实现上不断发展,种类繁多,其中SUN公司和开放软件基金会在其分布式产品中所建立和实用的RPC较为典型。

在SUN公司的网络文件系统NFS及开放网络计算环境ONC中,RPC是基本实现技术。OSF酝酿和发展的另一个重要的分布式计算软件环境DCE也是基于RPC的。在这两个系统中,RPC既是其自身的实现机制,又是提供给用户设计分布式应用程序的高级工具。由于对分布式计算的广泛需求,ONC和DCE成为Client/Server模式分布式计算环境的主流产品,而RPC也成为实现分布式计算的事实标准之一。

组件职责
RPC 实现结构由各个组件组成部分,下面简述一下每个组件的职责划分:
1.RpcServer  
负责导出(export)远程接口

2.RpcClient  
负责导入(import)远程接口的代理实现

3.RpcProxy  
远程接口的代理实现

4.RpcInvoker  
客户方实现:负责编码调用信息和发送调用请求到服务方并等待调用结果返回
服务方实现:负责调用服务端接口的具体实现并返回调用结果

5.RpcProtocol  
负责协议编/解码

6.RpcConnector  
负责维持客户方和服务方的连接通道和发送数据到服务方

7.RpcAcceptor  
负责接收客户方请求并返回请求结果

8.RpcProcessor  
负责在服务方控制调用过程,包括管理调用线程池、超时时间等

9.RpcChannel  
数据传输通道

协议编解码
客户端代理在发起调用前需要对调用信息进行编码,这就要考虑需要编码些什么信息并以什么格式传输到服务端才能让服务端完成调用。出于效率考虑,编码的信息越少越好(传输数据少),编码的规则越简单越好(执行效率高)。先看下需要编码些什么信息:
-- 调用编码 --  
1.接口方法  
包括接口名、方法名

2.方法参数  
包括参数类型、参数值

3.调用属性  
包括调用属性信息,例如调用附件隐式参数、调用超时时间等

-- 返回编码 --  
1.返回结果  
接口方法中定义的返回值

2.返回码  
异常返回码

3.返回异常信息  
调用异常信息

下面给出一种概念上的 RPC 协议消息设计格式:
-- 消息头 --
magic      : 协议魔数,为解码设计
header size: 协议头长度,为扩展设计
version    : 协议版本,为兼容设计
st         : 消息体序列化类型
hb         : 心跳消息标记,为长连接传输层心跳设计
ow         : 单向消息标记,
rp         : 响应消息标记,不置位默认是请求消息
status code: 响应消息状态码
reserved   : 为字节对齐保留
message id : 消息 id
body size  : 消息体长度
-- 消息体 --
采用序列化编码,常见有以下格式
xml   : 如 webservie soap
json  : 如 JSON-RPC
binary: 如 thrift; hession; kryo 等

格式确定后编解码就简单了,由于头长度一定所以我们比较关心的就是消息体的序列化方式。序列化需要关心三个方面:
1. 序列化和反序列化的效率,越快越好。
2. 序列化后的字节长度,越小越好。
3. 序列化和反序列化的兼容性,接口参数对象若增加了字段,是否兼容。

可以在本站参考更多关于序列化的说明。

应用

RPC在分布式系统中的系统环境建设和应用程序设计中有着广泛的应用,应用包括如下方面:

1、分布式操作系统的进程间通讯
进程间通讯是操作系统必须提供的基本设施之一,分布式操作系统必须提供分布于异构的结点机上进程间的通讯机制,RPC是实现消息传送模式的分布式进程间通讯的手段之一。

2、构造分布式计算的软件环境
由于分布式软件环境本身地理上的分布性, 它的各个组成成份之间存在大量的交互和通讯,RPC 是其基本的实现方法之一。ONC+和DCE两个流行的分式布计算软件环境都是使用RPC构造的,其它一些分布式软件环境也采用了RPC方式。

3、远程数据库服务
在分布式数据库系统中,数据库一般驻存在服务器上,客户机通过远程数据库服务功能访问数据库服务器,现有的远程数据库服务是使用RPC模式的。例如Sybase和Oracle都提供了存储过程机制,系统与用户定义的存储过程存储在数据库服务器上,用户在客户端使用RPC模式调用存储过程。

4、分布式应用程序设计
RPC机制与RPC工具为分布式应用程序设计提供了手段和方便,用户可以无需知道网络结构和协议细节而直接使用RPC工具设计分布式应用程序。

5、分布式程序的调试
RPC可用于分布式程序的调试。使用反向RPC使服务器成为客户并向它的客户进程发出RPC,可以调试分布式程序。例如在服务器上运行一个远端调试程序,它不断接收客户端的RPC,当遇到一个调试程序断点时,它向客户机发回一个RPC,通知断点已经到达,这也是RPC用于进程通讯的例子。

在RPC中,调用者发送一个请求消息到远程主机,远程主机收到请求后执行相应的程序,并将结果返回给调用者。RPC通过序列化数据传输协议将数据打包并进行网络传输,常见的序列化协议有JSON、Protobuf、Thrift等。RPC通常使用TCP或UDP作为底层传输协议。


其常用于分布式系统中,例如云计算、微服务架构、分布式数据库等,它可以让不同的服务之间进行远程调用,从而实现分布式系统的协作。


RPC架构设计需要考虑以下几个方面:

1、接口设计:RPC的基础是远程调用,因此接口设计是关键。接口应该设计清晰、简洁、易于理解,并且具有良好的扩展性和兼容性。

2、通信协议:RPC的通信协议需要支持高效的数据传输和序列化,同时也需要支持可靠性和安全性等方面的需求。常用的通信协议有HTTP、TCP、UDP等。

3、数据传输格式:RPC通信的数据需要进行序列化和反序列化。常见的序列化格式有JSON、Protobuf、Thrift等。选用合适的数据传输格式可以提高RPC的性能和扩展性。

4、负载均衡和容错处理:在分布式系统中,服务的负载均衡和容错处理是必不可少的。RPC架构需要考虑如何实现负载均衡和容错处理,例如使用负载均衡算法、使用备用服务等。

5、安全性和可靠性:在RPC架构中,数据的安全性和可靠性也是非常重要的。需要考虑如何保证数据传输的安全性和可靠性,例如使用加密协议、数据压缩等。

RPC架构设计需要综合考虑以上多个方面的需求,并根据实际场景进行选择和实现,以实现高效、可靠、安全、可扩展的RPC系统。


RPC可以应用于各种分布式系统中,例如:

1、微服务架构:微服务架构中的各个服务通常都是通过RPC进行通信,实现服务之间的远程调用和数据传输。

2、云计算:云计算中的各种服务也需要通过RPC进行通信,例如计算、存储、网络等服务。

3、分布式数据库:分布式数据库中的各个节点之间需要进行数据同步和通信,也可以通过RPC实现。

4、消息队列:消息队列中的生产者和消费者之间也可以通过RPC进行通信,实现高效的消息传输和处理。


在具体应用RPC时,需要根据实际场景选择合适的RPC框架,并按照RPC架构设计的思路进行实现。常见的RPC框架有gRPC、Dubbo、Thrift等。在使用RPC框架时,需要根据具体的业务场景进行配置和优化,以达到最优的性能和可扩展性。同时还需要考虑到RPC的安全性、可靠性和容错处理等方面的问题,以保证系统的稳定和安全。另外还要考虑传输服务、执行调用、异常处理等相关的步骤,在上文中也有一定的体现。


Thrift

Dubbo

Dubbo(读音[db])是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。


Dubbo治理框架

如图所示,Dubbo是一个综合性的含治理能力的RPC框架,非常核心的一点是其引入注册中心,好处是可以实现服务的动态扩展,这一点很重要。


Dubbo之RPC实现

从上图可以非常容易看出Client Stub和Server Stub分别承担Client端和Server端的Proxy角色,这和凯文哥上文手写的KW框架思路是一致的,他们承担的职责分别是:

Client Stub:负责RPC调用的请求编码和响应结果解码,即把调用涉及到的方法、调用参数等按照Client端和Server端约定的协议编码发送到Server端,接收Server的响应并对响应进行解码从而得到最终的RPC调用结果

Server Stub:接受Client端发送的调用请求,并按照Client端和Server端约定的远程调用协议对请求进行解码,根据解码后的请求定位到Server端被调用的目标代码,调用处理完之后对返回结果进行编码发送到Client端

Dubbo框架好在哪里呢

弹性扩展能力:上面提到了Dubbo引入了注册中心,这使得其具有动态扩展能力,这是非常重要的优势。

专用协议:服务调用方和服务提供方采用dubbo协议,该协议基于netty的高性能NIO通信框架,提供长连接支持,这比依靠代码层通过http+心跳保持长连接要更成熟和高效。


gRPC

gRPC (gRPC Remote Procedure Calls) 是 Google 发起的一个开源远程过程调用系统,该系统基于 HTTP/2 协议传输,其框架与Dubbo RPC部分实现基本一致,主要区别在于其通信基于HTTP/2,采用二进制的方式传输。


GRPC框架

HTTP/2是基于UDP协议的,通过上层算法保证可靠性传输,主要优点就是天然支持并行传输,因此性能有大幅提升。显然从这一点讲,由于HTTP协议广泛的影响力和通用性,GRPC在通信机制上是更优解。

GRPC相较于Dubbo有一个明显的弊端就是不能动态扩展,因为其使用protocol buffer这种描述文件来定义调用接口,要求其在服务端和客户端都保持一致,通过编译生成一堆代理和功能程序,这对服务开发团队的协同性和使用上便捷性提了很高的要求。


bRPC

tRPC


真的需要这么多 RPC 框架吗

2023年10月18日,腾讯开源了 RPC 开发框架:tRPC,号称具有 “多语言、高性能” 的特点,首批开源支持 Go / Cpp 两种编程语言。 众所周知,现有的开源 RPC 框架已经很多了,gRPC、Thrift、Dubbo、bRPC,难道就没有一个能腾讯满足需求吗,腾讯是不是在重复造轮子?我们真的需要这么多 RPC 框架吗?为此开源中国对腾讯 tRPC 团队进行了采访,来解答网友心中的部分疑惑。

1、有网友认为现有的开源 RPC 框架已经很多了,腾讯搞 tRPC 是在重复造轮子。您怎么看待这种观点?

存量的框架的确够多了,但对腾讯来说,多一套框架不能只是多了一套,核心是让存量归一。

以前在腾讯,都是由业务自己选择 RPC 框架,造成在用的框架种类繁多,有开源的,有自研的,达数十种。它们使用的通信协议不一样,使用的名字服务不一样,造成服务之间互通不顺畅,阻碍了业务的发展。同时,众多的 RPC 框架维护和使用成本也很高,急需收敛存量框架。是选择一个存量框架还是重新开发一个新的框架去做收敛,我们在开发 tRPC 之前,也深度思考了这个问题,并在内部进行了充分的讨论,最终决定采用自研 tRPC。因为腾讯的业务形态多样,对性能、开发语言支持、架构开放性等方面要求都比较高,已开源或者内部已有的 RPC 框架或多或少还不能完全满足腾讯业务的需求。

2、腾讯曾在 2017 年开源了 RPC 框架 Tars。今天的 tRPC 跟 Tars 有什么联系吗?为什么要另起炉灶又开发了个新的?

tRPC 和 Tars 是两个完全独立框架。不过,tRPC 设计之初也有借鉴 Tars 的部分设计,tRPC 的部分核心开发设计者曾经也是 Tars 的核心开发设计者。 之所以要另起炉灶,主要还是因为 Tars 不能承担起公司内部框架存量归一的目标,自身架构上比较封闭是最主要的原因。而 tRPC 采用插件化的设计,架构开放性很强,很容易融入到已有的服务治理平台中去,更利于存量收敛。

3、tRPC 项目是从什么时候开始的?背后有什么故事值得分享吗?

tRPC 项目从 2019 开始,到现在已经 4 年多了。当时公司存量框架数量最多的时候,达数十种,严重影响了研发效率,阻碍业务进一步发展。 tRPC 从成立到发展至今确实也发生了很多故事。比如在成立之初,对于是否应该另起炉灶去做 tRPC 来收敛存量框架,当时在公司内也是见解不一。我们内部论坛就这个问题有一个帖子,在全公司范围进行了激烈讨论,评论达到了上百条,pv 到达上万。不辩不明。

在内部经过这么大范围的讨论后,才最终确定了要自研 tRPC。 研发 tRPC 得到公司内部技术人员的广泛支持。为了使 tRPC 能成为集大成的 RPC 框架,能够承担存量归一的重任,我们研发采用了内部社区模式,公司很多擅长框架开发的技术同事都主动积极参与进来,先后为 tRPC 贡献代码的人员有数百人之多。设计研发过程中也是各种思想碰撞,比如 tRPC 插件化的总体架构形态的确定,就是通过几次数十人的闭门会议,在激烈的争吵中形成的。

4、为什么要将 tRPC 开源?希望开源能给该项目带来什么?

开源 tRPC 的原因有两个:
1. 公司内部业务对外扩展时需要。如游戏出海,业务需要在外部企业私有化部署,这时候因为业务开发使用了 tRPC,需要把代码交付出去。
2. 希望通过开源对外做更多的技术分享交流,并借助社区的力量来进一步将 tRPC 打造得更好。

5、官方提到 tRPC 支持多种通信协议,能具体说一下支持哪些通信协议吗?协议的通用性和高性能可以兼得吗?

tRPC 框架默认支持 tRPC 协议,还支持业界 HTTP (s)/gRPC/bRPC/Tars/Thrift 协议,以及公司内部多种通信协议,目前只开源了 HTTP (s)/gRPC 协议,未来会逐步开源其它协议。

对于协议这块通用性和高性能是否兼得的问题,这里更多地要看业务场景和需求,如果想要通用性,可以选择 HTTP 或者 gRPC 协议,如果想要高性能,可以选择 tRPC 协议,因为协议本身设计和实现会对性能有比较大的影响。

6、相比较于其他开源框架,tRPC 出现得比较晚。从 RPC 框架的演进历史来看,tRPC 与其他开源 RPC 框架有什么本质上的区别吗?

RPC 框架演进到现在确实已经很成熟了,业界开源的 RPC 框架各自之间也都很难说有什么本质区别,更多的是符合各自业务发展的诉求。tRPC 出现的主要目的是做公司存量框架收敛,它有一定的后发优势,可以吸取已有存量框架的优点,规避不足,通过在高性能的基础上基于插件化思想去构建开放性的架构,使它能更适用于腾讯多样复杂的业务场景。

7、官方提到项目规划,主要有两点,一是开源更多编程语言:Java、Python、Node,二是丰富生态,开源更多云原生相关的插件和组件。想问下是出于哪些方面考虑,将其作为未来重点开发方向?

主要还是希望框架能够更广泛和高效地使用起来,更多的开发语言支持能覆盖更多的场景,如现在很多企业都是使用 Java 语言,tRPC 只有支持 Java 才有可能成为其候选。又如现在 AI 场景大部分都使用 Python,那么 tRPC 支持了 Python 才有可能被使用。

丰富生态也是希望 tRPC 能够帮助使用者能够更快速构建自己的微服务体系。目前大家都喜欢使用云原生相关的组件去构建自己的微服务体系,tRPC 如果能够丰富云原生的插件生态,那么用户使用 tRPC 和这些云原生的组件对接就会更高效快捷。

8、腾讯有 tRPC,百度有 bRPC,阿里有 Dubbo,字节有 Volo,为什么每个大厂都要开发自己的 RPC 框架?

大厂为什么都要开发自己的 RPC 框架?个人觉得主要还是业务形态决定的。虽然 RPC 框架看起来都差不多,但真正应用到业务时,根据业务的形态不同又会有很多差异。 如果使用开源的框架,很有可能要费很大的成本才能解决这些差异,花费的时间周期也会更长,甚至可能解决不了。比如我们在游戏场景使用 tRPC 时,发现游戏这种有状态的业务场景,通用的 RPC 设计并不能满足其需求,我们也是基于 tRPC 插件化的架构,通过和游戏团队合作替换了底层通信组件后,才满足了游戏场景的需求。如果采用的开源框架,这个问题可能就很难解决了。