RPC 框架
基本介绍
RPC(Remote Procedure Call 远程过程调用)的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明调用机制,让使用者不必显式的区分本地调用和远程调用。
RPC 过程
类似本地调用函数的过程,但需要通过网络作为中间桥梁,在客户端和服务器之间建立好链接,进而实现在客户端调用服务器端的函数的过程,这其中RFC框架需要解决一些问题:
-
如何确定需要调用的函数
服务器端的函数约定了自己的ID(不是函数指针),服务器在获取到ID后,对照ID和函数的对应表,从而确定需要调用的函数
-
如何确定参数
通过网络传递,在客户端发送指令时,将函数和参数一同打包(序列化),再通过网络发送给服务器
RPC 概念模型
分为五个部分:User, User-Stub, RPC-Runtime, Server-Stub和Server
本地的过程调用在User-Stub中打包(序列化),然后通过RPCRuntime在客户端和服务器端传输,服务器端接收到数据后,解包获得需要执行的函数和对应的参数,执行完成后返回执行结果
IDL 文件
Interface Description Language,接口描述语言,通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
在RPC 过程中,服务双方是通过约定的规范进行远程调用,双方都依赖同一份IDL文件,需要通过工具来生成对应的生成文件,具体调用的时候用户代码需要依赖生成代码,所以可以把用户代码和生成代码看做一个整体。
分层设计——以 Apache Thrift为例
解编码层
-
生成代码
服务端和客户端依赖同一份IDL文件,通过该文件可以生产多种语言的代码以便通信
-
数据格式
在对函数和参数进行序列化的时候,可以通过多种方式进行编码
- 语言特定格式,例如JAVA的
Java.io.SerializabIe,语言内置便于操作 - 文本格式:JSON、XML等,便于阅读
- 二进制编码:跨语言,高性能,例如TLV和Varint
- 语言特定格式,例如JAVA的
二进制编码
相对与xml/json来讲,解析速度更快,信息密度更大
TLV编码:
- Tag:标签,可理解为类型
- Length:长度
- Value:值,Value 也可以为 TLV 结构
-
选型
需要保证兼容性,通用性和良好的性能(时间和空间)
协议层
一般有两种协议,一种以特定字符作为每个协议单元结束的标识,另一种以定长+不定长的部分组成,通过length字段描述长度
对于 RPC 的协议字段
- LENGTH:32bits,包其余部分的大小,不包含本字段长度
- HEADER MAGIC:16bits,值为0x1000。标识版本信息,协议解析时快速校验
- FLAG:预留字段,16bits,暂未使用,默认0x0000
- SEQUENCE NUMBER:32bits,表示数据包的 seqID,用于多路复用,单连接内递增
- HEADER SIZE:16bits,头部长度字节数/4 , 从第 14 个字节开始计算一直到 PAYLOAD 前,最大长度为 64 k
- PROTOCOL ID:编解码方式,有 Binary 和Compact 两种
- TRANSFORM ID:压缩方式,如 zlib 和 snappy
- INFO ID:传递一些定制的 meta 信息
- PAYLOAD : 消息体
协议解析
健康监测
为什么需要做健康监测?
比如网络中的波动,硬件设施的老化等等。可能造成集群当中的某个节点存在问题,无法正常调用。
健康监测实现分析
心跳检测的过程总共包含以下状态:健康状态、波动状态、失败状态。
完善的解决方案
(1)阈值: 健康监测增加失败阈值记录。
(2)成功率: 可以再追加调用成功率的记录(成功次数/总次数)。
(3)探针: 对服务节点有一个主动的存活检测机制。