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

118 阅读4分钟

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

RPC 的基本概念

  • IDL(Interface Definition Language) 文件

    • Thrift
    • Protobuf
  • 生成代码
  • 编解码(序列化/反序列化)
  • 通信协议

    • 应用层协议
  • 网络通信

    • IO 网络模型

      • blocking IO
      • unblocking IO
      • IO multiplexing
      • signal driven IO
      • asynchronous IO
    • 传输层协议

      • TCP
      • UDP

基本概念

  • 相比本地函数调用,RPC调用需要解决的问题

    • 函数映射
    • 数据转换成字节流
    • 网络传输
  • 一次 RPC 的完整过程

    编写IDL 文件,通过编译器工具将idl文件转换成语言对应的静态库

    通信协议:规范了数据在网络中的传输内容和格式。

    网络传输: 通常基于成熟的网络库走tcp/udp传输

  • rpc的好处

    • 单一职责,有利于分工协作运维开发
    • 可扩展性强,资源使用率更优
    • 故障隔离,服务的整体可靠性更高
  • RPC 带来的问题将由 RPC 框架来解决

    • 服务宕机如何感知?
    • 遇到网络异常应该如何应对?
    • 请求量暴增怎么处理?

RPC 框架分层设计

  • 编解码层

    • 数据格式:

      • 语言特定格式

      • 文本格式: 可读性更强

      • 二进制编码

        • TLV 编码:Thrift 使用 TLV 编码

          tag,length,value

          编码结构简单清晰且扩展性较好,但存在冗余信息有额外的内存开销

        • Varint 编码:Protobuf 使用 Varint 编码

          除了最后一个字节外,varint编码中的每个字节都设置了最高有效位(most significant bit - msb)–msb为1则表明后面的字节还是属于当前数据的,如果是0那么这是当前数据的最后一个字节数据。每个字节的低7位用于以7位为一组存储数字的二进制补码表示,最低有效组在前,或者叫最低有效字节在前。这表明varint编码后数据的字节是按照小端序排列的。

    • 选项:

      • 兼容性: 支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度
      • 通用型: 支持跨平台,跨语言
      • 性能: 编码之后数据大小和编码耗费时长
  • 传输协议层

    • 消息切分

      • 特殊结束符 '\r\n'
      • 变长协议:length+body
    • 协议构造

      • 以 Thrift 的 THeader 协议为例讲解
  • 网络通信层

    • 网络库

      • 提供易用api :封装底层socket api ,连接管理和事务分发
      • 功能: 协议支持: tcp,udp,uds; 优雅退出,异常处理
      • 性能: 应用层buffer减少copy,高性能定时器对象池
    • 核心指标

      • 吞吐高
      • 延迟低

RPC 框架的核心指标

  • 稳定性

    • 保障策略

      • 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
      • 限流: 保护被调用方,防止大流量把服务压垮
      • 超时控制: 避免将资源浪费在不可用的节点上
    • 请求成功率

      • 负载均衡
      • 重试 重试有放大故障的风险,加大直接下游的负载
    • 长尾请求 指明显高于均值的那部分占比较小的请求,p99 剩下的1%就是长尾请求

  • 易用性

    • 开箱即用
    • 周边工具
  • 扩展性
    • 中间件
    • option
    • 编解码层
    • 协议层
    • 网络传输层
    • 代码生成工具插件扩展
  • 观测性

    • Log
    • Metric
    • Tracing
    • 内置观测性服务
  • 高性能

    这里分两个维度,高性能意味着高吞吐和低延迟,两者都很重要,甚至大部分场景下低延迟更重要。多路复用可以大大减少了连接带来的资源消耗,并且提升了服务端性能,我们的测试中服务端吞吐可提升30%。

    调用端向服务端的一个节点发送请求,并发场景下,如果是非连接多路复用,每个请求都会持有一个连接,直到请求结束连接才会披关闭或者放入连接池复用,并发量与连接数是对等的关系。

    而使用连接多路复用,所有请求都可以在一个连接上完成,大家可以明显看到连接资源利用上的差异

    手段:

    • 连接池

    • 多路复用

    • 高性能界面协议

    • 高性能网络库