← 返回题目列表

服务契约如何保证兼容性?

困难 第 20 / 25 题 更新于 2026/10/02
微服务服务契约兼容性API演进
学习 AI 实战项目

简化版

服务契约兼容要求提供方变更后,仍在运行的消费者能够正确解析并保持原业务语义。安全做法是新增优于修改、展开—收缩、多版本共存,并用 Schema 检查、消费者契约测试和生产版本清单守门。

详细版

契约包括字段、类型、必填性、枚举、状态码、分页、幂等和错误语义,不只是 JSON 结构。在客户端允许未知字段时,新增响应字段通常安全;新增必填请求字段、删除响应字段、改变单位或复用 Protobuf 字段号都可能破坏消费者。

先让消费者接受新旧格式,再让提供方双写/双读并监测,确认旧版本无流量且过完消息与缓存窗口后清理。语义大改发布新版本;客户端应容忍未知响应字段和枚举,但不能静默把未知业务状态映射成成功。

完整版教学

一、结构兼容不等于语义兼容

金额字段仍是整数,但从“元”改成“分”,所有解析都能成功却会产生百倍差异。兼容评审必须同时检查名称、单位、时区、默认值、错误和副作用。

易错点:能反序列化只证明语法没坏,不能证明业务还正确。

二、兼容方向

方向含义常见场景
向后兼容新消费者读旧数据消费者先升级、重放
向前兼容旧消费者读新数据提供方先升级
双向兼容两边都成立任意滚动顺序
不兼容需要迁移重大语义变化

团队要按实际发布顺序选择规则,不能只写“保持兼容”。

三、安全扩展规则

新增响应字段时消费者应忽略未知字段;新增请求字段应可选并有明确默认语义。枚举新增值要求 UNKNOWN 分支,否则旧客户端可能崩溃或走错误默认路径。

Protobuf 删除字段后要 reserved 原编号和名称,避免旧字节被未来新字段误解。

四、展开—收缩流程

新增新字段 -> 消费者兼容双读 -> 提供方双写
-> 流量归零/对账 -> 停写旧字段 -> 过窗口 -> 删除

直接 rename 本质上是删除加新增。迁移期间要定义冲突时新旧字段谁优先,并监控两者差异。

五、错误与行为也是契约

把 404 改成 200+空对象、把幂等 PUT 改成重复创建,都会破坏调用方。超时、限流响应、重试提示和分页游标有效期也应文档化并测试。

错误码应稳定且可扩展,客户端对未知码走安全兜底,而不是依赖错误文本匹配。

六、如何自动守门

Schema Registry/OpenAPI diff 检查结构变化,消费者驱动契约验证实际依赖,集成测试验证语义样例。部署门禁读取生产消费者版本矩阵,不能只测试最新客户端。

监控解析失败、未知枚举、旧字段读取量和各版本流量;清理必须有“无人使用”的证据。

客户端生成器本身也要纳入兼容测试,因为生成代码可能比协议规范更严格地拒绝未知字段或缺失值。

文档中的示例和错误响应必须随契约发布,避免机器 Schema 与人工理解长期分叉。

七、常见误区与追问

  • 误区:只新增字段一定安全。 新必填请求字段和未知枚举仍可能破坏旧端。
  • 误区:HTTP 200 就保持了契约。 返回语义和副作用可能已改变。
  • 误区:所有客户端升级后即可删字段。 缓存、消息和离线任务仍可能持有旧数据。
  • 误区:URL v2 自动解决兼容。 仍需双版本迁移和下线。
  • 追问:默认值怎么选? 必须有明确业务含义,并区分“缺失”与真实零值。
  • 追问:如何处理未知枚举? 保留 UNKNOWN,记录告警并安全降级。
  • 追问:何时允许破坏性变更? 新版本并存且完成消费者迁移、观测和撤旧计划时。

八、加强记忆

契约兼容按“结构、语义、错误、副作用”四层检查,再用“先扩展、双轨运行、有证据收缩”迁移。Schema 工具守语法,契约测试守消费者依赖,生产版本与流量守真实生命周期;未知值安全处理,重大变化显式版本化。