RPC

RPC是远程过程调用,它是一种技术思想而非一种规范或协议,常见的RPC技术和框架有:

应用级的服务框架: Dubbo/Dubbox、Google gRPC、SpringBoot / SpringCloud
远程通信协议:Socket、REST(http json) 、SOAP(HTTP XML)
通信框架:MINA和Netty

gRPC: 是Google公布的开源软件,基于HTTP2.0协议,支持常见的多种众多编程语言,RPC框架是基于HTTP协议实现的,底层使用到了Netty框架的支持

Dubbo:阿里来源的一个极为出名的RPC框架,协议和序列化都可以插拨是极其鲜明的特色

RPC核心功能

服务寻址
服务寻址可以使用Call ID映射,在本地调用时,函数体是直接通过函数指针来指定的,但在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。

所以在RPC中,所以的函数都必须有自己的一个ID,这个ID在所以进程中都是唯一确定的

客户端在做远程过程调用时,必须附上这个 ID。然后我们还需要在客户端和服务端分别维护一个函数和Call ID的对应表。

当客户端需要进行远程调用时,它就查一下这个表,找出相应的 Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。

实现方式:服务注册中心。

要调用服务,首先你需要一个服务注册中心去查询对方服务都有哪些实例。Dubbo 的服务注册中心是可以配置的,推荐使用 Zookeeper。

序列化和反序列化
客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。

但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。

这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。

只有二进制数据才能在网络中传输,序列化和反序列化的定义是:

将对象转换成二进制流的过程叫做序列化
将二进制流转换成对象的过程叫做反序列化
这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。

网络传输

网络传输:远程调用往往用在网络上,客户端和服务端是通过网络连接的。

所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。

只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。

尽管大部分 RPC 框架都使用 TCP 协议,但其实 UDP 也可以,而 gRPC 干脆就用了 HTTP2。
TCP 的连接是最常见的,简要分析基于 TCP 的连接:通常 TCP 连接可以是按需连接(需要调用的时候就先建立连接,调用结束后就立马断掉),也可以是长连接(客户端和服务器建立起连接之后保持长期持有,不管此时有无数据包的发送,可以配合心跳检测机制定期检测建立的连接是否存活有效),多个远程过程调用共享同一个连接。

所以,要实现一个 RPC 框架,只需要把以下三点实现了就基本完成了:

Call ID 映射:可以直接使用函数字符串,也可以使用整数 ID。映射表一般就是一个哈希表。
序列化反序列化:可以自己写,也可以使用 Protobuf 或者 FlatBuffers 之类的。
网络传输库:可以自己写 Socket,或者用 Asio,ZeroMQ,Netty 之类。