尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
项目从1个模块拆成8个微服务,然后我又合了回去
摘要我们项目从 1 个 SpringBoot 单体拆成了 8 个微服务用了半年。然后在接下来的一年里分布式事务、调试地狱、运维成本翻倍团队被折磨得够呛。最后我做了一个决定合回去。不是退回到大泥球而是用模块化单体的方式重新组织代码。这篇文章复盘了整个过程——当初为什么拆、踩了什么坑、为什么合、合回去之后怎么做的。事情的开始我们为什么要拆2023 年底我加入了一个做 SaaS 的项目。那时候项目还小一个 SpringBoot 应用跑得好好的用户量 5 万出头QPS 不到 200。有一天老板说“我们要拆微服务。”我当时第一反应是好呀拆了更专业大家都在拆微服务不拆就落伍了。拆的理由听起来也挺合理的用户量在涨马上到 10 万了以后肯定要扩团队从 3 个人扩到了 8 个一个代码仓库 merge 经常冲突路演模块的慢查询偶尔拖慢整个应用如果能独立部署就好了现在回头看这三个理由里只有第二个勉强站得住脚。用户量 10 万是什么概念一个单体扛百万 DAU 都没问题。至于慢查询——加个索引的事非要动架构。但我们当时就是拆了。大家都觉得微服务是现代软件的标配不拆显得不够架构师。2026 年的面试风向已经变了。gankinterview.cn 的一篇文章提到面试官现在问的是你的业务量级真的需要微服务吗而不是你用过微服务吗1。可惜两年前没人这么问我。拆分过程8 个微服务是怎么诞生的我们照着 DDD 画了一圈领域边界最后定了 8 个服务投资者服务 (investor-service) 路演服务 (roadshow-service) 企业服务 (company-service) 互动服务 (interaction-service) 通知服务 (notification-service) 数据服务 (data-service) 资料服务 (material-service) 网关服务 (gateway-service)边界画得挺清晰的。每个服务有自己的数据库用 Feign 做 RPC 调用Nacos 做注册中心和配置中心Sentinel 做限流熔断SkyWalking 做链路追踪。技术栈选得中规中矩没什么花活spring:cloud:nacos:discovery:server-addr:nacos:8848sentinel:transport:dashboard:sentinel:8080拆的过程大概花了三个月。改代码、配 CI/CD、写 Dockerfile、调 K8s 部署加班是常态但大家干劲十足——毕竟在做架构。上线那天8 个服务在 K8s 里整整齐齐跑起来Grafana 面板上每一个 Pod 的绿色指示灯看着确实爽。蜜月期之后问题一个接一个爽了大概两个月。分布式事务的噩梦第一个大坑是分布式事务。上市公司预约路演的流程原来是一个 Service 方法里搞定校验企业信息 → 创建路演场次 → 开通互动提问 → 发通知。数据库事务一包要么全成、要么全滚。拆了之后变成roadshow-service → company-service校验企业→ interaction-service开通互动→ notification-service发通知。四个服务四个数据库跨服务调一个 RPC 就断一个数据库连接。Spring 的Transactional彻底废了。我们试过 Seata 的 AT 模式GlobalTransactionalpublicRoadshowcreateRoadshow(RoadshowDTOdto){companyClient.verifyCompany(dto.getCompanyId());interactionClient.enableQA(dto.getRoadshowId());roadshowRepo.save(roadshow);notificationClient.send(路演预约成功);}看上去挺优雅的。但问题出在异常场景——互动服务超时了Seata 回滚了路演创建和企业校验但通知那边已经发出了路演预约成功的短信。用户收到通知去页面一看路演不存在。这就是最终一致性问题。SAGA 也好TCC 也好本质上都是把保证不出错变成了出错后想办法弥补。对电商这种场景来说补偿逻辑写起来非常痛苦。后来我读到 Matthias Patzak 的观点“短期内模块化单体在开发速度和重构灵活性上具有压倒性优势。”1这话一点不夸张。一个 Bug 需要起 4 个服务才能调有一次线上报了一个 Bug投资者打开互动提问提问提交成功了但路演页面显示未开通互动。排查过程是这样的看 roadshow-service 日志 → 调用 interaction-service 返回了超时看 interaction-service 日志 → 开通互动成功回写状态时调 roadshow-service 超时看网络 → 两个服务之间间歇性丢包开发环境复现启动 gateway、roadshow-service、interaction-service、company-service 四个服务 Nacos MySQL Redis。本地 16G 内存跑不满。整个过程花了将近两天真正修代码只用了半小时。剩下的时间全在搭环境和追调用链。运维成本翻了三倍CI/CD 从 1 条流水线变成 8 条。每次升级依赖包要改 8 个 pom.xml。日志分散在 8 个地方查一个问题要拼多个 ELK 查询。gankinterview.cn 提供了一个量化对比1百万级用户系统模块化单体每月基础设施成本约 3000 美元微服务架构约 12000 美元——差 4 倍。我们没到那个量级但运维人力成本是实打实的。原来一个后端运维就能搞定的事拆完之后所有开发都要学 K8s、学链路追踪、学怎么排查分布式问题。团队只有 8 个人实在不划算。网络延迟和雪崩原来一个方法调用是纳秒级。变成 RPC 后是毫秒级。不只是延迟。有一次>为什么决定合回去2024 年底我做了一个决定合回去。不是拍脑袋。看下面的表格维度拆分前单体拆分后8 微服务部署时间5 分钟30 分钟编排依赖新增一个跨模块功能1-2 天1 周左右线上问题平均排查时间30 分钟2-4 小时运维人力0.5 人1.5 人CI/CD 流水线维护1 条8 条生产事故半年2 次5 次数据摆在这儿没什么好解释的。核心问题是我们团队 8 个人业务耦合度高没有任何一个模块需要独立扩缩容。拆分带来的收益独立部署、技术栈自由我们一个都没享受到付出的代价倒是全吃了。2026 年 51CTO 将模块化单体列为年度架构趋势指出微服务架构的过度拆分问题被广泛反思2。这件事早两年就该反思了。合回去之后模块化单体怎么做合回去不是把代码全倒回一个大 jar 包了事。那是退回到大泥球不是解决问题。我们做的事情是用 Maven 多模块保持边界platform/ ├── platform-investor ├── platform-roadshow ├── platform-company ├── platform-interaction ├── platform-notification ├── platform-common └── platform-start (启动模块)每个模块有自己的package和internal子包。internal下的类不对外暴露。模块之间通过public接口调用编译期就能检查出越界引用。这一步还借助了 ArchUnit 做架构测试ArchTestvoidmodules_should_not_depend_on_internal_packages(){noClasses().that().resideOutsideOfPackage(com.platform.roadshow..).should().dependOnClassesThat().resideInAnyPackage(com.platform.roadshow.internal..).check(classes);}CI 里跑不通过就不让合并。事务回归简单原来跨模块调用就是一个方法调用不需要 RPC不需要分布式事务。Spring 的Transactional又好使了。如果将来真的要拆边界已经画好了。哪天路演模块真的需要独立部署团队变大、独立发布节奏只需要把platform-roadshow抽出来加一层 RPC 适配层就行。边界不需要重画。什么时候该拆什么时候不该拆经过这一圈折腾我自己的判断标准是这样该拆的情况团队超过 50 人多个小组并行开发不同业务域不同模块有完全不同的发布节奏比如核心业务两周一发、后台管理一天一发某个模块需要独立扩缩容路演服务 QPS 1000数据服务 QPS 5技术栈确实需要异构比如算法服务用 Python业务用 Java不该拆的情况团队不到 20 人沟通成本本来就低业务强耦合跨模块事务多没有独立扩缩容需求整体 QPS 不超过 1000运维能力跟不上团队没有专门的 DevOpsMartin Fowler 说的好“除非系统复杂到无法作为单体管理否则不要考虑微服务。”1我以前觉得这是保守。现在觉得这是常识。总结一句话模块化单体是小团队的甜点区。微服务不是目的是好架构的结果。架构的选择不是哪种更高级而是哪种更适合你现在的阶段。我们当时的问题不是单体不好是代码写得烂。代码写得烂拆成微服务只会变得更烂——只不过烂得更有层次感了。如果再来一次我会先把单体内部的模块边界理清楚做好高内聚低耦合。等有一天业务规模真的到了单体扛不住的时候再拆也不迟。参考作者唐悦玮 公众号同名从后端出发用 AI 拓展到全栈的工程师。“微服务已死2026 面试官开始推崇模块化单体”: gankinterview.cn ↩︎ ↩︎ ↩︎ ↩︎“2026 技术架构新趋势从微服务回潮到 AI 原生架构”: 51cto.com ↩︎
RELATED

相关推荐

Protel到AutoCAD的PCB设计文件转换全攻略

Protel到AutoCAD的PCB设计文件转换全攻略

1. Protel电路设计软件与文件格式转换概述Protel作为电子设计自动化(EDA)领域的经典工具,自DOS时代起就深受工程师青睐。这款软件在PCB设计领域占据重要地位,特别是在上世纪90年代到本世纪初,几乎成为国内电子工程师的标配工具。其核心价值在…

📅 2026/9/11 18:13:23
《流浪地球2》外骨骼装备成真!傲鲨携消费级新品打造户外科技新生态

《流浪地球2》外骨骼装备成真!傲鲨携消费级新品打造户外科技新生态

7月4日,阳澄湖半岛度假区内,十几人穿着傲鲨VIATRIX增程动力外骨骼机器人徒步。外骨骼通过学习行走姿态助力,让徒步更轻松。这一科技正从工业走向户外,带来全新体验。从科幻到现实的户外装备《流浪地球2》与《死亡搁浅》中的外骨骼…

📅 2026/9/11 18:13:18
5分钟快速找回QQ空间全部历史说说的终极指南:GetQzonehistory完整教程

5分钟快速找回QQ空间全部历史说说的终极指南:GetQzonehistory完整教程

5分钟快速找回QQ空间全部历史说说的终极指南:GetQzonehistory完整教程 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 你是否还记得那些年发过的QQ空间说说?那些…

📅 2026/8/26 10:02:58
MORE NEWS

更多资讯

📰

Java聊天系统设计与实现:Socket多线程并发编程实战

简介:面向需要学习 Java 网络编程、完成课程设计或毕业设计的开发者,这一基于 Java 的聊天系统设计与实现资源提供了从客户端到服务器端的完整方案。资源包大小约 518KB,内含源代码、系统运行截图、项目报告和使用说明文档,覆盖用…

📰

DouK-Downloader 完整教程:三步快速批量下载抖音和 TikTok 作品

DouK-Downloader 完整教程:三步快速批量下载抖音和 TikTok 作品 【免费下载链接】TikTokDownloader 抖音 / TikTok 平台作品下载/数据采集工具 项目地址: https://gitcode.com/GitHub_Trending/ti/TikTokDownloader 从一个真实需求说起 假设你现在有个任务&…

📰

Spring Boot外卖点餐系统实战:角色权限、订单状态机与部署排错全解析

简介:这是一份面向毕业设计场景的Spring Boot外卖点餐系统完整项目,适合计算机相关专业学生用于课程设计、毕业设计或项目答辩参考。后台采用Spring Boot框架,前端页面使用Vue,数据库为MySQL,运行环境JDK1.8&#xff0…

📰

G-Helper 完全指南:华硕笔记本性能控制如何做到轻量又够用

G-Helper 完全指南:华硕笔记本性能控制如何做到轻量又够用 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivobook, Zenbook…

📰

YOLO-IOD: Towards Real Time Incremental Object Detection——迈向实时增量目标检测

论文针对增量目标检测任务,提出了一个基于YOLO框架的实时解决方案。以下是其核心研究内容的全面总结: 一、研究背景与问题 任务定义:增量目标检测要求模型在持续学习新类别时,不遗忘旧类别知识。 现有局限:主流IOD方…

📰

第六篇:Sim2Real 深度解析——如何让仿真中的智能体走进现实

第六篇:Sim2Real 深度解析——如何让仿真中的智能体走进现实 一、为什么仿真成功不代表现实可用 机器人在仿真环境中完成任务,到了现实环境却可能立即失败。这种差异称为 Reality Gap。 其来源至少包括六类: 1. 视觉差异 光照和阴影&#xff…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬