连载中 3/8

从单体到微服务:一次痛苦但值得的架构演进

2026-08-21 · 702 阅读 · 1 评论 · 15 赞

为什么要拆?

我们的核心业务跑在单个 Spring Boot 仓库里,五年积累下来,编译一次要三分钟,改一个字段要动五个模块,部署窗口卡在凌晨两点——团队规模从 3 人涨到 12 人后,协作摩擦大到没法忽视。

不是我拍板要拆的。是某天测试环境再次因为一个无关模块的重启挂掉之后,测试组长在群里发了一句"能不能把 X 模块单独拎出来"。这句话成了导火索。

拆之前没想清楚的事

1. 数据库是最大的债

单体时,所有模块共用一个数据库,外键约束、跨模块 join 是家常便饭。拆服务时,你不可能一夜之间把所有表按服务边界分库——迁移周期可能长达半年。这半年里,多个服务共用同一个库,"微服务"其实只是"分布式单体"。

拆服务的第一步不是写新代码,而是理清数据归属。

2. 团队认知对齐比技术方案更难

架构方案写得很漂亮,但团队成员对"为什么要拆""拆完之后各自负责什么"的理解参差不齐。有人觉得微服务就是"每个模块独立部署",有人理解为"每个服务独立数据库"。认知不对齐会导致实施阶段反复返工。

我的建议:在拆之前,组织一次全员技术会议,把拆分边界、数据归属、团队分工画成一张大图贴到墙上。每天站会都对着这张图说话。

实际怎么拆的

我们用了绞杀者模式(Strangler Fig Pattern):先在网关层做路由分流,新功能直接写到新服务里,旧功能逐步迁移。迁移一个下线一个,保持系统始终可运行。

// 网关路由配置示例
spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service

关键原则:旧接口不改行为,只改路由。让网关做透明代理,对前端无感。

踩过的坑

分布式事务是最痛的。单体时一个 @Transactional 搞定的事,拆完之后跨服务调用要用 Seata 或者最终一致性方案。我们的选择是:核心链路用 Seata AT 模式,非核心链路用消息队列 + 本地事务表做最终一致。

不是所有跨服务操作都需要强一致。想清楚业务能不能容忍短暂不一致,再选方案。

值不值?

拆完三个月回头看:编译时间从三分钟降到四十秒,部署可以按服务独立发布,团队各自迭代互不阻塞。但代价是运维复杂度翻倍——监控、日志、链路追踪全都要上。

如果你团队不到 5 人、业务变化不频繁,单体仍然是最好的架构。微服务不是银弹,是组织规模倒逼出来的工程妥协。

☕
503

10 年全栈工程师 · 503咖啡馆主理人

#架构#微服务#Spring Boot

评论 (5)

端
端到端测试 2026-09-09 22:16
阶段4回归:点赞收藏评论全链路已就绪 ☕
端
端到端测试 2026-09-09 22:10
阶段4测试评论:<script>alert(1)</script>
李
李四 2026-08-30 09:15
"微服务不是银弹,是组织规模倒逼出来的工程妥协"——这句话得裱起来。
c
coffee_dev 2026-08-29 14:51
绞杀者模式确实是最低风险的拆法。但建议补一篇 Seata 的实践,AT 模式踩坑也不少。
张
张三 2026-08-29 10:23
数据归属那块深有感触,我们拆的时候也是卡在这。最后是做了半年的数据双写迁移才彻底分库。

热门推荐

连载中 11/22

主从搭建实操:从零配出一主两从

光讲原理不过瘾?手把手搭一主两从:my.cnf 六个参数、复制账号、GTID、CHANGE REPLICATION SOURCE TO、SHOW REPLICA STATUS 验收,附翻车排查清单。

#MySQL#主从复制#GTID#主从搭建#高可用
2026-05-07 · 10100 阅读 · 0 评论 · 0 赞
连载中 16/22

连接池:HikariCP 参数与连接风暴

连接池不是越大越好:8 核机器配 1000 连接反而更慢的数学原理,HikariCP 四个必调参数,maxLifetime 与 wait_timeout 的隐形陷阱。

#MySQL#连接池#HikariCP#maxLifetime#连接风暴
2026-05-10 · 9872 阅读 · 0 评论 · 0 赞
连载中 4/16

缓存穿透:恶意 ID 打穿 MySQL 的四道防线

请求的数据在缓存和数据库里都不存在时,缓存形同虚设。聊聊参数校验、空值缓存、布隆过滤器、限流熔断四道防线的原理与组合打法。

#Redis#缓存穿透#布隆过滤器#高可用
2026-05-16 · 9293 阅读 · 21 评论 · 287 赞