架构决策的反模式:什么时候你不该拆微服务?

微服务不是万能药。用真实案例说明单体架构在什么场景下优于微服务,给出'该不该拆'的决策矩阵,帮你避开过度拆分的坑。

微服务被神化了。过去十年,它从一种架构选项变成了"政治正确"——不拆就是落后,不拆就是技术债。

但现实是,70% 的微服务迁移项目最终都陷入了"分布式单体"的泥潭。不是微服务不好,而是大多数团队根本没想清楚自己为什么要拆。

架构决策的核心从来不是"什么技术更先进",而是"什么问题更痛"。如果你连痛点在哪都没搞清楚,拆微服务只会制造更多痛点。

这篇文章不打算再讲微服务有多好——那些内容你已经看过一万遍了。我想聊的是另一面:什么时候你根本不该拆


团队不到 30 人?别折腾了

微服务的本质是组织边界的映射。康威定律说得直白:系统架构会趋向于组织的沟通结构。

但这话反过来也成立:如果你的组织根本没有清晰的边界,强行拆微服务只会制造混乱。

一个 10 人的开发团队,所有人坐在一起,中午一起吃饭,遇到问题吼一声就能解决。这种沟通效率,任何 RPC 调用都比不上。

拆成微服务后呢?

  • 服务 A 的接口改了,得通知服务 B 的负责人
  • 服务 B 的负责人正在修服务 C 的 Bug,没空看
  • 服务 C 的部署流水线挂了,没人知道怎么修
  • 一个需求要改三个服务,发版得协调三个人的时间

沟通成本从 O(1) 变成了 O(n²)

我见过一个 8 人团队,把电商系统拆成了 23 个微服务。结果每次上线都要开全员会议,一个接口变更要发五封邮件,最后大家干脆建了个群,所有变更都在群里吼。

这不叫微服务,这叫用分布式架构模拟单体架构

团队规模推荐架构理由
< 10 人单体沟通成本最低,迭代最快
10-30 人模块化单体代码边界清晰,部署仍是一体
30-100 人粗粒度微服务按业务域拆分,3-5 个服务
> 100 人细粒度微服务团队自治,独立演进

团队规模是架构决策的第一个约束条件。如果你的团队还在"一个披萨能喂饱"的阶段,老老实实写单体。


业务域还没稳定?拆了也是白拆

微服务拆分的黄金法则是"按业务边界拆"。DDD(领域驱动设计)里叫限界上下文(Bounded Context)。

听起来很美。问题是:大多数创业公司的业务边界根本还没稳定

你今天觉得"用户"和"订单"是两个独立域,明天产品经理说要在用户页展示订单统计,后天运营说要给用户打标签关联订单行为。三个需求下来,你的"独立服务"已经耦合得比单体还紧。

有个做 SaaS 的团队,早期按"用户服务"“订单服务"“支付服务"拆了三个微服务。业务跑了半年,发现真正的边界应该是"前台展示"和"后台运营”。

结果呢?

  • 用户服务里塞了一堆运营逻辑
  • 订单服务要调用户服务拿标签,又要调支付服务查账单
  • 三个服务之间的调用关系比意大利面还乱

最后他们做了一件"政治不正确"的事:把三个服务合并回一个单体,按模块划分代码边界

两年后业务稳定了,再把"支付"和"通知"拆出去。这次拆分顺理成章,因为边界已经用脚投票投出来了。

业务不确定性高的时候,单体的"改起来快"比微服务的"部署独立"重要一万倍。


数据一致性要求高?分布式事务会让你哭

微服务最被低估的成本是数据一致性

单体架构里,一个事务就能搞定跨表更新。订单状态改了,库存扣了,用户积分加了——一个 COMMIT 完事。

拆成微服务后,这三步分布在三个数据库里。你要保证它们要么都成功,要么都回滚,就得引入分布式事务。

分布式事务的方案无非几种:

  • 两阶段提交(2PC):性能差,锁资源时间长,数据库不一定支持
  • TCC(Try-Confirm-Cancel):代码复杂度翻倍,每个业务逻辑要写三遍
  • Saga 模式:长事务编排,补偿逻辑难写,中间状态对外可见
  • 最终一致性:接受短暂不一致,用消息队列异步对齐

每种方案都有代价。选哪种,取决于你能容忍哪种不一致。

有个做金融的团队,把账户系统拆成了"账户服务"“交易服务"“风控服务”。一笔转账要跨三个服务,他们选了 Saga 模式。

结果上线第一周就出事了:交易服务扣了钱,风控服务判定异常要回滚,但回滚消息丢了。用户的钱少了,订单却没生成。

排查了三天,最后发现是消息队列的一个分区挂了,回滚消息进了死信队列没人消费。

分布式系统的 Bug 比单体系统难排查 10 倍。不是因为代码更复杂,而是因为状态分散在多个节点,日志分散在多个系统,时序问题靠人脑根本理不清。

如果你的业务对数据一致性要求极高(金融、库存、支付),又没有成熟的基础设施团队,单体架构是更安全的选择


运维能力不够?微服务会把运维成本放大 10 倍

微服务不只是代码层面的事,它对运维体系的要求是质变级的。

单体架构的运维很简单:

  • 一台服务器,跑一个进程
  • 一个 Nginx 做反向代理
  • 一个监控面板看 CPU、内存、QPS
  • 出了问题看一个日志文件

微服务架构的运维:

  • Kubernetes 集群,至少 3 个节点做高可用
  • 服务注册与发现(Consul、Nacos、Eureka)
  • API 网关(Kong、Traefik、APISIX)
  • 分布式链路追踪(Jaeger、Zipkin、SkyWalking)
  • 集中式日志(ELK、Loki)
  • 服务网格(Istio、Linkerd)——可选但推荐
  • 配置中心(Apollo、Spring Cloud Config)
  • 熔断限流(Sentinel、Hystrix)

每一项都是人力成本

有个传统企业做数字化转型,CTO 是从互联网大厂挖来的,一上来就推微服务。招了 5 个 Java 开发,写了 12 个服务,但没有专职运维。

上线后噩梦开始了:

  • 服务注册中心偶尔抽风,服务互相找不到
  • 链路追踪没配好,一个请求慢在哪根本查不出
  • 日志分散在 12 个容器里,排查问题要 kubectl logs 12 次
  • 配置中心的权限没管好,有人把生产环境的数据库密码提交到了测试环境

半年后,这个 CTO 离职了。接手的架构师第一件事是把 12 个服务合并成 3 个,运维成本直接降了 70%。

微服务的运维成本不是线性增长的,是指数级的。服务数量从 1 增加到 10,运维复杂度可能从 1 增加到 100。

如果你没有专职的 SRE 团队,没有成熟的 CI/CD 流水线,没有完善的监控告警体系——别碰微服务


性能瓶颈不在架构?拆了也没用

很多人拆微服务的理由是"单体太慢了”。

但慢的原因是什么?

  • 数据库没加索引,全表扫描
  • N+1 查询问题,一个列表页发 100 次 SQL
  • 没做缓存,每次都查库
  • 同步调用太多,一个请求串行调 5 个外部接口
  • 代码写得烂,循环里套循环

这些问题,拆微服务一个都解决不了

数据库慢,拆成两个数据库还是慢。N+1 查询,拆成两个服务还是有 N+1。没做缓存,拆了还是没做。代码烂,拆了还是烂。

有个内容平台,首页加载要 8 秒。团队讨论后决定拆微服务:用户服务、内容服务、推荐服务、评论服务。

拆完一测,首页加载变成了 12 秒。因为原来一次数据库查询能拿到的数据,现在要发 4 次 HTTP 请求,每次都有网络开销。

后来一个资深工程师介入,做了三件事:

  1. 给内容表加了复合索引
  2. 用 Redis 缓存热点内容
  3. 把推荐算法从同步调用改成异步预计算

首页加载从 8 秒降到 1.2 秒。一行微服务代码都没写

性能优化的 80% 收益来自 20% 的低垂果实。在拆微服务之前,先把这些果实摘了。


成本算过吗?微服务真的很贵

微服务的隐性成本经常被忽略。

开发成本:

  • 每个服务都要写一遍认证、鉴权、日志、监控
  • 服务间通信要定义协议、处理超时、重试、熔断
  • 联调要启动多个服务,本地开发环境搭建复杂
  • 一个功能改三个服务,代码评审要拉三个人

测试成本:

  • 单元测试好写,集成测试难写
  • 端到端测试要启动整个服务栈,跑一次半小时
  • 服务版本兼容性问题,A 服务升级了,B 服务没跟上,测试环境炸了

部署成本:

  • 12 个服务要部署 12 次,流水线要写 12 份
  • 服务依赖顺序要理清,A 依赖 B,B 依赖 C,部署顺序不能乱
  • 回滚要协调,A 回滚了,B 和 C 要不要一起回滚?

运维成本前面说过了,不再赘述。

这些成本加起来,微服务的总拥有成本(TCO)可能是单体的 3-5 倍

有个创业公司,A 轮融资后想"规范化”,把单体拆成了 8 个微服务。拆的过程花了 4 个月,3 个全职开发。拆完后每月云资源费用从 8000 涨到 28000。

B 轮融资失败,公司要省钱。第一件事就是把微服务合回单体,云资源费用降回 9000。

技术选型不能脱离商业语境。活下去比架构优雅重要得多。


决策矩阵:该不该拆微服务?

说了这么多"不该拆"的场景,那什么时候该拆?

我整理了一个决策矩阵,你可以对着打分:

维度强烈建议拆可以考虑拆别拆
团队规模> 100 人,多团队协作30-100 人,按域分组< 30 人,一个团队
业务稳定性核心域稳定 2 年以上部分域稳定,部分还在变整体业务还在探索
发布频率不同模块发布节奏差异大部分模块需要独立发布整体一起发布即可
扩展需求不同模块资源需求差异大部分模块需要独立扩展整体扩展即可
数据一致性能容忍最终一致性部分场景强一致,部分可放松全局强一致
运维能力有专职 SRE,成熟 K8s有基础 CI/CD,能搞定监控运维靠开发兼职
技术栈不同模块需要不同语言/框架主体统一,少量异构统一技术栈

满足 3 个以上"强烈建议拆"的条件,才值得认真考虑微服务。否则,模块化单体是更稳妥的选择。


模块化单体:被低估的中间路线

很多人不知道"模块化单体"这个选项。

它的核心思想是:代码层面按模块划分,部署层面仍是一体

举个例子,一个电商系统可以这样组织:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
monolith/
├── user/           # 用户模块
│   ├── api.py
│   ├── service.py
│   └── repository.py
├── order/          # 订单模块
│   ├── api.py
│   ├── service.py
│   └── repository.py
├── payment/        # 支付模块
│   ├── api.py
│   ├── service.py
│   └── repository.py
└── shared/         # 共享基础设施
    ├── database.py
    ├── cache.py
    └── auth.py

模块之间通过明确的接口通信,禁止直接访问对方的数据库表。代码评审时,跨模块的调用要严格审查。

这种架构的好处:

  • 保留了单体的部署简单、调试方便
  • 代码边界清晰,未来要拆某个模块出去很容易
  • 团队可以按模块分工,减少冲突
  • 性能更好,没有网络开销

Shopify 的核心系统就是一个巨大的模块化单体,支撑着每年几十亿美元的 GMV。他们内部叫"Modular Monolith",跑了十几年,稳定性吊打很多微服务系统。

架构演进不是一步到位的事。先单体,再模块化单体,最后才是微服务——这是更务实的路径。


拆了再合回来,丢人吗?

不丢人。

亚马逊的 Prime Video,2023 年把一部分微服务合回了单体,节省了 90% 的运维成本。这事被写成技术博客,全网传疯。

很多人觉得"拆了又合"是决策失误。其实不是。架构决策是基于当时的信息和约束做的最优选择

半年前业务高速增长,团队扩张,拆微服务是对的。半年后业务收缩,团队精简,合回单体也是对的。

架构不是一锤子买卖,它是持续演进的过程

有个做直播的团队,2021 年行业火爆,团队从 20 人扩到 80 人,把单体拆成了 15 个微服务。2023 年行业寒冬,团队裁到 30 人,又把 15 个服务合成了 4 个。

这不是反复横跳,这是根据约束条件动态调整

技术债务不是"没上微服务",而是"上了微服务但维护不起"。


写在决策之前

下次有人提议拆微服务,你可以问几个问题:

  1. 我们要解决什么问题? 是部署冲突?是扩展瓶颈?还是团队沟通成本?
  2. 这个问题用微服务能解决吗? 如果是代码写得烂,拆了还是烂。
  3. 我们有能力承担微服务的成本吗? 运维、测试、联调、监控,每一项都是钱和人。
  4. 有没有更轻量的方案? 模块化单体、代码分层、更好的 CI/CD,可能就够了。
  5. 如果半年后要合回来,代价大吗? 如果拆分不可逆,说明设计有问题。

架构决策的本质是权衡取舍。微服务不是银弹,单体也不是原罪。

选对架构,比选先进架构重要得多。

广告

📚 关注公众号,免费获取技术材料

扫码关注公众号,回复「资料」领取:

  • 📘 企业架构设计模板
  • 📗 数据治理实施指南
  • 📙 工业软件技术白皮书
公众号二维码

长按或扫描二维码