第四章:编码与演化
1. 为什么要关注编码与演化
分布式系统中,数据总在跨进程、跨机器、跨时间流动。只要存在版本不一致,就会出现兼容性问题。编码格式与模式演化规则决定了系统能否平滑升级。
2. 数据编码格式
2.1 语言私有序列化
如 Java Serializable、Python pickle,开发便利但跨语言差、安全风险高、版本演化能力弱,不适合作为长期公共协议。
2.2 文本格式
JSON、XML、CSV 可读性高、生态成熟,但存在体积大、类型表达不精确、二进制字段处理笨重等问题。
2.3 二进制变体
MessagePack、BSON 等在体积与性能上优于纯文本,但若仍携带字段名,压缩收益有限。
3. 基于模式的二进制协议
3.1 Thrift 与 Protocol Buffers
两者通过 IDL 定义 schema,运行时以字段编号编码,兼顾紧凑性与可演化性。
3.1.1 演化规则
- 新增字段应为可选或具备默认值。
- 删除字段后不应复用旧字段编号。
- 类型变更需保证兼容转换路径。
3.2 Avro
Avro 不在数据中写字段编号,依赖写入 schema 与读取 schema 的解析规则完成兼容。
3.2.1 适用场景
- 大数据离线文件(schema 写在文件头)。
- 配合
Schema Registry的事件流。 - 动态语言与数据导出场景。
3.3 Schema 的工程价值
- 降低协议歧义。
- 支撑滚动升级。
- 为自动校验、代码生成与治理平台提供基础。
4. 数据流与兼容性
4.1 经由数据库的数据流
数据库里的数据生命周期往往长于应用代码版本。滚动升级期间,旧代码可能读新数据,新代码也要读旧数据,因此通常要求同时满足前向与后向兼容。
4.2 经由服务的数据流
4.2.1 REST 与 RPC
REST:基于HTTP资源语义,调试友好,演化成本低。RPC:性能更高,但不能假装“远程调用等价本地调用”,必须显式处理超时、重试、幂等与部分失败。
4.2.2 RPC 设计要点
- 区分超时、失败与未知结果。
- 写接口优先幂等语义。
- 用版本化协议与兼容字段做灰度发布。
4.3 经由消息系统的数据流
消息代理在发送者和消费者之间提供缓冲与解耦,适合异步架构与削峰填谷。
4.3.1 消息格式约束
Broker 通常只处理字节,不理解业务 schema。若无统一协议治理,版本漂移会快速累积为兼容性事故。
4.3.2 Actor 模型
分布式 Actor(如 Akka)把并发与消息传递统一,但跨版本部署时同样依赖稳定消息协议。
5. 落地建议
- 对外协议优先使用“可演化 schema + 版本治理”。
- 为事件流建立 schema 注册与兼容检查。
- 升级流程采用“先兼容、后切换、再清理”的三阶段策略。