241125学习日志——[CSDIY] [ByteDance] 后端训练营 [18]
CSDIY:这是一个非科班学生的努力之路,从今天开始这个系列会长期更新,(最好做到日更),我会慢慢把自己目前对CS的努力逐一上传,帮助那些和我一样有着梦想的玩家取得胜利!!!
第一弹:Cpp零基础学习【30 DAYS 从0到1】
第二弹:Cpp刷题文档【LeetCode】
第三弹:Go开发入门【字节后端青训营】
第四弹:Cpp简单项目开发【黑马Rookie】
第五弹:数据结构绪论【数据结构与算法】
第六弹:Go工程实践【字节后端青训营】
第七弹:高质量编程和性能调优【字节后端青训营】
第八弹:Linux 基础知识【书生大模型训练营】
第九弹:Python 基础知识【书生大模型训练营】
第十弹:Git 基础知识【书生大模型训练营】
第十一弹:玩转HF/魔搭/魔乐社区【书生大模型训练营】
第十二弹:书生大模型全链路开源体系【书生大模型训练营】
第十三弹:玩转书生「多模态对话」与「AI搜索」产品【书生大模型训练营】
第十四弹:浦语提示词工程实践【书生大模型训练营】
第十五弹:HTTP 框架修炼之道【字节后端青训营】
第十六弹:打开抖音会发生什么【字节后端青训营】
第十七弹:将我的服务开放给用户【字节后端青训营】
第十八弹:InternLM + LlamaIndex RAG 实践【书生大模型训练营】
第十九弹:深入浅出 RPC 框架【字节后端青训营】
241125——[ByteDance] [06] 深入浅出 RPC 框架
01. 基础概念
1.1 本地函数调用
压栈…弹栈…等等操作
基于 Go 语言的实现。
1.2 远程函数调用(RPC - Remote Procedure Calls)
RPC 需要解决的问题
- 函数映射
- 数据转换成字节流
- 网络传输
1.3 RPC 概念模型
1.4 一次 RPC 的完整过程
IDL 文件:Interface description language
生成文件
编解码
通信协议
网络传输
1.5 RPC 的好处
- 单一职责,有利于分工协作和运维开发
- 可扩展性强,资源使用率更优
- 故障隔离,服务的整体可靠性更高
1.6 RPC 带来的问题
- 服务宕机,对方如何处理?
- 在调用过程中发生网络异常
- 请求量徒增导致服务无法及时处理
👇
RPC 框架应运而生
02. 分层设计
编解码层|协议层|网络通信层
2.1 分层设计 - 以 Apache Thrift 为例
用户编写的业务逻辑代码
👇
通过代码生成工具转化为 lib 代码
👇
框架的编解码层
👇
框架的协议层
👇
框架的网络通信层
2.3 编解码层 - 生成代码
IDL 生成不同语言的 CodeGen
2.4 编解码层 - 数据格式
- 语言特定格式
- 许多编程语言都内建了将内存对象编码为字节序列的支持
- 文本格式
- JSON、XML、CSV 等文本格式,具有人类可读性
- 二进制编码
- 具备跨语言和高性能等优点,常见有 Thrift 的 BinaryProtocol,Protobuf 等
2.5 编解码层 - 二进制编码
-
TLV编码
- Tag:标签(类型)
- Length:长度
- Value:值
2.6 编解码层 - 选型
- 兼容性
- 支持自动增加的字段,而不影响老的服务,提高系统的灵活度
- 通用性
- 支持跨平台、跨语言
- 性能
- 从空间和时间两个维度来考虑,也就是编码后数据大小和编码耗费时长
2.7 协议层
约定的通信协议
2.8 协议层 - 概念
- 特殊结束符
- 一个特殊字符作为每个协议单元结束的表示
- 变长协议
- 以定长加不定长的部分组成,其中定长的部分需要描述不定长的内容长度
2.9 协议层 - 协议构造
LENGTH:数据包大小
HEADER MAGIC:标识版本信息
SEQUENCE NUMBER:表示数据包的 seqID
HEADER SIZE:头部长度
PROTOCOL ID:…
TRANSFORM ID:…
INFO ID:…
PAYLOAD:…
2.10 协议层 - 协议解析
2.11 网络通信层
2.12 网络通信层 - Sockets API
2.13 网络通信层 - 网络库
- 提供易用 API
- 封装底层 Scoket API
- 连接管理和事件分发
- 功能
- 协议支持:tcp、udp 和 uds 等
- 优雅退出(高级功能…)、异常处理等
- 性能
- 应用层 buffer 减少 copy
- 高性能定时器、对象池等
03. 关键指标
3.1 稳定性 - 保障策略
- 熔断:保护调用方,防止被调用的服务出现问题而影响到整个链路
- 限流:保护被调用方,防止大流量把服务压垮
- 超时控制:避免浪费资源在不可用节点上
均会导致 👉 降级
3.2 稳定性 - 请求成功率
负载均衡、重试
3.3 稳定性 - 长尾请求
Backup Request
设计Backup request的关键是要防止服务器繁忙时期的请求风暴。在服务器繁忙时期client容易发生等待超时,倾向于发送backup request。大量的backup request会进一步让服务器更繁忙,于是请求风暴诞生了。防止请求风暴的要点是区分普通超时和风暴期超时。
3.4 稳定性 - 注册中间件
3.5 易用性
-
开箱即用
- 合理的默认参数选项、丰富的文档
-
周边工具
- 生成代码工具、脚手架工具
简单易用的命令行工具…
3.6 扩展性
- Middleware
- Option
- 编解码层
- 协议层
- 网络传输层
- 代码生成工具插件扩展
3.7 观测性
- Log、Metric、Tracing
- 内置观测性服务
3.8 高性能
场景
- 单机多机
- 单连接多连接
- 单/多 client 单/多 server
- 不同大小的请求包
- 不同请求类型:pingpong streaming
目标
- 高吞吐
- 低延迟
手段
- 连接池
- 多路复用
- 高性能编解码协议
- 高性能网络库
04. 企业实践
4.1 整体架构 - Kitex
Kitex Core 核心组件
Kitex Byted 与公司内部基础设施集成
Kitex Tool 代码生成工具
4.2 自研网络库 - 背景
- 原生库无法感知连接状态
- 在使用连接库时,池中存在失效连接
- 原生库存在 goroutine 暴涨的风险
- 一个连接 一个 goroutine 的模式,由于连接利用率低下,存在大量 goroutine 占用调度开销,影响性能
4.3 自研网络库 - Netpoll
- 解决无法感知连接状态问题
- 引入 epoll 主动监听机制
- 解决 goroutine 暴涨风险
4.4 扩展性设计
支持多协议,也支持灵活的自定义协议扩展
4.5 性能优化 - 网络库优化
- 调度优化
- LinkBuffer
- Pool
- 引入内存池和对象池,减少 GC 开销
4.6 性能优化 - 编解码优化
- Codegen
- 预计算并预分配内存,减少内存操作次数,包括内存分配和拷贝
- Inline 减少函数调用次数和不必要的反射操作
- 自研 Go 语言实现的 Thrift IDL 解析和代码生成器
- JIT
- Frugal
4.7 合并部署
微服务过微,传输和序列化开销越来越大
- 中心化的部署调度和流量控制
- 基于共享内存的通信协议
- 定制化的服务发现和连接池实现
碎碎念:八股文选手养成日记,只是一位复制PPT上的文字,其实根本没有进入脑子,如此懒惰作风什么时候能改掉?但其实我也不想烂。只是真的没有时间。
与君共勉。