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

27 阅读5分钟

1.基本概念

1.1 本地函数的调用

  • 将a和b的值压栈
  • 通过函数指针找到calculate函数,进入函数取出栈中的值2和3,将其赋予×和y
  • 计算×* y,并将结果存在z
  • 将z的值压栈,然后从calculate返回5.从栈中取出z返回值,并赋值给result

1.2 远程函数调用(RPC-Remote Procedure Calls)

RPC 需要解决的问题

  • 函数映射
  • 数据转换成字节流
  • 网络传输

1.3 RPC概念模型

RPC概念模型.png

1.4 一次RPC的完整过程

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

1.5 RPC的好处

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

1.6 RPC带来的问题

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

2.分层设计

2.1 以Apache Thrift为例

  • 用户自己编写的业务逻辑代码
  • 通过代码生成工具把IDL文件转换成不同语言对应的lib代码,里面封装了编解码逻辑
  • 框架的编解码层
  • 框架的协议层
  • 框架的网络通信层

2.2 编解码层-生成代码

编解码层.png

2.3 编解码层-数据格式

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

2.4 编解码层-二进制编码

TLV编码

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

2.5 编解码层-选型

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

2.6 协议层-概念

  • 特殊结束符 一个特殊字符作为每个协议单元结束的标示
  • 变长协议 以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度

2.7 协议层-协议构造

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

2.8 协议层-协议解析

协议解析.png

2.9 网络通信层-Socket API

socketapi.png

2.10 网络通信层-网络库

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

3.关键指标

3.1 稳定性-保障策略

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

3.2 稳定性-请求成功率

请求成功率.png

3.3 稳定性-长尾请求

长尾请求.png

3.3 稳定性-长尾请求

3.4 稳定性-注册中间件

注册中间件.png

3.5 稳定性-易用性

  • 开箱即用 合理的默认参数选项、丰富的文档
  • 周边工具 生成代码工具、脚手架工具

Suite简单易用的命令行工具

  • 生成服务代码脚手架
  • 支持protobuf 和thrift
  • 内置功能丰富的选项
  • 支持自定义的生成代码插件

3.6 稳定性-扩展性

  • Middleware
  • Option
  • 编解码层
  • 协议层
  • 网络传输层
  • 代码生成工具插件扩展

3.7 稳定性-高性能

  • 场景

    • 单机多机
    • 单连接多连接
    • 单/多client单/多server
    • 不同大小的请求包
    • 不同请求类型:例如pingpong、streaming等
  • 目标

    • 高吞吐
    • 低延迟
  • 手段

    • 连接池
    • 多路复用
    • 高性能编解码协议
    • 高性能网络库

4.小结

  • 框架通过中间件来注入各种服务治理策略,保障服务的稳定性
  • 通过提供合理的默认配置和方便的命令行工具可以提升框架的易用性
  • 框架应当提供丰富的扩展点,例如核心的传输层和协议层
  • 观测性除了传统的Log、Metric和Tracing之外,内置状态暴露服务也很有必要
  • 性能可以从多个层面去优化,例如选择高性能的编解码协议和网络库