RPC框架和关键指标 | 青训营

89 阅读6分钟

RPC架构

RPC是一种进程间通信方式,允许像调用本地服务一样调用远程服务,通信协议大多采用二进制方式。

下面就来介绍一下RPC的基本概念、三层核心框架、框架的核心指标以及相关实践。

基本概念

本地函数调用

image.png

远程函数调用(RPC-remote procedure calls)

image.png

要解决的问题:

  • 函数映射:

    怎么告诉网上商城我们要调用付款的这个函数,而不是退款或者充值呢?

    在本地调用中,函数体是直接通过函数指针来指定的,我们调用哪个函数,编译器就自动帮我们调用它相应的函数指针。

    但是在远程调用中,指针是不行的,因为两个进程的地址空间是完全不一样的。所有函数都有一个自己的ID,在做RPC的时候要附上这个ID,还得有个ID和函数的对照关系表,通过ID找到对应的函数并执行。

  • 数据转换成字节流:

    客户端怎么把参数值传给远程的函数呢?

    在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。

    在远程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。这时候就需要把客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。

  • 网络传输:

    远程调用往往用在网络上,要保证在网络上高效稳定地传输数据。

1984年论文中提出RPC的过程有5个模型:

  • user
  • user-stub
  • RPC-Runtime
  • Server-stub
  • server

image.png

一次RPC的完整过程

image.png

RPC的好处

image.png

RPC带来的问题

image.png

分层设计

  • 编解码层
  • 协议层
  • 网络通信层

Apache Thrift例子

image.png

编解码层

image.png 生成代码

image.png

编码数据格式

  • 语言特定的格式

    许多编程语言都内建了将内存对象编码为字节序列的支持,例如Jsva有java.io.serializable

  • 文本格式

    JSON XML CSV等文本格式,具有人类可读性

  • 二进制编码

    具备跨语言和高性能等优点,常见有Thrift的BinaryProtocol,Protobuf等

TLV结构

image.png

编码后是一串字节流,各个类型是用编号表示的,tag表示标识的是什么(前面string换成了tag=1),减少了数据描述的大小

格式:type--tag--length--value

选型

  • 兼容性

    支持自动增加新的字段,而不影响老的服务,这将提高系统的灵活度。

  • 通用性

    支持跨平台、跨语言

  • 性能

    从空间和时间两个维度来考虑,也就是编码后数据大小和编码耗费时长。

协议层

image.png

image.png

协议构造

image.png

协议解析

image.png

网络通信层

image.png

sockets API

image.png

必须知道IP和端口

网络库

  • 提供易用API

封装底层Socket API; 连接管理和事件分发

  • 功能

协议支持:tcp、udp和uds等; 优雅退出、异常处理

  • 性能

应用层buffer减少copy; 高性能定时器,对象池等

关键指标

  • 稳定性
  • 易用性
  • 扩展性
  • 观测性
  • 高性能

稳定性

保障策略

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

image.png

请求成功率

image.png

长尾请求

长尾请求指明显高于均值的那部分占比较小的请求。

image.png

如图,t4是长尾请求耗时,明显比t1加t2少,这样机制能大大减少整体延时。

注册中间件

image.png

Kitex Client 和 Server 的创建接口均采用 Option 模式,提供了极大的灵活性,很方便就能注入这些稳定性策略。

易用性

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

image.png

扩展性

image.png

一次请求发起首先会经过治理层面,治理相关的逻据被封装在middleware中,这些middleware会被构造成一个有序调用链逐个执行,比如服务发现、路由、负载均衡、超时控制等,mw执行后就会进入到remote 模块,完成与远端的通信。

观测性

image.png

除了传统的 Log、Metric、Tracing 三件套之外,对于框架来说可能还不够,还有些框架自身状态需要暴露出来,例如当前的环境变 量、配置、Client/Server初始化参数、缓存信息等。

高性能

image.png

两个维度,高性能意味着高吞吐和低延迟,两者都很重要,甚至大部分场景下低延迟更重要。

多路复用可以大大减少了连接带来的资源消耗,并且提升了服务端性能,我们的测试中服务端吞吐可提升30%。 右边的图帮助大家理解连接多路复用调用端向服务端的一个节点发送请求,并发场景下,如果是非连接多路复用,每个请求都会持有一个连接,直到请求结束连接才会被关闭或者放入连接池复用,并发量与连接数是对等的关系。 而使用连接多路复用,所有请求都可以在一个连接上完成,大家可以明显看到连接资源利用上的差异。

小结

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

企业实践

整体架构 -kitex

image.png

自研网络库的必要

  • 原生库无法感知连接状态

在使用连接池时,池中存在失效连接,影响连接池的复用。

  • 原生库存在 goroutine 暴涨的风险

一个连接一个 goroutine 的模式,由于连接利用率低下,存在大量 goroutine 占用调度开销,影响性能。

Netpoll

  • 解决无法感知连按状态问题

引入 epoll 主动监听机制,感知连接状态

  • 解决 goroutine 暴涨的风险

建立 goroutine 池,每用 goroutine

  • 提升性能

引入 Nocopy Bufer,向上层提供 NoCopy 的调用接口,编解码层面零拷贝。

拓展性设计

image.png

  • kitex支持多协议的并且也是可扩展的,交互方式上前面已经说过支持ping-pong、streaming、oneway
  • 编解码支持thrift、Protobuf
  • 应用层协议支持TTHeader、 Http2、也支持裸的thrift协议
  • 传输层目前支持TCP,未来考虑支持UDP、kernel-bypass的RDMA
  • 框架内部不强依赖任何协议和网络模块,可以基于接口扩展,在传输层上则可以集成其他库进行扩展。

性能优化-网络库优化

image.png

性能优化-编解码优化

image.png

合并部署

image.png

image.png