RocksDB源码-0x0D-协议设计TLV
说起协议设计,这个话题我以前没有过深的思考。协议的方案选择很多,选哪个从来不是简单的喜好,一般是多个维度比较取舍的结果。
1 考虑的维度
比如说我现在要设计协议,就要先问上自己几个问题
- 是不是需要跨语言
- 是不是需要长期存储
- 是不是需要前向/后向兼容
- 是不是需要高频访问的对性能敏感的
- 是不是需要schema
- 是不是需要人类可读的
2 不同的方案
- 2.1 TLV 纯二进制+自定义编码
- 代表
- RocksDB VersionEdit
- LevelDB
- SQLite
- MySQL redo log
- Kafka log
- 特点
- 自定义write format
- TLV或者TVL的变体
- 优点
- 极致性能
- 极致空间效率
- 完全可控
- 最强前向兼容
- 缺点
- 人肉维护
- 开发成本高
- 容易出bug
- 几乎没有工具链
- 场景
- 底层系统
- 内部协议
- 长期存储
- 热路径
- 代表
- 2.2 接口定义语言IDL驱动的二进制协议
- 代表
- Protobuf
- Thrift
- Avro
- FlatBuffers
- 特点
- 有Schema
- 自动生成代码
- 多语言支持
- 优点
- 开发效率高
- 跨语言
- 工具丰富
- 缺点
- write format不完全可控
- 兼容性有规则限制
- 依赖runtime
- 热路径性能不如手写TLV
- 场景
- RPC
- 服务通信
- 中间层存储
- 团队协作
- 代表
- 2.3 自描述数据格式
- 代表
- JSON
- XML
- YAML
- 特点
- 文本
- 自描述
- 人类可读
- 优点
- 调试友好
- 灵活
- 无schema也能用
- 缺点
- 慢
- 大
- 类型弱
- 歧义多
- 场景
- 配置
- 控制面
- 低频交互
- 代表
- 2.4 列式/批量格式
- 代表
- Parquet
- ORC
- Arrow
- 特点
- 面向列
- schema强
- 批处理
- 场景
- 分析
- OLAP
- 离线
- 代表
3 TLV
RocksDB这种底层的存储引擎,从空间/性能/兼容性/数据长期存储,这几个方面,协议设计肯定选择TLV。什么是TLV
1 | |
短短几行代码就是一个tag的处理,每添加或者扩展一个tag,无非就是多一个switch分支的事情
上面代码最重要的两个函数
- GetVarint32
- GetLengthPrefixedSlice
这里面体现的就是RocksDB的编解码 RocksDB源码-0x0E-编解码
4 怎么做的前向兼容
4.1 不认识的tag预处理
1 | |
4.2 配合主循环的default分支专门处理不认识的tag
前提是必须显式有L(length)的TVL,处理方式就是跳过不要
1 | |
RocksDB源码-0x0D-协议设计TLV
https://bannirui.github.io/2026/02/04/RocksDB/RocksDB源码-0x0D-协议设计TLV/