Skip to content
返回维护与 LTS

框架迁移

增量替换一个框架为另一个(如 Express→Fastify、Vue 2→3),非大爆炸。

为什么

框架迁移触及每个路由、每个中间件、每个测试 — 是软件中爆炸半径最大的变更。大爆炸迁移意味多周分支啥也不发,坏时(会坏)无法判断 200 个变更哪个导致。增量方式 — 绞杀者无花果模式 — 一次一个端点路由到新框架,旧框架作回退。每个迁移端点各自 PR、部署、回退。迁移期间持续发功能,且可随时停若优先级变。这是无冻结迁移 500 路由应用的方式。

何时使用

当前框架 EOL 或阻塞需要的功能时。绝不为新鲜迁移 — 成本总比估高。

如何做

1. 前面放路由/代理(nginx 或进程内路由)可按路径路由到旧或新
2. 先选最低风险端点(只读、低流量路由)验证方法
3. 在新框架实现该端点;仅该路径路由到新应用
4. 生产双跑:影子流量到新,比较响应,diff 告警
5. 该端点切到新框架;保旧代码即时回退
6. 迁移下一端点;重复。各自 PR + 部署 + 监控窗口
7. 最后端点迁完则完全删旧框架
8. 全程在未迁端点发功能 — 迁移不可冻结产品

示例

# 绞杀者无花果:nginx 按路径路由到旧(Express)或新(Fastify)
location /api/health { proxy_pass http://fastify:3001; }  # 已迁
location /api/      { proxy_pass http://express:3000; }   # 未迁

# 影子流量:记同请求下旧新 diff
app.get('/api/orders', async (req, res) => {
  const [oldRes, newRes] = await Promise.all([
    expressHandler(req), fastifyHandler(req)
  ]);
  if (JSON.stringify(oldRes) !== JSON.stringify(newRes)) {
    logger.error({ oldRes, newRes, path: req.path }, '迁移 diff');
  }
  res.json(oldRes);  // 切换前仍服旧
});

# 切换一个端点(各自 PR + 部署)
# nginx:把 /api/orders -> fastify:3001
# 监控错误率 1 小时;退化则回退 nginx(即时回退)

# 每个迁移端点一个 PR:
# "migrate: /api/health to fastify"
# "migrate: /api/orders to fastify"
# ... 500 个 PR 后完全删 Express。

常见问题

  • ⚠大爆炸迁移分支 — 6 周无功能,坏时无法 bisect 200 个交织变更。
  • ⚠无影子流量 — 切换端点凌晨 3 点发现新框架日期序列化不同。
  • ⚠迁移期间冻结功能 — 业务失耐心半路取消,永远留两框架。

最佳实践

  • ✓用绞杀者无花果模式:代理按路径一次迁一端点 — 各自可部署可回退。
  • ✓切换前每端点影子流量:同请求发旧新,任一响应 diff 告警。
  • ✓迁移期间绝不冻结功能 — 在未迁端点发功能;迁移是后台非停世界事件。