SuperAPI AI 工具集

arch-strangler-fig

编程与开发

查看项目

更新于 10-16 16:26

技能介绍

用途

该技能用于以增量方式迁移遗留系统,而不是一次性重写。它适用于以下场景:把单体应用迁移到微服务(可能持续数月或数年);替换一个过于关键、无法为其重写而停机的遗留系统;分解一个内部机制理解不足的系统——每次迁移一个行为,并在迁移过程中重建对系统的理解;以及当有人提出「大爆炸式重写」时,作为更安全的替代方案。

主要能力与核心理念

一句话概括:把遗留系统包在一个门面(facade)里。将新功能以及逐步重写的既有功能,路由到门面之后的新服务上。当所有功能都完成迁移后,遗留系统就被「绞杀」,可以退役。

具体纪律步骤包括:

  • 选取接缝。找出可以在清晰边界(HTTP 端点、消息处理器、定时任务)被拦截的一块功能。
  • 构建门面。用一个代理 / 网关 / 调度器为该功能路由流量,起初全部流量仍走向遗留系统。
  • 构建替代实现。新服务为该功能实现相同的外部契约。
  • 切换百分比。把 1% / 10% / 100% 的流量导向新服务,并对比输出(影子流量、并行运行)。
  • 停用。当某功能的所有流量都在新服务上运行后,删除遗留代码路径。
  • 重复。转向下一块功能。

它常与防腐层(ACL)配对使用:遗留系统的模型几乎总与新服务不同,ACL 在两者之间做转换,使新服务不会继承遗留系统的数据形态或词汇。ACL 模式可参见 ddd-context-mapping。

关键点:每个迁移步骤都必须能够独立发布。如果某一步需要「重写 6 个月后再切换」,那构建的是并行系统,而不是绞杀式迁移。真正的绞杀式迁移每周都会发布小的、已迁移的功能切片。

使用方式

常见的门面实现方式包括:API 网关(Kong、Istio、自定义代理)按路径 / 请求头路由;数据库视图抽象读操作来自旧库还是新库;事件桥用于事件形态的系统——新旧服务消费相同事件,并按特性开关路由;以及针对嵌入式遗留系统的代码内自定义调度器(一个协调类决定「走旧路径还是新路径」)。

迁移期间的模式处理:新服务通常拥有自己的数据,而遗留系统仍持有规范存储。可选策略有:读旧、写双库(新服务暂时从遗留系统读取,写入同时落到两个存储;当新存储成为规范来源后,翻转读取方向);或从遗留系统复制到新系统(变更数据捕获 CDC 将遗留系统的变更推送到新存储,新服务只从新存储读取)。

决策启发式:始终从最简单的一块功能切片开始,先证明迁移机制可行,而不必一开始就押注风险最高的部分;在正式切换前先并行运行新旧系统一段时间,对比结果并调查差异;写下一个「杀死遗留系统」的明确日期和里程碑计划,否则迁移会永远进行下去,两套系统要维护 5 年;停用是工作的一部分而非事后再补——在遗留代码被删除之前,迁移都不算完成。

适用场景与限制

适用场景如前所述,包括单体到微服务的渐进迁移、无法停机重写的关键遗留系统替换、理解不足的系统的逐行为迁移,以及替代大爆炸重写的更安全方案。

不适用场景:遗留系统很小,直接重写确实更短、风险更低;功能纠缠严重到画不出干净的门面——此时应先做一次暴露接缝的重构;或者把绞杀当作一个没人打算完成的无限期迁移的掩护——遗留系统永远不会消失。

反模式包括:伪装成绞杀的大爆炸重写(声称使用绞杀模式,实际计划是「并行重写 18 个月后切换」,那只是加了包装的重写);无限期的绞杀(新服务多年只处理 30% 流量,无人完成迁移,两套系统被永久维护);没有 ACL 的绞杀(新服务逐字继承遗留系统的数据形态,坏设计传播到替代品中);按技术层切片(迁移「数据库」或「API」而不迁移连贯的功能,会产生半迁移的烂摊子)。

相关资料

相关技能包括:ddd-context-mapping(防腐层是经典配套模式)、arch-microservices(绞杀是单体到微服务的标准路径)、arch-event-driven(新旧系统之间的桥接常通过事件实现)、arch-fitness-functions(自动化检查「遗留代码路径是否真的在被使用」)。

参考来源:Martin Fowler 的「StranglerFigApplication」(2004 年文章,原始阐述);Sam Newman 的《Monolith to Microservices》(O'Reilly,有完整章节讲绞杀模式迁移)。