RPC框架的分层 | 青训营

198 阅读5分钟

2023-08-29-11-25-36-image.png 简单来说:可以分为编解码层协议层网络通信层

  • 广义编解码层:包括Service.client\Processorread\writeTProtocal
  • 狭义编解码层TProtocal
  • Code部分是不在框架内的
  • IDL:Service.client\Processor + read\write
    • 是RPC框架的约束
    • client和server依赖同一份IDL文件 2023-08-29-11-34-03-image.png 并通过工具将IDL文件转换成不同语言的代码

1.1 编解码层

1.1.1 数据格式

  • 语言特定编码格式:许多编程语言都内建了将内存对象编码字节序列的支持
    这种编码形式好处是非常方便,可以用很少的额外代码实现内存对象的保存与恢复,这类编码通常与特定的编程语言深度绑定,其他语言很难读取这种数据。如果以这类编码存储或传输数据,那你就和这门语言绑死在一起了。安全和兼容性也是问题。

  • 文本格式:JSON、XML、CSV等文本格式,具有人类可读性
    文本格式具有人类可读性,数字的编码多有歧义之处,比如XML和CSV不能区分数字和字符串。JSON虽然区分字符串和数字,但是不区分整数和浮点数,而且不能指定精度,处理大量数据时,这个问题更严重了。
    没有强制模型约束,实际操作中往往只能采用文档方式来进行约定,这可能会给调试带来一些不便。由于JSON在一些语言中的序列化和反序列化需要采用反射机制,所以在性能比较差。

  • 二进制编码:具备跨语言和高性能等优点
    常见有ThriftBinaryProtocol, s.Protobuf 等,实现可以有很多种, TLV 编码和 Varint 编码,本质上是转换为二进制流

1.1.2 二进制编码

  • TLV编码: 结构:
    • Tag:标签,可以理解为类型
    • Lenght: 长度
    • Value:值,Value 也可以是个TLV结构
      2023-08-29-11-46-37-image.png
      TLV编码有额外字节的开销:比如field tagLength

1.1.3 编码选型

  • 通用性: 通用性有两个层面的意义:

    • 技术层面
      序列化协议是否支持跨平台、跨语言。如果不支持,在技术层面上的通用性就大大降低了。
    • 流行程度
      序列化和反序列化需要多方参与,很少人使用的协议往往意味着昂贵的学习成本;另一方面,流行度低的协议,往往缺乏稳定而成熟的跨语言、跨平台的公共包。
  • 兼容性
    在移动互联时代,业务系统需求的更新周期变得更快,新的需求不断通现,而老的系统还是需要继续维护。
    如果序列化协议具有良好的可扩展性,支持自动增加新的业务字段,而不影响老的服务,这将大大提供系统的灵活度

  • 性能

    • 空间开销(Verbosity)
      序列化需要在原有的数据上加上描述字段,以为反序列化解析之用。如果序列化过程引入的额外开销过高,可能会导致过大的网络,磁盘等各方面的压力。对于海量分布式存储系统,数据量往往以TB为单位,巨大的的额外空间开销意味着高昂的成本。
    • 时间开销(Complexity
      复杂的序列化协议会导致较长的解析时间,这可能会使得序列化和反序列化阶段成为整个系统的瓶颈

1.2 协议层

协议是双方确定的交流语义。
比如:我们设计一个字符传输的协议,他允许客户端发送一个字符串。这个协议很简单,首先发送4字节的消息总长度,然后再发送1字节的的字符集charset长度,接下来就是消息的payload,字符集名称和字符串正文。

特殊结束符协议

2023-08-29-14-03-26-image.png

  • 过于简单,对于一个协议单元必须要全部读完才能够进行处理,除此之外,必须要防止用户传输的数据不能同结束符相同,否则就会出现紊乱
  • HTTP 协议头就是以回车(CR)加换行(LF)符号序列结尾。

变长协议:

2023-08-29-14-08-11-image.png

  • 一般是自定义协议,由headerpayload组成,会以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度,使用比较广泛。

协议构造

2023-08-29-14-09-16-image.png

  • LENGTH字段:
    32bits,包括数据包剩余部分的字节大小,不包含LENGTH自身长度
  • HEADER MAGIC 字段:
    16bits,值为:Ox1000,用于标识协议版本信息,协议解析的时候可以快速校验
  • FLAGS字段:
    16bits,为预留字段,暂未使用,默认值为 0x0000
  • SEQUENCENUMBER字段:
    32bits,表示数据包的seqId,可用于多路复用,最好确保单个连接内递增
  • HEADER SIZE字段:
    16bits,等于头部长度字节数/4,头部长度计算从第14个字节开始计算,一直到PAYLOAD前 (备注:header的最大长度为64K)
  • PROTOCOL ID字段:
    uint8编码,取值有:~ProtocollDBinary = 0ProtocollDCompact = 2
  • NUM TRANSFORMS字段:
    uint8编码,表示TRANSFORM个数
  • TRANSFORM ID字段:
    uint8编码,表示压缩方式zlib or snappy
  • INFO ID 字段:
    uint8 编码,用于传递一些定制的 meta 信息
  • PAYLOAD消息内容

1.3 网络通信层

未完待续……