跳到主要内容

兼容、迁移、灰度与退出条件

系统迁移需要在新旧版本并存时维持契约,用分批灰度控制风险,并以可验证的退出条件结束双轨运行。

1. 先列出所有兼容面

迁移影响的不只有 HTTP API。完整清单通常包括:

  • 请求、响应、错误码和认证;
  • 事件 schema、顺序和投递语义;
  • 数据库 schema、数据格式和索引;
  • 配置、开关和权限;
  • SDK、批处理、报表和人工操作;
  • 运行指标、告警和审计字段。

结构兼容也不等于行为兼容。接口仍返回相同字段,但金额舍入、默认排序或重试语义发生变化,调用方依然可能出错。

为每个兼容面登记所有者、消费者、版本和计划下线时间。无法列出消费者时,先增加访问日志或注册机制,再开始破坏性变更。

2. 使用扩展、迁移、收缩

数据库和接口变更可以分成三个阶段:

  1. 扩展:新版本增加字段或能力,同时兼容旧读写;
  2. 迁移:回填历史数据,逐批切换调用方和流量;
  3. 收缩:确认旧路径无使用后,删除旧字段和兼容逻辑。

例如重命名数据库列时,先新增新列并让应用兼容双读,确定唯一写入策略后回填,再切换所有读取方,最后删除旧列。直接 rename 会让滚动发布中的旧实例失效。

双写要定义部分失败和权威数据源。能通过数据库事务、outbox 或 CDC 完成的同步,不要依赖两次无保护的远程写入。

3. 迁移计划是一组状态

迁移对象可以是租户、数据分区、调用方或业务流程。为每一批记录状态:

待迁移 → 回填中 → 增量追平 → 影子验证 → 灰度 → 已切换 → 已关闭回退

状态转换要幂等,并保存开始时间、数据范围、校验结果和操作者。中断后可以从已确认位置继续,避免重新扫描全部数据。

批次大小由故障影响、处理时间和回退能力决定。先迁移内部或低风险对象,再覆盖高价值流量;每一批结束后留出观察窗口。

4. 灰度规则保持稳定可解释

灰度可以按租户、地域、账号哈希、客户端版本或业务类型分桶。一个对象在同一阶段应稳定命中相同版本,避免状态在新旧实现间来回跳转。

每个阶段预先定义:

  • 流量比例和持续时间;
  • 技术与业务指标;
  • 最小样本量;
  • 继续、暂停和回退阈值;
  • 当班负责人和沟通渠道。

错误率、P99 和资源只是技术信号。订单成功、金额差异、人工工单和客户投诉等业务指标同样需要进入判断。

5. 影子和双读用于比较

无副作用查询可以使用影子流量或双读:主路径继续返回旧结果,新实现同步计算,系统比较结果和延迟。

比较器要忽略随机 ID、时间戳和无语义排序等可接受差异,并将真正差异按原因归类。差异率为零也不能证明写入安全;并发、事务和下游副作用仍要通过真实小流量验证。

影子请求要有独立标识,禁止触发通知、扣费或消息发布。它产生的负载也要计入容量,避免验证过程影响正式流量。

6. 回滚与向前修复分开设计

代码可以回滚,数据格式和外部事件未必可逆。迁移前需要分别回答:

  • 路由如何切回;
  • 新版本写入的数据旧版本能否读取;
  • 已发送事件由谁继续处理;
  • 正在进行的长流程如何归属;
  • 回滚会不会重复业务副作用。

可逆变更准备自动回滚;数据库已经完成不可逆转换时,通常采用向前修复,并通过功能开关关闭风险路径。两类方案的权限、耗时和验证步骤都应演练。

回滚阈值要在上线前确定。故障发生后临时讨论“是否已经足够严重”,会浪费最关键的恢复时间。

7. 退出条件结束兼容期

迁移完成需要同时满足:

  • 目标对象全部进入新路径;
  • 技术和业务指标稳定达到目标;
  • 数据回填完成,差异已清零或有批准解释;
  • 没有旧接口、字段、事件或客户端流量;
  • 运行责任、文档和告警已经转交;
  • 旧资源、权限、同步任务和开关已删除;
  • 回退窗口已按约定关闭。

每项条件都要有证据和负责人。“观察一段时间没问题”需要改成明确周期、指标和查询结果。

删除旧路径本身也走评审和灰度。先关入口并观察,再删除数据和基础设施,可以避免漏掉低频消费者。

8. 迁移完成后复盘收益

迁移结束后比较原有基线:发布速度、故障范围、延迟、成本和团队协作是否改善。目标未达到时,检查假设、边界和执行过程,决定继续优化、停止投入或恢复更简单的结构。

把兼容适配、临时同步和迁移开关留在代码里,会形成新的技术债。退出清单完成后再关闭项目,能够把人力从永久双轨维护中释放出来。

9. 面试题

9.1 一个核心接口怎样做到无停机迁移并保留回退能力

出现公司:阿里巴巴、字节跳动

考察重点

  • API、事件、数据和行为兼容。
  • 分批状态、影子验证和灰度阈值。
  • 数据回退、向前修复与退出条件。

相关内容:第 1 节“先列出所有兼容面”至第 8 节“迁移完成后复盘收益”。

参考回答

我会先列出 API、事件、数据、配置和所有消费者,采用扩展、迁移、收缩:新旧版本先同时可用,完成数据回填和调用方切换,确认旧流量归零后再删除兼容。每个租户或分区有可恢复的迁移状态,先做影子比较,再按稳定分桶逐级灰度。

每一阶段预先定义错误率、尾延迟、业务结果、样本量和回退阈值。路由回退与数据恢复分开设计;不可逆数据变化准备向前修复。最终以全量切换、数据校验、稳定观察期、旧消费者归零、责任转交和旧资源删除作为退出条件,再比较迁移前后的业务和工程指标。