RPC 框架分层设计| 青训营

RPC 框架分层设计与企业实践

RPC(Remote Procedure Call)是一种远程过程调用技术,用于在不同计算机或进程间调用函数。RPC框架的设计涉及多个分层,包括编解码层、协议层、网络通信层等,同时也需要考虑稳定性、性能优化、易用性等方面的问题。以下是关于RPC框架分层设计和企业实践的详细整理笔记。

基本概念

  • 本地函数调用:同一程序内部的函数之间的调用。
  • 远程函数调用(RPC):在不同计算机或进程之间进行的函数调用。
  • RPC需要解决的问题:函数映射、数据序列化、网络传输。

一次 RPC 的完整过程

  1. IDL(Interface Description Language)文件:使用中立方式描述接口,使不同平台、不同语言的程序可以相互通信。
  2. 生成代码:IDL通过编译器生成语言对应的静态库,用于后续调用。
  3. 编解码:将数据从内存表示转换为字节序列(编码),或者从字节序列转换为内存表示(解码)。
  4. 通信协议:规范数据在网络中的传输内容和格式,通常包括请求/响应数据和元数据。
  5. 网络传输:基于成熟的网络库,通过TCP/UDP进行数据传输。

RPC 的好处

  1. 单一职责:有利于分工合作和运维开发。
  2. 可扩展性:资源使用率更优,便于水平扩展。
  3. 故障隔离:提高整体服务可靠性,出现问题不会影响整个链路。

RPC 带来的问题

  1. 服务宕机处理:如何应对被调用服务宕机的情况,保障调用方稳定性。
  2. 网络异常保证:处理调用过程中的网络异常,保证消息的可达性。
  3. 请求量突增应对:有效措施应对突发请求,防止服务不可用。

分层设计

编解码层

负责数据的序列化和反序列化,将数据转换为字节序列以及反之。

协议层

定义数据的传输格式和结束标识,可以使用特殊结束符或变长协议。

特殊结束符

一个特殊字符作为每个协议单元结束的标示

变长协议

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

网络通信层

封装底层的Socket API,处理连接管理、事件分发等,提供易用的网络通信接口。

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

关键指标与企业实践

稳定性 - 保障策略
  • 熔断:保护调用方,防止被调用的服务故障影响整个链路。
  • 限流:保护被调用方,避免大流量压垮服务。
  • 超时控制:避免资源浪费在不可用节点上。
稳定性 - 请求成功率

保证尽可能高的请求成功率,降低失败率,提升用户体验。

稳定性 - 长尾请求

处理长时间运行的请求,防止因少数请求而影响整体性能。

稳定性 - 注册中间件

使用注册中间件管理服务的注册与发现,保证调用的准确性和稳定性。

易用性
  • 提供开箱即用的功能,减少部署和配置的复杂性。
  • 提供丰富的文档和示例,方便开发者使用和理解。
  • 提供周边工具,如代码生成工具、脚手架工具等,简化开发流程。
扩展性
  • 使用中间件和选项来实现功能的扩展和定制。
  • 可以扩展编解码层、协议层、网络传输层等组件。
观测性
  • 使用日志、指标和追踪来监控系统的运行状态。
  • 内置观测性服务,方便收集和分析运行数据。
高性能

通过网络库、编解码优化、内存管理等手段提升系统性能。

企业实践 - 套件

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

自研网络库 - 背景

原生库无法感知连接状态 在使用连接池时,池中存在失效连接,影响连接池的复用

原生库存在 goroutine 暴涨的风险 一个连接一个 goroutine 的模式,由于连接利用率低下,存在大量 goroutine 占用调度开销,影响性能.

解决无法感知连接状态问题 引入 epoll 主动监听机制,感知连接状态 解决 goroutine 暴涨的风险

建立 goroutine 池,复用 goroutine

提升性能 引入 Nocopy Buffer,向上层提供 NoCopy 的调用接口,编解码层面零拷贝

性能优化 - 网络库优化、

调度优化 epoll_wait 在调度上的控制 gopool 重用 goroutine 降低同时运行协程数 LinkBuffer 读写并行无锁,支持 nocopy 地流式读写 高效扩缩容 Nocopy Buffer 池化,减少 GC Pool 引入内存池和对象池,减少 GC 开销

性能优化 - 编解码优化

Codegen 预计算并预分配内存,减少内存操作次数,包括内存分配和拷贝Inline 减少函数调用次数和避免不必要的反射操作等自研了 Go 语言实现的 Thrift IDL 解析和代码生成器,支持完善的 Thrift IDL 语法和语义检查,并支持了插件机制 - Thriftgo JIT 使用 JIT 编译技术改善用户体验的同时带来更强的编解码性能,减轻用户维护生成代码的负担基于 JIT 编译技术的高性能动态 Thrift 编解码器 - Frugal

合并部署

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

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

posted @ 2023-08-04 21:43  LucianaiB  阅读(45)  评论(0)    收藏  举报  来源