本节摘要:遗留系统最难的一类不是"烂到要重写",而是"半好半坏"——迁了半年还剩四百万存量单,拔不掉、养不起。绞杀者模式(Strangler Fig)给出的答案是不迁:让新系统像藤一样沿着场景逐步接管,老系统原地萎缩直至只剩一具数据躯壳。本节讲绞杀的三个部件——路由切面、事件拦截、数据一致性策略——以及青柚商城半年绞杀实录里被验证的四条收尾判据。
青柚商城的老订单系统是 2.0 时代的产物:核心下单链路还算稳,但促销规则硬编码、状态机混乱、没人敢动核心表。新交易上下文上线时,迁移动议的第一版计划是"数据迁移"——写迁移脚本把四百万存量单搬进新库。计划评审十分钟就被财务否了:存量单挂着财务对账与税务口径,任何"搬家式"的数据变更都要走审计留痕,迁移脚本做不到逐单可举证。 再算人力账:写迁移、核数据、修差异的预估是三个人半年,而这半年里新需求一个不能停。
绞杀者模式换了一个问题:不是"怎么把老系统搬走",而是"怎么让新系统逐步接管老系统的职责,直到老系统只剩数据"。名字来自绞杀无花果树:种子落在宿主树上,沿枝干生长,多年后宿主只剩树干形状的空壳,撑起整棵树的是藤。落到系统上:新老并存,按场景一片片接管流量,老代码不删但不再生长。
部件一:路由切面。 在老系统入口立一个路由层(网关规则或拦截器都行),按"场景"切流:新单走新系统,查询老单走老系统,特定营销活动的新单也走新系统。路由的粒度必须是业务场景而不是 URL 或表——场景是谈判单位,产品与运营听得懂"退货申请已切换新流程",听不懂"order-api 的 v2 路由已启用"。路由层同时是回滚开关:新系统出问题,把场景切回去,分钟级恢复。
部件二:事件拦截。 绞杀期最险的暗礁是双头写入:老系统还活着,它自己的代码还在改那几张表(批量运维、夜间任务、半残余功能)。解决方案是在老库上装变更捕获——要么触发器、要么日志解析——把老系统的每次数据变更翻译成事件广播给新系统。这样不管谁写的,两边数据都动。注意方向:拦截的是"老系统还在发生的事实",不是让新系统去老库轮询——轮询把新系统与老库的 schema 绑死,绞杀又多了一根藤缠着宿主。
部件三:防腐层反向部署。 2.4 的防腐层防的是外部模型渗入;绞杀期它多了个使命:把老系统的模型翻译成新上下文的语言。新系统看老单,经防腐层转成新模型的只读视图;老系统回调新逻辑,也经防腐层送进命令侧。老系统的字段名、状态码、口径怪癖,只允许活在防腐层一个类里——半年后老系统退役,删掉防腐层,全部残留一次清零。

必须单独立一节讲双写,因为它埋葬过的绞杀项目比任何技术难题都多。所谓双写,指"过渡期让新系统把数据同时写进老库,保持两边一致"。听上去稳妥,实际上是个结构陷阱:两个系统各自的事务无法覆盖对方——新库提交成功、老库写失败(或反过来),数据从这一刻起分叉,而对账发现分叉时,往往已经过了修复窗口。青柚商城评审时否掉的正是这个方案,替代品是上面的事件拦截:老库永远只由老系统写,新库只由新系统写,跨库一致靠捕获事件的最终一致。事实广播天然幂等可重放,比双写的"恰好都成功"脆弱假设结实得多。判据一句话:绞杀期允许短暂的数据时差,不允许双向写路径。
绞杀最常见的烂尾不是失败,是"永远过渡"——两年后新老系统还在并存,谁也不敢关老的。青柚用四条判据定义退场,全部满足才动手关:
四条判据的价值在于它们都可观测——退场靠证据不靠勇气。满足后老库转只读档案(保留审计追溯),删路由、删拦截、删防腐层。青柚实际执行到第四个月已满足前三条,等财务季度对账走完,第六个月正式退役,比"数据迁移方案"的预估省了整整三个月,且全程无审计风险。
绞杀是场持续数月的双系统共存期,技术与业务之间最好有三条白纸黑字的约定,青柚的版本可以直接借用。约定一:新需求一律只做进新系统——哪怕要的功能老系统也"顺手就能加"。这条约定是绞杀成立的前提:老系统一旦还在长新功能,"零业务变更"的退场判据永远无法满足。约定二:共存期的口径以老系统为准——报表、对账、客服查询在切换完成前都按老口径出数,新系统的差异记入差异台账逐条核对,而不是反过来。这条约定保护的是信任:数据差异一旦让业务方自己发现,绞杀的信誉就破产了。约定三:每个场景切换前给业务方一次演练窗口——客服与运营要在灰度环境把新场景完整跑一遍再切流。绞杀砍掉的是迁移脚本,砍不掉的是变更管理,而变更管理的主语从来是业务方。
何时该放弃绞杀。绞杀不是万能答案,两种局面应该果断换路线。其一是老系统仍在高频生长:业务方天天往里加功能,说明它的领域还很活跃,绞杀等于追着一列行驶中的火车装新车厢——这时该谈的可能是让老系统先把核心域让出来(按 2.3 重新划分),而不是整体接管。其二是老系统已无业务逻辑只剩数据查询:连场景都没有可接管的,做一次只读化的数据归档加一个查询接口,成本远低于搭路由、装拦截的整套绞杀工程。绞杀的适用窗口是"老系统冻结生长、新系统逐步承接"的中间态,窗口两头都不适用。
最后一块骨头:跨上下文的一致性。没有共同事务的三个上下文怎么合作?6.4 Saga。