由浅入深了解 RPC 框架 | 青训营笔记

637 阅读9分钟

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

深入了解 RPC 框架 ~

前言:RPC 是什么?

传统的单体应用架构目前已经过时了,现在流行的分布式和微服务架构不同的功能模块往往会部署在不同的服务器上,在方法调用时调用到其他服务器上的服务必须通过网络来表达调用的语义和传达调用的数据,这时就是要借助 RPC 来帮忙。

本次课程讲解了 RPC 框架的基本概念,并分析了其分层设计。支持 Golang 的 RPC 框架有很多,掌握 RPC 的概念与框架的设计理念,对我们今后学习和使用 Go 语言的各种 RPC 框架非常有帮助,甚至可以尝试去手撸一个 RPC 框架...

image.png


RPC 基本概念

RPC 全称 Remote Procedure Call (远程过程调用),RPC 的应用场景之一就是目前大火的分布式与微服务领域,让一台服务器直接通过网络调用另一台服务器上的函数/方法。

RPC 允许像调用本地服务一样调用远程服务。

image.png

RPC 解决的问题:

  1. 函数映射:也就是告诉另一台服务器我要调用的是哪个函数,因为是两台服务器两个进程地址空间,不能像本地调用那样用指针或者引用,远程调用要通过一个 ID 来确定调用的函数。
  2. 数据转换成字节流:远程调用时方法的参数需要通过底层网络协议(TCP)传递到目标服务器,内存中的参数需要序列化成二进制形式发送给另一条服务器。
  3. 网络传输:远程调用都是在网络上的,因此要保证在网络上高效、稳定地传输数据。
RPC 概念模型

1984 年 Nelson 发表了论文 《Implementing Remote Procedure Calls》 ,其中提出了 RPC 的过程由 5 个模型组成:User、User-Stub、RPC-Runtime、Server-Stub、Server。

image.png

在网络上存在调用(Caller)机器与被调(Callee)机器,Caller 中的 User 发起一次本地调用,User-stub 会将参数打包,经过 RPCRuntime 发从至被调机器,被调机器将参数解压后执行 Server 中真正的业务逻辑,并将结果经 Server-stub 打包后再发送给调用机器,调用机器解压出执行结果再返回。

一次 RPC 的完整过程

在实际的应用中,RPC 通常由以下几个部分组成:IDL、生成代码、编解码、通信协议、网络传输。

image.png

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

PRC 的优点:

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

RPC 框架与分层设计

PRC 带来好处的同时也会带来一些问题,比如:

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

以上的问题就需要 RPC 框架来解决,RPC 框架在设计上大体可分成三个层次:编解码层。协议层。网络通信层。

编解码层:

编解码在实现上要综合考量兼容性、通用性与性能,有以下三种数据格式可供选择:

  • 语言特定的格式:许多编程语言内建了将内存对象编码为字节序列的支持(序列化/反序列化)。
  • 文本格式:JSON、XML、CSV 等文本格式,可读性强。
  • 二进制编码:具备跨语言和高性能等优点,常见有 Thrift 的 BinaryProtocol、Protobuf 等。

协议层:

编解码层将数据打包好以后需要按照一定的规则添加一些元数据,因此 RPC 框架需要约定一个可靠的协议。

协议有两种比较常见的格式:

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

以 Thrift 框架为例,协议单元除了消息体(payload)以为还会包含很多额外的数据:

  • length - 数据包大小
  • header magic - 标识版本信息,协议解析时候快速校验
  • sequence number - 表示数据包的 seqID,可用于多路复用
  • header - size - 头部长度
  • protocol ID - 编解码方式,有 Binary 和 Compact 两种
  • Transform ID - 压缩方式,如 zlib 和 snappy
  • info ID - 传递一些定制的 meta 信息

框架会先从内存中读取一个魔法数(Magic Number)来确定协议的类型,再读取到编码方式从而解码消息体。

image.png

网络通信层:

网络通信层需要借用操作系统提供的 Sockets API 实现,现实中一般使用封装好的网络库作为 RPC 框架的网络通信层。

网络库的选择要考虑到:

  • 提供易用的 API;
  • 功能完整,支持 tcp、udp 和 uds 多种协议,具备异常处理;
  • 性能好,使用高性能定时器、对象池等手段提高网络库的性能。

RPC 关键指标

衡量 RPC 框架的五大关键指标:稳定性、易用性、扩展性、观测性、高性能。

(1)稳定性:

可以采取一些保障策略确保稳定性,有以下三个降级措施:

✔ 熔断: 当服务出现不可用的情况时暂时停掉对该服务的调用。保护调用方,防止被调用的服务出现问题而影响到整个链路。

✔ 熔断: 当请求 QPS 超过阈值时对请求量进行限制,防止大流量把服务压垮。

✔ 超时控制: 避免浪费资源在不可用节点上。

稳定性的另一大关键指标是 请求成功率,可以采取负载均衡和重试等手段提高成功率。

长尾请求

还有一个优化的点是 长尾请求。在分布式系统中,由于网络波动、系统调度和服务器负载等原因,难免会出现较大的请求延迟。关于请求延迟业界有一个常用的 P99 标准,它是指 99% 的请求延迟都在某个耗时以内,只有 1% 的请求会大于这个时间,这 1% 就可以认为是长尾请求。

长尾请求拿到响应以后,如果响应失败会再次重传,这就导致请求时间会比较长,一个优化的方法是 Backup Request

image.png

以 99% 的请求耗时为基准,第一次发起请求以后,不需要等待响应结果,一旦时间超过基准就认为这次请求可能会失败,立刻发起第二次请求,这样可以减少长尾请求等待响应造成的时间开销。

在 RPC 框架的实际应用中,使用 注册中间件 来把上面保证稳定性的措施整合起来,用户需要时直接选择需要的功能开启就可以了。

(2)易用性:

✔ 开箱即用: 合理的默认参数,丰富的文档。

✔ 周边工具: 生成代码工具,脚手架工具。

(3)扩展性:

一个优秀的 RPC 框架应该提供尽可能多的扩展点,包括中间件、代码生成工具、编解码层、协议层、网络层的扩展插件等等。

(4)观测性:

框架的观测性也非常重要,在使用 RPC 框架的过程中要有一些方法能检测运行,比如 Log(日志)、Metric(监控)、Tracing(链路跟踪)还有 RPC Framework 往往会内置观测服务。

(5)高性能:

高性能的目标是高吞吐和低延迟,性能可以从多个层面进行优化:

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

企业实践 - KiteX 框架

KiteX 是字节跳动官方出品的 Go 语言微服务 RPC 框架,目前已经开源。

KiteX 三大核心:Kitex Core(核心组件)、KiteX Byted(与公司内部基础设施集成)、KiteX Tool(代码生成工具)。

自研网络库:

其底层采用的网络库 Netpoll 也是字节跳动自研产品,虽然 Go 本身自带了网络库支持,但是原生库无法感知连接状态,存在 goroutine 暴涨的风险,Netpoll 由此诞生,并且性能上相比原生库也有很大的提高。

扩展性设计:

KiteX 支持多协议,也支持灵活的自定义扩展。在编解码层支持 Thrift 与 Protobuf 两种协议,应用层支持 Http 2,传输层支持 TCP、UTP 等等。

性能优化:

KiteX 在多个层次进行了性能优化。比如网络库引入内存池和对象池,减少 GC 开销,引入了 Nocopy Buffer,支持读写并行等;编解码层面使用 JIT 编译技术建勇用户维护生成代码的负担;在代码生成工具上自研了 Thrift IDL 解析和代码生成器,支持完善的 Thrift IDL 语法和语义检查,并支持了插件机制。

合并部署:

合并部署是一个新的微服务形态。

微服务过微会导致传输和序列化开销越来越大,一个优化思路是将亲和性强的服务实例尽可能调度到同一个物理机,远程 RPC 调用优化为本地 IPC 调用。


🚀【参考】🚀

  1. 字节内部课:RPC 框架分层设计 - 掘金 (juejin.cn)
  2. 什么是RPC,你知道嘛? - 知乎 (zhihu.com)
  3. 熔断、限流、降级的区别 - feshfans - 博客园 (cnblogs.com)
  4. 网络中的长尾问题_legend050709ComeON的博客-CSDN博客_什么是长尾问题