我为什么从微服务退回单体架构

我为什么从微服务退回单体架构

------一次"技术升级"的反思与回归


一、那个让我冲动的下午

三年前,我坐在工位上,刷着技术博客。满屏都是"微服务是未来的方向""单体架构是技术债的根源""Netflix 是如何用微服务支撑亿级流量的"。

当时我们系统的情况是这样的:一个运行了两年多的单体应用,代码大概 8 万行,部署一次需要 5 分钟,团队 6 个人。

说实话,系统跑得好好的。但架不住心里那股劲儿------"别人都在用微服务,我们还在单体,是不是技术落后了?"

于是我花了两周时间,画了一张服务拆分图,把原来的单体拆成了 9 个微服务。订单服务、用户服务、支付服务、商品服务、通知服务、日志服务、配置服务、网关服务、还有一个说不清干嘛的"公共服务"。

我至今记得第一次把整套系统跑起来的那个晚上。9 个服务,3 个数据库,2 个消息队列,1 个注册中心,1 个配置中心。屏幕上密密麻麻的终端窗口,像极了黑客帝国。

我当时的感觉是:终于像个正经架构师了。


二、然后现实开始打脸

第一个月:开发效率断崖式下跌

以前改一个功能,打开一个项目,改完,提交,部署。现在呢?

改一个"用户下单"的功能,涉及订单服务和用户服务。我得同时打开两个项目,改完用户服务,写个接口,改完订单服务,调接口。然后发现两个服务的 API 版本对不上,又得回去改。

一个简单的需求,以前半天搞定,现在要两天。

更崩溃的是本地调试。以前 npm run dev 或者 mvn spring-boot:run 一把梭,现在得先把注册中心跑起来,再把配置中心跑起来,然后依次启动各个服务。哪天某个服务的端口被占了,或者配置文件写错了,整个链路就跑不通。

我组里一个新来的同事,配了三天环境,最后跟我说:"哥,我想跑路。"

第三个月:运维噩梦

9 个服务,每个服务至少两个实例做高可用。加上中间件,我们服务器上跑了接近 30 个进程。

然后问题来了:

  • 服务 A 调服务 B,B 超时了。 是 B 本身慢,还是网络问题,还是注册中心把 A 指向了一个不健康的 B 实例?排查一次至少半小时。
  • 数据库分散了。 以前一个库,JOIN 一下完事。现在订单和用户在两个库,要查"某个用户的所有订单",得先查用户服务拿 ID,再拿 ID 去订单服务查。后来干脆上了 Elasticsearch 做聚合,又多维护一个组件。
  • 日志分散了。 一个请求经过网关 → 用户服务 → 订单服务 → 支付服务,出了问题你得挨个翻 4 个服务的日志,靠一个 traceId 串联。我至今记得有天凌晨三点,我一边翻 Kibana 一边骂自己。

第六个月:团队开始分裂

6 个人的团队,每人负责 2-3 个服务。表面上"术业有专攻",实际上:

  • 小张负责支付服务,对订单服务的逻辑一窍不通。订单服务要改个字段,得跟小李沟通半天,小李还不一定有空。
  • Code Review 变成了走过场。没人能同时看懂所有服务的代码,review 的时候大家都在点头。
  • 线上出问题,互相甩锅。"我这边接口返回没问题啊,是你调的方式不对吧。"

最讽刺的是:我们拆微服务,本意是让团队并行开发更快。结果变成了并行地互相阻塞。


三、我终于承认:我们不是 Netflix

回过头来看,微服务不是不好。微服务是一把手术刀,精准、强大,但前提是你得有手术室、麻醉师、护士团队,以及一台值得动手术的病人。

我们缺什么?

微服务的前提条件 我们当时的情况
团队规模 20+ 人 6 人
清晰的领域边界 业务还在快速变化,边界每月都在变
成熟的 DevOps 体系 一个半吊子运维 + 我这个兼职架构师
独立的数据库团队 没有,DBA 是隔壁组借的
完善的监控和链路追踪 没有,出问题靠人肉
服务治理经验 没有,全靠网上抄

**我们不是 Netflix,甚至连 Netflix 的 1% 都不到。**​ Netflix 有上千个工程师,有专门的基础设施团队,有自研的 Chaos Monkey 做混沌测试。他们用微服务是因为不得不这么做------单体根本装不下他们的复杂度。

而我们呢?我们的"复杂度"是 8 万行代码,6 个人,一个部署包。

这不是复杂度,这是矫情。


四、决定退回的那天

转折点是一个线上事故。

用户反馈下单失败。我排查了三个小时,发现是订单服务调用户服务时,因为网络抖动导致超时,但订单服务没有做好重试和降级,直接抛了异常给用户。

修复方案很简单:加个熔断和重试。但问题是,这个逻辑散落在 4 个地方------订单服务调用户服务、订单服务调库存服务、订单服务调支付服务、支付服务调通知服务。每个地方用的库版本还不一样,有的用 Hystrix,有的用 Resilience4j,有的干脆什么都没用。

我坐在那,突然觉得很荒谬。

一个单体应用里,这种问题根本不存在。方法调用失败了?加个 try-catch,完事。现在呢?我得在分布式系统里处理网络不可靠、服务不可用、消息丢失、数据不一致......

而这一切,只是为了让 6 个人能"独立开发"。

那天晚上我跟技术总监聊了很久。他说了一句话让我醍醐灌顶:

"架构是为业务服务的,不是为架构师的面子服务的。"


五、退回单体,但这次不一样

我们没有一夜之间把所有微服务合并回去。那太激进了。我们是分三步走的:

第一步:止血

先把最痛的几个问题解决:

  • 把配置中心干掉,改回本地配置文件 + 环境变量
  • 把消息队列干掉,改回应用内的事件驱动
  • 把分布式事务干掉,改回数据库事务

这一步做完,运维复杂度直接砍掉一半。

第二步:合并

按"改动频率"和"业务耦合度"重新评估。发现 9 个服务里,真正需要独立的只有 2 个:支付服务(对接第三方,安全隔离需要)和通知服务(异步发送,可以独立)。

其余 7 个服务,合并成一个单体。不是简单地把代码堆一起,而是重新用模块化方式组织

复制代码
monolith/
├── modules/
│   ├── user/
│   ├── order/
│   ├── product/
│   ├── payment/    (只留接口定义,实现在独立服务)
│   └── notification/ (同上)
├── shared/
│   ├── common/
│   └── db/
└── api/

每个模块有明确的边界和接口,但部署时是一个包

第三步:建立纪律

这是最关键的一步。单体架构最大的风险是"大泥球"------代码越来越乱,最后谁都不敢动。

所以我们立了几条规矩:

  1. 模块之间只能通过接口通信,不能直接访问对方的数据库表
  2. 每个模块有独立的测试套件,CI 里模块级别跑测试
  3. 定期做架构评审,当某个模块的复杂度或团队规模真的到了需要拆分的程度,再拆
  4. 监控和告警不能省,单体的监控比分布式简单得多,没理由不做

六、退回之后的变化

说几个数据:

指标 微服务时期 退回单体后
部署时间 20 分钟(全链路) 3 分钟
新功能开发周期 平均 5 天 平均 2 天
线上故障排查时间 平均 2 小时 平均 15 分钟
服务器成本 12 台 3 台
团队满意度 低(新人离职率 40%) 高(半年 0 离职)

但比数据更重要的是心态的变化

以前大家每天都在跟基础设施搏斗------服务注册不了、配置拉不到、链路追踪断了。现在大家终于可以把精力放在写业务代码上了。

那个差点跑路的新同事,现在是我们组最积极的 code reviewer。


七、我学到了什么

1. 康威定律是真实的

设计系统的架构,受制于产生这些设计的组织的沟通结构。

6 个人,拆成 9 个服务,本质上是在用技术架构强行模拟一个大团队的协作模式。结果就是沟通成本爆炸,每个人都成了"分布式系统里的一个节点",信息在传递中不断丢失。

团队规模决定了架构的复杂度上限。

2. 分布式系统的复杂度不是线性的

很多人以为:把单体拆成 N 个服务,复杂度除以 N。

错。复杂度是乘以 N。

因为你在单体里不需要处理的那些问题------网络分区、数据一致性、服务发现、熔断降级、分布式追踪------全部变成了你必须处理的问题。而且每一个都是深坑。

3. 模块化是微服务的"平替"

很多人把"单体"等同于"大泥球"。这是误解。

一个设计良好的模块化单体,完全可以做到:

  • 模块边界清晰
  • 团队可以并行开发不同模块
  • 单个模块可以独立测试
  • 将来需要时,把某个模块拆成独立服务(只需要改接口实现,不需要改调用方)

模块化单体 + 良好的架构纪律 = 80% 的微服务收益,10% 的复杂度。

4. 技术选型要问"为什么",而不是"为什么不用"

每次引入一个新东西,问自己:

"如果不引入这个,我最大的痛苦是什么?这个痛苦真的到了必须解决的程度吗?"

如果答案是"其实忍忍也能过",那就先忍忍。等技术真的痛了,你自然知道该用什么。


八、最后想说的话

这篇文章不是劝你不要用微服务。如果你的团队有 50 人,业务复杂到单体已经管不住了,那微服务可能是正确的选择。

这篇文章是写给那些和我当年一样的人:

  • 团队不到 10 人
  • 业务还在探索期,需求变化快
  • 没有专职的运维和基础设施团队
  • 系统跑得好好的,只是"感觉"该升级了

如果你符合以上大部分条件,请认真考虑:你的系统真的需要微服务吗?

有时候,最好的架构决策不是"加上什么",而是"忍住不加什么"。

相关推荐
code 小楊37 分钟前
Agent间如何高效协作?深度拆解A2A(Agent-to-Agent)协议
人工智能·架构·开源
onthe_wing37 分钟前
flink基础知识,系统运行时架构,部署模式详解
大数据·架构·flink
布吉岛的石头1 小时前
Java 程序员第 48 阶段1:Transformer 架构总览与自注意力直觉,从 RNN 痛点理解注意力机制
java·架构·transformer
Asum1ta1 小时前
生产环境 Kubernetes 高可用集群部署实战:外部 etcd + Keepalived + HAProxy + 多 Master 架构
架构·kubernetes·etcd
jianqiang.xue1 小时前
ESP-IDF保姆级入门19|低功耗模式全解与工程化设计:分级休眠/唤醒源配置/功耗调优/外设适配,实现工业级功耗性能平衡
stm32·单片机·物联网·架构·esp32
源代码•宸2 小时前
前置准备:定时微服务有什么价值
经验分享·后端·微服务·云原生·架构
晏宁科技YaningAI2 小时前
企业通信系统技术规划方法:从业务需求到可演进架构
网络·性能优化·架构·gateway·paas
lhldsg3 小时前
相册印刷实战指南:从设计规范到系统落地全流程解析
java·小程序·架构·设计规范
IT大白鼠3 小时前
Kubernetes 核心资源ReplicaSet 控制器详解
云原生·容器·kubernetes