这是我参与「第五届青训营」伴学笔记创作活动的第 10 天。
-
远程函数调用(RPC - Remote Procedure Calls)
两个服务部署在不同机器上
-
RPC需要解决的问题:
- 1.函数映射。怎么告诉一个服务调用那个函数?每个函数有id,rpc时带上这个id,通过id找到函数再去执行。
- 2.数据转换成字节流。如何把参数告诉远程?
- 3.网络传输。如何保持网络高效稳定传输数据?
-
RPC概念模型:
-
理论模型:User、User-Stub、RPC-Runtime、Server-Stub、Server
-
-
RPC基本概念:
-
相比于本地函数调用,远程函数调用是不知道对方有哪些方法,需要一种方式声明有哪些方法,方法参数,这样即可按照约定调用。约定的描述文件就叫IDL文件。
-
IDL (Interface description language)文件:IDL 通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
-
生成代码:通过编译器工具把 IDL 文件转换成语言对应的静态库
-
编解码:从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化。解决了跨语言的数据交互格式
-
通信协议:规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据
-
网络传输:通常基于成熟的网络库走 TCP/UDP 传输
-
-
RPC优缺点:
-
优点:1.单一职责,有利于分工协作和运维开发 2.可扩展性强,资源使用率更优 3.故障隔离,服务的整体可靠性更高
-
缺点:1.服务宕机,对方应该如何处理? 2.在调用过程中发生网络异常,如何保证消息的可达性? 3.请求量突增导致服务无法及时处理,有哪些应对措施?
-
以上缺点由RPC框架来处理
-
-
RPC框架分层设计
-
编解码层,协议层,网络通信层
-
编解码层
-
客户端和服务端依赖同一份IDl文件,生成不同语言的生成代码
-
IDL文件数据格式:
-
语言特定的格式:许多编程语言都内建了将内存对象编码为字节序列的支持,例如 Java 有 java.io.Serializable。兼容性问题
-
文本格式:JSON、XML、CSV 等文本格式,具有人类可读性。描述有缺陷,json不能区分整数浮点数,没有参数类型约束,而且性能较差
-
二进制编码:把数据转换成二进制流,具备跨语言和高性能等优点,常见有 Thrift 的 BinaryProtocol,Protobuf 等
-
实现方式:TLV编码。结构简单清晰,扩展性好,但tag和length有额外内存开销
-
-
-
编码格式选型:
- 兼容性:支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度
- 通用性:支持跨平台、跨语言;流行程度
- 性能:从空间和时间两个维度来考虑,也就是编码后数据大小和编码耗费时长
-
-
协议层
-
编码后的数据,需要依据约定的通信协议,添加额外信息,才能传输
-
概念:
-
特殊结束符:一个特殊字符作为每个协议单元结束的标示。“\r\n”
-
变长协议:以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度。“length”
-
-
协议解析:从内存中读取指定部分,magicNumber,知道什么类型的协议,再读取编码方式,知道用什么去解码,解出来交给上层处理
-
-
网络通信层
-
使用sockets API进行网络通信。位于传输层和应用层之间
-
bind,将socket绑定到IP+端口上,listen监听进来的连接,放到一个队列里,accept,客户端发起请求时接受请求,没有请求时阻塞,然后可以调用read,write进行通信,close关闭套接字。
-
常用封装好的网络库,作为rpc框架的网络通信层
- 选型指标:
- 提供易用 API:封装底层 Socket API连接管理和事件分发 功能:协议支持: tcp、udp 和 uds 等;优雅退出、异常处理等 性能:应用层 buffer 减少 copy;高性能定时器、对象池等
-
-
-
总结
了解了本地函数调用与RPC调用的区别,RPC的概念模型以及RPC框架的分层设计。