14 RPC框架分层设计 | 青训营笔记

56 阅读5分钟

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

RPC 基本概念

  • RPC:Remote Procedure Calls,远程函数调用。

  • RPC需要解决的问题:1. 函数映射;2. 数据转换成字节流;3. 网络传输

  • RPC概念模型

    《Implementing Remote Procedure Calls》

    • User
    • User-Stub
    • RPC-Runtime
    • Server-Stub
    • Server

一次RPC的完整过程

  • IDL (Interface Definition Language) 文件

    • Thrift
    • Protobuf
  • 生成代码

  • 编解码(序列化/反序列化):从内存到字节序列的转换,反之为解码

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

    • 应用层协议
  • 网络通信

    • IO 网络模型

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

      • TCP
      • UDP

RPC的好处与弊端

  • 好处

    1. 单一职责,有利于分工协作和运维开发
    2. 可扩展性强,资源使用率更优;可以针对不同场景分配资源
    3. 故障隔离,服务的整体可靠性更高
  • 缺点→由RPC框架解决

    1. 服务宕机时对方如何处理
    2. 网络异常时难以保证消息的可达性
    3. 请求量突增导致服务无法及时处理

RPC框架分层设计

  • Apache Thrift

    image.png

  • 编解码层

    • 生成代码:依赖同一份IDL文件

    • IDL文件数据格式:

      • 语言特定格式:实现简单,与特定编程语言绑定,其他语言无法读取数据,兼容性不足

      • 文本格式:如JSON、XML、CSV等,描述有缺陷,模型约束不足,性能较差

      • 二进制编码:具备跨语言和高性能的优点

        • TLV 编码:Thrift 使用 TLV 编码,有tag和length的冗余信息,增加内存,压缩率不足

          • type:表示类型
          • feild tag:使用tag表示用的字段,减少数据的表示大小
          • length:长度
          • value:值

          image.png

          image.png

        • Varint 编码:Protobuf 使用 Varint 编码

    • 编码格式选型:

      • 兼容性:支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活性
      • 通用型:支持跨平台、跨语言
      • 性能:时间短、空间占用小
  • 传输协议层

    • 消息切分

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

        image.png

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

        • length+body

        image.png

    • 协议构造

      • 以 Thrift 的 THeader 协议为例讲解

        image.png

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

      image.png

  • 网络通信层

    • Sockets API

      • 默认是阻塞模式
    • 网络库:提供易用API,功能丰富,提高性能

    • 核心指标

      • 吞吐高
      • 延迟低

RPC框架的核心指标

  • 稳定性

    • 保障策略

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

      • 负载均衡:均匀调用服务
      • 重试:失败后继续请求特定次数
    • 长尾请求:明显高于平均响应时间的小占比请求

      • BackupRequest:备份请求,利用它来提高稳定性,减少长尾请求的延时

      image.png

    • 注册中间件(拦截器):创建时以可选方式把上述策略加入,保障框架稳定性

  • 易用性

    • 开箱即用:提供合理的默认参数选项,有丰富的文档,不用额外配置
    • 周边工具:IDL生成代码工具、脚手架工具(如生成一些重复性代码)等等
  • 扩展性:提供尽可能多的扩展点,在middleware、option、编解码层等等都可以添加策略

  • 观测性

    • Log:日志
    • Metric:监控面板
    • Tracing:链路跟踪
    • 内置观测性服务:简单的http服务,给予用户观测当前框架的情况
  • 高性能

    • 场景:单机多级、单连接多连接、单多client 单多server、不同大小请求包、不同请求类型
    • 目标:高吞吐、低延迟(实际场景中更重要)
    • 手段:连接池、多路复用、高性能编解码协议、高性能网络库

Kitex实践

Kitex | CloudWeGo

  • Kitex 整体架构

    • Kitex Core:核心组件
    • Kitex Byted:与公司内部基础设施集成
    • Kitex Tool:代码生成工具

    image.png

  • 自研网络库 Netpoll

    • 背景:原生库无法感知连接状态;原生库存在goroutine暴涨的风险
    • 改进:引入epoll主动监听机制,感知连接状态;建立goroutine池,复用goroutine;引入Nocopy Buffer,向上层提供NoCopy的调用接口,编解码层面零拷贝,提升性能
    • 扩展性上支持多协议,也支持灵活的自定义协议扩展
  • 性能优化

    • 网络库优化:调度优化、LinkBuffer、Pool
    • 编解码优化:Codegen、JIT
  • 合并部署

    • 微服务过微,传输和序列化开销越来越大

    • 思路:将亲和性强的服务实例尽可能调度到同一个物理机,远程RPC调用优化为本地IPC调用

    • 合并部署方式

      • 中心化的部署调度和流量控制
      • 基于共享内存的通行协议
      • 定制化的服务发现和连接池实现
      • 定制化的服务启动和监听逻辑