Protocol Buffers

语言无关的接口与数据序列化格式,通过字段编号保证向前向后兼容:新增字段用新编号,废弃字段保留编号与名称(reserved),删除编号不复用。

Protocol Buffers 是什么

Protocol Buffers(Protobuf)是语言无关的接口定义与序列化格式:用 .proto 描述消息结构与服务方法,工具链生成各语言的代码,二进制编码比 JSON 更紧凑、解析更快。它的兼容性来自字段编号而非字段名——双方按编号解析,因此新增字段必须用新编号,废弃字段要把编号与名称放进 reserved 声明,永久禁止复用。掌握这条规则,就能在不停机、不升级全部调用方的前提下演进消息结构。

基本信息

定义文件.proto 描述消息、枚举与服务方法
编码特点二进制、字段编号定位,体积与解析开销低于文本格式
兼容机制按编号解析,字段名仅用于生成代码
演进规则新增用新编号;废弃用 reserved 冻结编号与名称
生态常与 gRPC 配合使用,也可单独用于消息与文件存储

典型使用场景

  • 服务间通信:多语言服务之间用同一份 .proto 生成代码,避免手写解析
  • 消息与事件:作为 Kafka 等消息队列的载荷格式,配合模式注册中心治理
  • 移动端接口:体积与解析开销敏感的场景,优于文本格式
  • 数据落盘:结构化数据长期保存,靠编号演进保证历史数据可读
  • 配置下发:把结构化配置二进制化,减少传输体积
  • 跨团队契约:接口定义集中维护,变更走评审与兼容检查

定义与演进示例

定义与演进示例
syntax = "proto3";

message Order {
  string id = 1;             // 编号 1 一旦发布不可更改含义
  int64 total_cents = 2;     // 金额用整数分,避免浮点误差
  reserved 3;                // 已废弃字段的编号,永久保留
  reserved "legacy_no";      // 已废弃字段的名称,防止被重新启用
  repeated Item items = 4;   // 新增字段用新编号,旧客户端忽略即可
  string channel = 5;        // 可选字段默认值需与业务约定区分「未设置」
}

兼容规则

操作兼容性说明
新增字段(新编号)兼容旧数据解析时该字段取默认值
删除字段需先废弃保留编号与名称到 reserved,禁止复用编号
修改类型多为破坏如 int32 改 string 会导致解析错乱
字段改名二进制兼容不影响解析,但会影响生成代码与文档
枚举新增值需容忍未知值旧客户端遇到未知枚举值需要有默认处理分支
兼容规则要写进团队规范并放进流水线:用 lint 与兼容检查工具阻止复用编号、改类型等高风险改动进入主干。
proto3 中基本类型无法区分「未设置」与「默认值」:业务需要区分时使用可选字段或包装类型,否则 0 与「未填」会被混为一谈。

易错点

  • 复用已废弃字段编号:新旧数据解析互相污染,出现难以复现的字段错乱
  • 把可选字段当成必填使用:旧客户端不发送该字段时被拒,兼容性被破坏
  • 直接改字段类型:二进制编码长度与语义不匹配,解析静默出错
  • 废弃字段不写 reserved:半年后有人重新启用该编号,历史数据被误读
  • 只改 .proto 不同步更新兼容检查:问题在联调阶段才暴露,回滚成本高

数据来源与参考

  • Protocol Buffers 语言指南(protobuf.dev)
  • Google API 设计指南
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌