1646 字
约 5 分钟
8
S02-A02 · API 与 RPC 治理:网关、契约、版本与灰度

适用读者:要对"接口改了不炸调用方"负责的人。
前置:S02-B09(HTTP 与 RPC)、S02-B10(OpenAPI 工具化)。
版本基线:OpenAPI 3.1、gRPC/protobuf 3.x、nginx/网关(示例)。
覆盖旧文:—(E 驱动)
覆盖扩展:E-S02-026(网关限流/熔断/灰度)+ 契约与版本策略。
上一篇:S02-A01 · 实时通信架构选型
下一篇:S03 · 数据结构与算法(下一系列)。


1. 一句话结论

接口治理的核心不是"写文档",而是"让契约成为唯一事实来源,并给变更设闸门"。

要素 作用
契约单一来源(OpenAPI / .proto 进仓库) 服务端、客户端、文档、测试都从它生成
兼容性规则 规定什么能改、什么不能改
网关 统一鉴权、限流、路由、灰度
变更闸门 CI 检查破坏性变更,不允许"悄悄改"

2. 契约:从"文档"到"唯一事实来源"

阶段 表现 问题
L0 接口靠口头/IM 沟通 每人都有一份"记忆中的契约"
L1 手写文档(Wiki) 三天后过期
L2 契约文件进仓库(OpenAPI/proto) 需要 CI 校验与代码生成
L3 契约驱动:代码从契约生成 + CI 阻断破坏性变更 治理闭环

判据:"能不能从契约自动生成客户端 SDK / 测试用例?" 能 → 你到 L2 以上了。


3. 兼容性规则表(最容易出事的地方)

3.1 HTTP/JSON

变更 兼容性 说明
新增可选字段 ✅ 向后兼容 老客户端忽略即可
新增必填字段(请求) ❌ 破坏 老客户端不传 → 服务端拒
删除字段 ❌ 破坏 老客户端仍在读
字段改名 ❌ 破坏 视同删除 + 新增
类型变更(int → string) ❌ 破坏 反序列化失败
收紧校验(如长度上限变小) ⚠️ 潜在破坏 已有合法数据可能超限
枚举新增值 ⚠️ 视客户端实现 老客户端可能不认识新值

3.2 Protobuf(更强约束)

变更 兼容性
新增字段(新编号) ✅
删除字段 ✅ 前提:把编号 reserved,防止被复用
改字段编号 ❌ 破坏(数据错位)
改字段类型(int32 → int64) ⚠️ 部分兼容(varint 同构可兼容,反之不行)
改字段名 ✅(proto 用编号传输)

铁律:字段编号一旦发布就不能复用。删字段必须 reserved 5; 断掉后人复用的可能。


4. 三种破坏性变更的处置

处置 做法 代价 适用
并行版本 /v2/... 或 package v2 维护双份、双跑期 大改、外部客户
兼容扩展 加字段 + 服务端兼容旧值 小 绝大多数场景
灰度 + 强推 内部服务强制升级(无外部客户) 协调成本 内部 RPC、可控客户端

判据:调用方能不能被你强制升级? 能 → 强推;不能(浏览器、第三方)→ 并行版本。


5. 网关的职责边界

职责 放网关 放服务
鉴权(token 校验) ✅ —
限流(按 key/租户) ✅ 精细限流需服务配合
路由与灰度(按 header/用户) ✅ —
协议转换(REST ↔ gRPC) ✅ —
熔断/重试 ✅(粗粒度) ✅(业务语义重试)
业务校验 ❌ ✅
事务 ❌ ✅

常见错误:把业务校验放网关 → 网关变成"又一个业务系统",无法独立演进。


6. 灰度与回滚

① 契约变更 → CI 校验(破坏性变更阻断)
② 服务端先上(向后兼容版本)
③ 灰度:1% → 10% → 50% → 100%(按用户/租户/地域)
④ 观测:错误率、P99、业务成功率
⑤ 回滚:开关/路由规则切回旧版本(≤ 1 分钟)
判定指标 阈值(示例)
5xx 率 上升 > 0.5 个百分点 → 回滚
P99 延迟 上升 > 30% → 回滚
业务成功率 下降 > 1% → 回滚

顺序铁律:先上服务端,后上客户端(服务端兼容旧客户端;反过来必炸)。


7. 观测与契约漂移检测

检查 手段
实现是否符合契约 契约测试(schemathesis / Dredd)
是否存在未文档化字段 抓包对比契约(漂移检测)
客户端是否用了未定义字段 网关日志字段级统计
版本使用分布 按 Accept-Version 统计(决定旧版本下线时间)

8. 交付物

交付物 内容
契约仓库结构 api/openapi/*.yaml 或 proto/,含 CI 校验
兼容性检查 工具配置(如 openapi-diff、buf breaking)
版本演进表 版本 / 状态(active/deprecated/retired)/ 下线计划
灰度方案 分组规则、观测指标、回滚开关位置
ADR 为何用并行版本而非兼容扩展(或反之)

9. 自测(架构师版)

  1. 为什么"新增必填字段"是破坏性变更,而"新增可选字段"不是?
  2. Protobuf 删字段为什么必须 reserved?
  3. 什么情况下可以"强推"而不是并行版本?
  4. 网关为什么不该做业务校验与事务?
  5. 灰度时你最先看哪个指标?为什么不是"平均延迟"?

10. 系列收尾

S02 到此结束(16 篇)。下一系列 S03 · 数据结构与算法(186 张旧卡),从复杂度与基础结构开始,承接 B02/B04 的"进程与可靠传输"之后所需的算法基础。

S02 的验收报告见 ../acceptance.md。


本篇属于系列《S02 · 计算机与网络基础》,架构师层第 2 篇。扩展点 E-S02-026。

S02-A02 · API 与 RPC 治理:网关、契约、版本与灰度
https://www.clxhxhhr.top/posts/5196/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。