一、改造背景
我们面对的是一个运行了 8 年的核心业务系统——一个基于 Spring MVC + MyBatis 的单体应用,代码总量约 120 万行,模块涵盖订单、支付、库存、用户、营销、报表、后台管理等 9 个业务域。随着业务增长,系统暴露出三个致命问题:
- 部署瓶颈:300+ 开发人员共用一条主线,每周仅能发布 2 次,任何模块的回归验证都牵动整个应用
- 性能短板:一个报表查询拖垮整个订单服务的现象频繁发生,模块间无隔离
- 技术债堆积:最早的代码还残留着 JDK 7 的写法,新功能不得不在旧的全局状态上打补丁
改造目标是在不中断线上业务的前提下,将单体应用逐步拆分为 12 个独立微服务。
二、拆分策略:绞杀者模式(Strangler Fig Pattern)
我们选择绞杀者模式而非"大爆炸"重写——新功能在新服务中构建,旧功能逐步迁移,单体应用逐渐"枯萎"直至下线。
2.1 拆分原则

2.2 目标架构

三、实施路线图(6 个月)
第一阶段:基础设施铺设(第 1-4 周)
目标:在新旧系统之间建立安全的通信桥梁,为后续逐步迁移打好基础。
关键动作:
- 部署 API Gateway(Kong),配置路由规则:默认流量仍指向单体应用,特定 URI 前缀路由到新微服务
- 搭建服务注册中心(Nacos),所有新服务启动时自动注册
- 建立 CI/CD 流水线:每个微服务独立代码仓库 + 独立构建 + 独立部署,实现从提交到上线的全自动化
- 统一配置管理:将单体应用的配置文件迁移到 Nacos Config,实现动态刷新

第二阶段:先行试点——用户服务(第 5-8 周)
- 目标:选择一个改动最少、依赖最少的模块作为试点,验证整套方案。
- 选择用户服务作为第一个迁移目标,原因:
- 业务逻辑相对独立,外部依赖少
- 接口调用量大但逻辑简单(主要是 CRUD)
- 变更影响面可控,即使出问题也容易回滚

第三阶段:核心链路迁移(第 9-20 周)
- 用户服务验证成功后,按业务影响从小到大的顺序推进:

- 分布式事务处理:
- 最棘手的问题是订单创建 → 库存扣减 → 支付扣款的跨服务事务一致性。我们采用 Seata AT 模式 解决:

第四阶段:收尾与下线(第 21-24 周)
- 逐一验证旧单体应用中各模块流量已降为零
- 保留旧系统作为"只读归档"一个月
- 下线旧系统,回收服务器资源
- 输出完整的迁移文档和应急手册
四、关键技术决策复盘
4.1 为什么选 Nacos 而不是 Eureka/Consul?
Nacos 同时提供服务发现和配置管理,且对国内的 Dubbo/Spring Cloud Alibaba 生态支持最完善。团队现有技术栈以阿里中间件为主,选 Nacos 减少学习成本。
4.2 为什么用 Seata 而不是 Saga 编排?
Saga 编排适合长流程(秒杀、审批流),但我们面对的核心场景是 2-3 个服务的短事务(订单→库存→支付),Seata AT 模式对业务代码侵入最小,只需在方法上加 @GlobalTransactional 注解。
4.3 跨服务查询怎么办?
拆服务最大的副作用是"以前一个 SQL 搞定的事现在要调 N 个接口"。我们遵循两条规则:
- 能冗余就冗余:用户服务将常用字段(昵称、头像)下发给订单服务本地冗余,通过消息队列同步变更
- 不能冗余就用 BFF:搭建 Backend For Frontend 聚合层,专门为前端组装跨服务数据,避免前端直接调多个微服务
五、效果与收益
