什么是RPC?
In distributed computing, a remote procedure call (RPC) is when a computer program causes a procedure (subroutine) to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction. That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. This is a form of client–server interaction (caller is client, executor is server), typically implemented via a request–response message-passing system.
RPC(Remote Procedure Call)即远程过程调用,不同于本地调用,RPC是指调用远端机器的函数或方法,且不需要关心底层的调用细节,如网络协议和传输协议等,对于调用者来说,和调用本地方法没有什么区别。RPC调用的是一个远端对象,调用者和被调用者是处于不同的地址空间,要想完成调用,必须实现以下几个能力:
服务发现
由于调用的是远端对象,因此需要可以定位到调用的服务器地址以及调用的具体方法的进程,一般可以通过注册中心或者哈希查找来实现,将被调的接口注册到某个地方,比如使用CallerId和函数名作为映射,调用者通过CallerId进行调用,服务端收到调用请求后,通过CallerId查找到对应函数,再执行后续处理流程。
序列化和反序列化
调用者和被调用者处于不同的机器上,因此函数参数及其他一些Context信息需要经过网络传输才能到达服务端,网络传输的是二进制数据,因此RPC需要支持将函数参数(如基本类型int、long、map以及自定义类型等)可以序列化为网络可以传输的二进制数据,同时,也需要支持将二进制数据反序列化为程序可以处理的数据类型,是序列化的逆过程。
网络传输
网络传输协议和RPC本身没有关系,一般使用TCP进行网络传输,通过HTTP或者UDP也是可以完成RPC所需要的功能的。
如上,如果某个服务框架实现了上述这些功能,就是一个RPC框架,通过此框架便可以像调用本地方法一样来调用远端方法。
为什么使用RPC?
如果是一个功能比较简单的应用,可以将所有功能实现在一个服务中或者实现在多个服务中,但是部署在一个机器上,如此,接口间调用要么在同一进程内或者是本地进程间通信。随着业务的发展,服务功能持续迭代,单体应用出现性能瓶颈,因此需要考虑对服务进行拆分,根据业务功能划分为不同的模块,不同的模块部署到不同集群上,模块间进行通信完成功能。如将服务的管理域和执行域进行拆分,不仅是服务架构更合理清晰,也方便根据不同的模块划分不同的资源,保证服务的整体性能。
一个服务拆分为不同的模块,或者单体应用拆分为多个微服务时,此时便需要RPC出场了,不同模块及不同服务间都需要RPC才能完成通信。可以说RPC是分布式系统架构或者微服务架构必不可少的实现手段。
RPC原理
理清了RPC的基本概念之后,简单阐述下RPC框架的实现原理。首先看一张RPC调用的全貌图:
当客户端发起一次远程调用时:
- client以本地方式方式调用远程方法;
- client stub收到调用后负责将方法以及参数等组装成网络可以传输的消息体;
- client stub找到服务端地址,通过系统调用,将数据传输服务端;
- server stub收到消息后进行反序列化;
- server stub通过得到的参数调用本地方法;
- 执行结果返回给server stub;
- server stub将执行结果进行序列化;
- server stub进行系统调用将数据发送给客户端;
- client stub收到消息并进行解码;
- cleint stub将结果返回给调用者。
RPC框架所要实现的便是将序列化、反序列化以及网络传输等流程进行封装,这些流程对于调用者来说是透明的,调用者并不需要了解这些细节以及调用流程。
常用的RPC框架有哪些?
Thrift
Thrift是一个轻量级、跨语言的RPC框架,主要用于各个服务之间的RPC通信,最初由Facebook于2007年开发,2008年进入Apache开源项目。它通过自身的IDL中间语言,并借助代码生成引擎生成各种主流语言的RPC服务端和客户端模板代码。Thrift支持多种不同的编程语言,包括C++、Java、Python、PHP、Ruby、Erlag、Haskell、C#、Cocoa、JavaScript、Nodejs、Smalltalk、OCaml和Golang等。
gRPC
gRPC是一个高性能、通用的开源RPC框架,其由Google2015年主要面向移动应用开发并基于HTTP/2标准协议而设计,基于ProtoBuf序列化协议开发,且支持众多语言开发。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链式功能,从而有助于节省带宽、降低TCP连接次数、节省CPU使用、电池寿命。
支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等语言
Dubbo
Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。 Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用,目前Dubbo已经交给Apache基金会维护。
gRPC VS Thrift
什么时候应该选择gRPC而不是Thrift
- 需要良好的文档、示例
- 喜欢、习惯HTTP/2、ProtoBuf
- 对网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC
- 需要在非常多的语言间进行数据交换
- 对CPU敏感
- 协议层、传输层有多种控制要求
- 需要稳定的版本
- 不需要良好的文档和示例
参考文档
谁能用通俗的语言解释一下什么是 RPC 框架?
RPC框架:从原理到选型,一文带你搞懂RPC
gRPC vs Thrift