RPC原理与实现 | 青训营笔记

77 阅读3分钟

这是我参与「第五届青训营」笔记创作活动的第11天

1. 本堂课重点内容

  • 基本概念
  • 分层设计

2. 基本概念

2.1 本地函数调用

func main() {
    var a = 2
    var b = 3
    result := calculate(a, b)
    fmt.Println(result)
    return
}

func calculate(x, y int) {
    z := x * y
    return z
}
  1. 将a和b的值压栈
  2. 通过函数指针找到calculate函数,进入函数取出栈中的值2和3,将其赋予x和y
  3. 计算x * y,并将结果存在z
  4. 将z的值压栈,然后从calculate返回
  5. 从栈取出z返回值,并赋值给result

2.2 远程函数调用

图片.png

2.3 RPC概念模型

图片.png

2.4 一次RPC的完整过程

图片.png

  • IDL文件
    • IDL通过一种中立的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信
  • 生成代码
    • 通过编译器工具把IDL文件转换成语言对应的静态库
  • 编解码
    • 从内存中表示到字节序列的转换称为编码,反之为解码,也常叫做序列化和反序列化
  • 通信协议
    • 规范了数据在网络中的传输内容和格式。除必须的请求/响应数据外,通常还会包含额外的元数据
  • 网络传输
    • 通常基于成熟的网络库 TCP/UDP 传输

2.5 RPC的好处

  1. 单一职责,有利于分工协作和运维开发
  2. 可扩展性强,资源使用率更优
  3. 故障隔离,服务的整体可靠性更高

图片.png

2.6 RPC带来的问题

  1. 服务宕机,对方应该怎样处理
  2. 在调用过程中发生网络异常,如何保证消息的可达性
  3. 请求量突增导致服务无法及时处理,有哪些应对措施

3.分层设计

3.1 Apache Thrift

图片.png

3.2 生成代码

图片.png

3.3 数据格式

  • 语言特定的格式
    • 许多编程语言都内建了将内存对象编码为字节序列的支持,例如java有java.io.Serializable
  • 文本格式
    • Json、XML、CSV等文本格式,具有人类可读性
  • 二进制编码
    • 具备跨语言和高性能等优点,常见的有Thrift的BinaryProtocol,Protobuf等

3.4 二进制编码

3.4.1 TLV编码

  • Tag: 标签,可以理解为类型
  • Length: 长度
  • Value: 值,Value也可以是TLV结构

编辑器描述结构体 图片.png

编码后的字节流

图片.png

3.5 编解码层-选型

  • 兼容性
    • 支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度
  • 通用性
    • 支持跨平台、跨语言
  • 性能
    • 从空间和时间两个维度来考虑,也就是编码后数据的大小和编码耗费时长

3.6 协议层概念

  • 特殊结束符
    • 一个特殊字符作为每个协议单元结束的标示

图片.png

  • 变长协议
    • 以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度

图片.png

3.7 协议构造

图片.png

  • LENGTH: 数据包大小,不包含自身
  • HEADER MAGIC: 标识版本信息,协议解析时候快速校验
  • SEQUENCE NUMBER:表示数据包的seqID,可用于多路复用,单链接内递增
  • HEADER SIZE: 头部长度,从第14个字节开始计算一直到PAYLOAO前
  • PROTOCOL ID: 编解码方式,有Binary和Compact两种
  • TRANSFORM ID:压缩方式,如zlib和snappy
  • INFO ID: 传递一些定制的meta信息
  • PLYLOAD: 消息体

3.8 协议解析

图片.png

3.9 网络通信层 - Sockets Api

图片.png

图片.png

3.10 网络通信层-网络库

  • 提供易用Api
    • 封装底层Socket Api
    • 连接管理和事件分发
  • 功能
    • 协议支持: tcp、udp和uds等
    • 优雅退出、异常处理
  • 性能
    • 应用层buffer减少copy
    • 高性能定时器、对象池等