RPC协议介绍
RPC
,是Remote Procedure Call
的缩写,意为远程过程调用,使得调用远程服务的方法,就像我们调用本地方法一样简单,并且我们不需要关心整个过程底层的细节。
RPC
协议被广泛应用于分布式系统节点间的通信,我所接触的分布式存储Curve
就广泛使用了RPC
协议.
关于RPC
协议的实现,有很多RPC框架可以为我们所用,比如gRPC
dubbo
等,因此我们一般不需要去自己实现RPC
。
RPC架构
整个RPC
架构可以看做五个部分:
- 客户端,调用远程方法
- 客户端
stub
:把客户端调用的方法以及参数等信息传往服务端 - 网络传输:在客户端
stub
以及服务端stub
之间传递信息,可以是基于TCP也可以是基于UDP - 服务端
stub
:接收客户端的方法调用请求,调用方法,向客户端stub
返回执行结果 - 服务端:提供远程方法
一次RPC调用
一次RPC
调用的流程如下:
- 客户端调用方法(就像调用本地方法一样)
- 客户端
stub
将调用的方法及参数信息打包为RpcRequest
并序列化 - 客户端
stub
得到远程服务地址,将消息发送给服务端 - 服务端
stub
接收到消息,反序列化得到RpcRequest
,根据RpcRequest
中的方法和参数调用本地方法,将得到的结果封装为RpcRequest
并序列化 - 服务端
stub
将RpcResponse
响应给客户端stub
- 客户端
stub
反序列化消息得到RpcResponce
,得到方法调用结果
为什么需要RPC协议?
相信很多第一次接触RPC
协议的人,在看完RPC
的介绍之后,不禁心生疑惑:这不就是消息传输吗?我已经有了TCP
乃至HTTP
,不是也可以达到同样的效果吗?那为什么还会有RPC
协议并且应用还这么广泛?
我在第一次接触到RPC
的时候也有同样的疑惑,并且在很长一段时间里对RPC
的理解都比较模糊,那么我们就从TCP
说起吧!
众所周知,TCP
可以实现可靠的、面向连接的、基于字节流的消息收发,由于是基于字节流的传输,TCP
的消息是没有边界的,我们接收和发送的消息就是源源不断的字节流,我们不知道哪些字节流是一个完整的消息,我们可能会收到半个消息也可能会收到一个半消息,想要区分消息的边界就需要我们自己去定义规则来处理,比如传递一个消息时加上消息长度或者加上开始和结束标识,这样我们就可以在源源不断的字节流中区分一个一个完整的消息,我前段时间写了一个Go
库tcpack就是用来解决这个问题。
可以看到,纯的TCP
通信是不可以直接拿来用的,需要我们在应用层面做相应的处理才可以完美地运行,因此就出现了HTTP
websocket
等应用层协议,它们都是基于TCP
的,提供了更好的封装以支持不同的场景。
大多数的RPC
也是基于TCP
的,运行在应用层,其实历史上RPC
的出现比HTTP
更早,HTTP
主要处理超文本的传输,并且它是很标准的,因为要确保任何一个浏览器可以向全世界任何一台服务器发起HTTP
请求,其请求头中包含了太多的固定的信息,并且使用JSON
去序列化结构体数据,相比之下,RPC
协议常常用于公司内部微服务之间的通信,它更加灵活,每个公司都可以定制自己的RPC
框架,并且可以使用Protobuf
这种性能更好的序列化协议去序列化传输数据。
综上所述,RPC
性能相比HTTP
更好并且实现更灵活,更广泛地应用于微服务以及分布式节点通信场景中。