扩展-收缩是什么
扩展-收缩是兼容性变更的标准手法:先扩展(新增字段或接口,双写并回填历史数据),确认消费方全部迁移后再收缩(删除旧结构)。数据库表结构演进与对外接口版本演进都适用同一套节奏,核心是让新旧版本在发布窗口内可以同时正确运行。
为什么不能一步到位
滚动发布期间旧实例与新实例会同时在线,直接把字段改名会让尚未更新的实例立刻报错。把变更拆成互不阻塞的三步之后,任何时刻新旧代码都能正确读写,回滚也只需要退回上一版本,不必逆转数据。
三个阶段
- 扩展:新增结构,旧结构继续可用,写入同时更新两处
- 迁移:读路径切换到新结构,并校验新旧数据一致性
- 收缩:确认无依赖后删除旧结构与兼容代码
数据库列改名示例
| 阶段 | 操作 | 兼容性要求 |
|---|---|---|
| 扩展 | 新增 new_col 并双写,读兼容新旧两列 | 旧代码不改动照常运行 |
| 迁移 | 回填历史数据,读切到 new_col 并抽样校验 | 旧列保持可读,随时可回退 |
| 收缩 | 停止写旧列,确认无读取方后删除 | 先核对依赖方调用量清零 |
落地要点
| 回退要点 | 每个阶段独立可回退,双写与回填期间监控延迟与数据差异 |
|---|---|
| 完成判据 | 旧结构零读取、零写入,持续观察一个发布周期后再删除 |
| 接口侧 | 字段先加后删,枚举先扩后收,消费方对未知字段保持容忍 |
| 清理登记 | 旧结构的删除时间与责任人登记,到期前复核存量依赖 |
适合什么变更
这套手法适用于所有需要零停机的结构变更:字段改名、字段拆分与合并、类型调整、接口版本替换、枚举值扩展。不适合的是无法双写的场景,例如删除数据或收紧唯一约束,这类变更需要先确认存量数据满足新约束,再单独安排停机窗口或分批处理。
每个阶段都要能独立回退;回填与双写期间必须监控延迟与数据差异,否则偏差往往要等到收缩阶段才暴露,届时已经无法简单回退。