RPC(Remote procedure call)远程过程调用,是一种分布式系统通信方法,多系统数据的交互方案,除了RPC外,还有HTTP调用、分布式消息队列、数据库和分布式缓存,其中RPC和HTTP调用是无需通过中间件,端到端系统的直接数据交互方式。
RPC从客户端上通过参数传递的方式调用另一个地址空间(通常是共享网络的另一台机器上)的过程或者函数,并得到返回的结果,在调用过程中隐藏了底层的通讯细节,不需要直接处理Socket通讯或者HTTP通讯。
RPC远程调用
RPC为了实现不必显式区分远程调用同本地调用的区别,需要解决一下三个问题。
(1)寻址
为了调用时在两个地址空间里准确寻址到函数,(指针只适合在同一个地址空间寻址),两个机器上得所有函数都必须有一个ID,且在所有的进程中,这个ID是唯一确定的,客户端开寻址时,必须附上ID,因而必须在客户端和服务器端维护一个ID和函数的映射表----Call ID映射,两个机器上的表不一定完全相同,但是对应函数的Call ID必须相同,客户端需要远程调用时,就进行查表,并把Call ID传给服务端,服务端也通过查表,来确定客户端需要调用的函数,并执行相应的代码。
(2)序列化和反序列化
客户端在给远程函数(可能是不一样语言的程序)传参时,为了达到本地调用时去栈里调用一样的效果,需要客户端先将参数转换为字节流,传给服务端,这叫序列化,服务端再把字节流转成自己能读懂的格式,叫做反序列化,从服务端返回的数值也需要序列化和反序列化的过程。
(3)网络传输
客户端和服务端通过网络连接,网络传输层需要把Call ID和序列化后的字节流在客户端和服务端之间传输,因而能实现传输需求的协议都可以,大多数的RPC采用TCP协议保证了数据传输的可靠性,UDP也可以,gRPC采用了HTTP2协议。
一次RPC过程如下:
实例获取
由于采用分布式架构,一个服务会有多个实例,获取实例时就需要一个服务注册中心,比如在Dubbo中,使用Zookeeper作为注册中心,在调用时,从Zookeeper获取服务的实例列表,再从中选择一个实例进行调用。
选择实例时,Dubbo提供了4种负载均衡策略:
(1)如果每次都去注册中心查询列表,效率很低,那么就要加缓存;
(2)客户端总不能每次调用完都等着服务端返回数据,所以就要支持异步调用;
(3)服务端的接口修改了,老的接口还有人在用,这就需要版本控制;
(4)服务端总不能每次接到请求都马上启动一个线程去处理,于是就需要线程池;
RPC协议
在客户端和服务端之间传输数据包时,有可能一次获取多个或者半个数据包,即粘包和半包问题,需要提前约定传输数据格式,即RPC协议,分为数据头和消息体。
- 数据头一般用于身份识别,包括协议标识、数据大小、请求类型、序列化类型等信息;
- 消息体主要是请求的业务参数信息和扩展属性等