从”拆就对了”到”拆对了吗”
过去几年,”微服务”几乎是架构讨论的默认答案。技术会议、招聘 JD、架构评审,到处都在谈论服务拆分、容器编排和 service mesh。但进入 2025 年下半年之后,社区风向开始出现明显变化——不是微服务不灵了,而是很多团队发现自己花了大量精力拆出去的服务,并没有换来预期的收益,反而背上了一身运维债。
Gartner 2026 年的技术趋势报告里有一组让不少架构师坐不住的数据:约 45% 的企业在微服务迁移后遭遇了超出预期的运维成本增长。DORA 2026 加速报告也指出,90% 采用微服务的团队实际上仍在做批量部署,承受着分布式系统的全部复杂性,却没有拿到独立部署的核心红利。换句话说,大部分团队交了”微服务税”,但没享受到”微服务福利”。
与此同时,亚马逊 Prime Video 团队公开了一个极具说服力的案例:他们把一个关键服务从微服务架构迁回单体后,基础设施成本直接降了 90%。亚马逊 CTO Werner Vogels 在反思中提到一句话——”构建可演进的软件系统是一种策略,而非宗教信仰。”这句话基本上点破了过去几年架构选型中最大的问题:把微服务当成了信仰,而不是工具。
正是在这种背景下,模块化单体重新进入了主流视野。它不是传统意义上那个代码搅成一团的巨石应用,而是一种介于传统单体和微服务之间的架构形态——保留微服务的领域拆分思想,但在部署层面仍然是单一进程。
模块化单体到底”模块化”在哪
很多团队第一次听到”模块化单体”这个词的时候,会误以为它就是”把单体写得好一点”。这个理解差了一层。模块化单体的核心不是代码写得整洁,而是在单体内部建立和微服务一样的边界纪律。
具体来说,一个合格的模块化单体应该满足三个条件:每个业务模块拥有自己的领域模型和数据访问层,模块之间通过明确的接口通信而不是直接互相调用内部类;模块内部可以独立开发和测试,不依赖其他模块的运行时状态;部署时是一个进程,但代码结构和部署形态是解耦的——未来如果某个模块需要独立出去,迁移成本是可控的。
这一点至关重要。模块化单体的价值不在于”现在不拆”,而在于”拆的时候不痛苦”。如果你的模块边界足够清晰,接口定义足够稳定,那么从进程内方法调用切换到 HTTP/gRPC 调用,本质上只是通信协议的变更,而不是一次伤筋动骨的重构。
以一个常见的电商系统为例,模块化单体的代码结构大致长这样:
shop-app/
├── user-module/
│ ├── application/
│ │ └── UserService.java
│ ├── domain/
│ │ └── User.java
│ └── infrastructure/
│ └── UserRepository.java
├── order-module/
│ ├── application/
│ │ └── OrderService.java
│ ├── domain/
│ │ └── Order.java
│ └── infrastructure/
│ └── OrderRepository.java
└── payment-module/
├── application/
│ └── PaymentService.java
└── infrastructure/
└── PaymentRepository.java
每个模块内部遵循 DDD 的分层结构,模块之间通过 application 层暴露的接口交互。比如订单模块需要调用用户信息,它依赖的是 UserService 接口,而不是直接碰 UserRepository。这样即使将来把 user-module 独立成微服务,order-module 只需要把 UserService 的实现从进程内调用换成远程调用,领域逻辑不用动。
微服务的隐性成本比你以为的要高
微服务架构本身的技术价值没有问题,真正的问题在于很多团队在不具备条件的时候就启动了拆分。当一个 10 人团队管理着 8 个微服务的时候,每个开发平均要负责将近一个服务,但基础设施的维护成本——服务注册发现、配置中心、链路追踪、日志聚合、容器编排、CI/CD 流水线——不会因为团队小就按比例缩小。这些固定开销就像一个很高的底座,服务数量撑不起来的时候,成本效率非常低。
更隐蔽的成本来自网络。有一个被反复验证但经常被忽视的事实:进程内方法调用的延迟在微秒级别,而一次跨服务的 RPC 调用,即使在内网环境下也在毫秒级别。一个涉及 4 到 5 个服务协作的核心接口,光网络开销就可能贡献几十甚至上百毫秒。有团队做过真实对比,同一套业务逻辑从微服务迁回模块化单体后,核心接口的平均响应时间从 450ms 降到了 80ms,接近 6 倍的差距。这不是代码质量问题,是架构形态决定的天然差异。
还有一个经常被低估的问题:分布式事务的一致性。单体架构下,多个模块共享一个数据库,一个本地事务就能搞定的事,到了微服务架构里就变成了 saga、TCC 或者最终一致性方案。这些方案不仅实现复杂,而且在异常场景下的行为很难验证。很多团队在拆服务的时候没有充分评估这一点,等到线上出了数据不一致的问题,排查起来非常痛苦。
两种架构的关键差异:不是非此即彼
把模块化单体和微服务放在对立面上比较,本身就是一种误解。它们更像是同一条演进路径上的两个阶段,而不是两个互斥的选项。但为了帮助团队做判断,还是需要把关键维度的差异拉出来看清楚。
| 维度 | 模块化单体 | 微服务 |
|---|---|---|
| 部署形态 | 单一进程,一次构建一次部署 | 多进程,独立构建独立部署 |
| 模块通信 | 进程内方法调用,延迟极低 | HTTP/gRPC/消息队列,有网络开销 |
| 数据一致性 | 本地事务,简单可靠 | 分布式事务,需 saga 或最终一致性 |
| 独立扩展能力 | 整体扩展,粒度粗 | 按服务独立扩展,粒度细 |
| 故障隔离 | 一个模块崩溃可能影响整体 | 可做到服务级隔离和熔断 |
| 运维复杂度 | 低,一个应用一套监控 | 高,需要全链路追踪和服务治理体系 |
| 团队规模门槛 | 5-30 人团队均可 | 建议 20 人以上且组织可拆分 |
| 技术栈灵活性 | 统一技术栈 | 各服务可选择不同技术栈 |
从这张表里能看出一个关键信息:微服务在独立扩展、故障隔离和技术栈灵活性上有不可替代的优势,但这些优势的兑现需要足够的团队规模和运维成熟度来支撑。如果你的团队还在 10 人左右,业务模块的流量差异也不大,这些优势根本用不上,但复杂度的成本是真金白银地付了。
什么时候该用微服务:四个必要条件
2026 年社区逐步形成了一个相对务实的共识,判断是否需要微服务,至少要同时满足以下几个条件:
- 团队规模足够大:通常 15 人以上的研发团队才可能从微服务的并行开发中真正受益。团队小时,服务拆分带来的协作增益远不如沟通成本的增加。
- 已验证的独立扩展需求:不是”可能需要”,而是已经有数据证明某个模块的流量或资源消耗和其他模块存在显著差异,整体扩展造成明显的资源浪费。
- 严格的故障隔离要求:业务上要求某个子系统的故障不能扩散到其他部分,比如支付系统不能因为推荐服务的崩溃而不可用。
- 成熟的 DevOps 基础设施:CI/CD、容器编排、服务发现、链路追踪、统一日志——这些不是可选项,是微服务的入场券。DORA 的数据显示,DevOps 成熟度低的团队切换到微服务后,部署频率和故障恢复速度反而会下降。
这四个条件不是”满足一个就行”,而是缺一不可。很多团队的微服务实践之所以痛苦,就是在只满足了一两个条件的时候就做了决策。最常见的场景是:CTO 在技术会议上看到一篇微服务的最佳实践文章,回去就要求团队把单体拆了。半年后发现维护成本翻倍,开发效率反而下降,但已经回不了头了。
模块化单体的三个常见误区
虽然模块化单体的概念听起来简单,但在实际落地中,团队很容易掉进几个坑里。
第一个误区是”有模块名就是模块化”。很多项目的代码目录里确实有 user、order、payment 这样的文件夹,但模块之间互相直接 import 对方的内部类、共享同一个数据库表、甚至一个事务里跨模块写多张表。这种”假模块化”本质上还是传统单体,只是在目录层面做了分组。等到真正想拆服务的时候,才发现耦合关系盘根错节,拆一个模块牵动半个系统。
第二个误区是忽视模块间的接口设计。模块化单体要为未来的演进留路,核心就在于模块间通信必须通过接口,而不是直接访问实现。但很多团队为了开发效率,默认让模块之间直接调用 application service 的实现类。短期看确实快了,但接口边界一旦模糊,模块化就名存实亡。正确的做法是,每个模块对外暴露一组接口(可以是 Java interface,也可以是模块 API 模块),其他模块只能依赖接口,不能依赖实现。
第三个误区是过早追求数据库物理隔离。有些团队听说了”每个微服务一个数据库”的原则,于是在模块化单体阶段就给每个模块建了独立的数据库。这在单体部署形态下几乎没有任何收益,反而带来了跨库查询困难、分布式事务问题提前到来等副作用。正确的做法是:在单体阶段共用一个数据库实例,但每个模块拥有自己独立的表集合,通过 schema 或者表名前缀做逻辑隔离。等真正拆服务的时候再做物理隔离。
演进路径:从模块化单体到微服务的正确姿势
模块化单体最被低估的价值,是它提供了一条低风险的演进路径。不是所有系统一开始就需要微服务,但几乎所有系统都有可能在未来发展到需要微服务的阶段。关键在于,你现在的架构是否为这个可能性留了门。
一个比较健康的演进路径大概是这样的:
- 起步阶段:用模块化单体启动项目,按领域划分模块,模块间通过接口通信,共用数据库但逻辑隔离表。
- 识别瓶颈:系统上线后通过监控数据识别出流量最大或者资源消耗最不均衡的模块。通常这种模块在 1-2 个以内。
- 定向拆分:把瓶颈模块独立成微服务,通信方式从进程内调用切换为远程调用。由于接口已经定义好,迁移的工作量主要集中在部署和基础设施层面。
- 按需扩展:随着业务增长,逐步把更多模块独立出去,但始终保持”有需要才拆”的原则,而不是一上来就全部拆完。
这条路径的好处是每一步的决策都有数据支撑,而不是拍脑袋。而且任何时候你都可以停下来——如果系统发展到某个阶段发现模块化单体已经够用了,那就停在模块化单体,没有任何损失。
一个判断标准:如果你的微服务拆分需要专门招一个 DevOps 工程师来维护基础设施,而你的业务团队只有 5 个开发,那这个拆分大概率是不划算的。
2026 年的架构选型:回归理性
如果站在 2026 年这个时间节点往回看,过去十年的架构演进其实经历了一个完整的周期:从单体到微服务的狂热,到微服务复杂度的集中爆发,再到模块化单体的理性回归。这不是简单的钟摆运动,而是行业在真实实践中积累出了更成熟的判断框架。
对于正在做架构选型的团队,2026 年的核心认知可以总结为三点:
- 架构选型的第一性原则是解决业务问题,不是追逐技术潮流。微服务不是更先进的架构,模块化单体也不是更保守的选择,它们是针对不同场景的不同工具。
- 复杂度不会消失,只会转移。微服务把代码层面的复杂度转移到了运维和基础设施层面。如果你的运维能力跟不上,这种转移就是净亏损。
- 演进式架构是更安全的策略。从模块化单体起步,通过清晰的模块边界为未来留路,在数据和业务需求的驱动下逐步拆分——这条路比”一开始就拆微服务”风险低得多,也比”永远不拆”灵活得多。
说到底,架构师最有价值的能力不是会画多少种架构图,而是在给定约束条件下做出最务实的取舍。2026 年的架构讨论不再围绕”微服务好不好”,而是”在当前阶段,什么样的架构能让团队跑得最快、最稳”。这个问题没有标准答案,但有了更清晰的思考框架,至少不会再被”拆就对了”这种声音带着走了。
原创文章,作者:,如若转载,请注明出处:https://fudengji.cn/article/313/