微服务不是银弹,单体也不是耻辱:一次重构后的真实感悟

🔑 关键词:微服务,单体架构,重构,团队效率,技术债务

📖 摘要:作者经历了一次从微服务退回单体的重构,结合具体参数和团队协作细节,讨论了架构选型背后的非技术因素,提出“架构是组织结构的投影”这一观点,并给出了自己的判断标准。

微服务不是银弹,单体也不是耻辱:一次重构后的真实感悟

图片

2019年我加入一家B轮公司,当时技术部刚完成从冷启动到快速扩张的转变。所有人都在谈微服务,好像不拆几个服务就不好意思说自己是做互联网的。我们当时把订单、支付、库存、用户拆成了四个服务,每个服务独立部署,数据库也物理隔离,还上了Kubernetes。刚开始确实爽,每个小组可以独立发版,互不打扰。但到了2021年,问题开始集中爆发:一次跨服务查询需要经过3次HTTP调用,平均延迟从原本单体的45ms涨到了280ms;每次联调要启动4套环境,配置中心一改就有人喊连不上;更痛苦的是,为了一个“用户积分”的功能,需要同时改用户服务和订单服务,两个团队排期对不上,硬是拖了两周。我们那时候开会经常说,这是微服务带来的“自治”代价,但我心里清楚,这其实是架构在替我们的组织方式背锅。

图片

后来公司业务调整,我们决定把订单和库存合并回一个单体。这不是推倒重来,而是基于一个很朴素的判断:这两个服务的数据一致性要求极高,而且几乎总是同时被修改。拆开之后我们不得不引入分布式事务,用的是Seata的AT模式,但经常会因为undo_log表锁冲突导致本地事务失败,成功率从原来的99.99%降到了99.7%。对于电商系统来说,0.3%的失败意味着每天几百个订单卡在中间态,客服要手工处理。合并后,我们直接用本地事务+悲观锁,代码删掉了一大堆补偿逻辑,吞吐量反而上去了。我印象很深的一个数字:改造前两台服务节点在高峰期的CPU是70%左右,合并后单台服务节点在同样的压力下CPU只有45%,因为省去了序列化和网络开销。所以谁说单体一定性能差?关键看你的业务是不是真的需要拆分。

图片

我要提一个可能被很多人忽视的观点:微服务拆的不是代码,而是团队的责任边界。如果你的团队本来就是按照业务域划分的,比如有人专门做订单、有人专门做库存,那么就算你代码写在一起,你们也可以通过模块化接口来解耦。反而拆成服务后,为了维持“服务自治”,你不得不引入大量的接口文档、契约测试、版本管理,这些都是隐性成本。我们当时有四个服务,但只有十二个开发人员,平均每个服务3个人。为了保持每个服务的发布节奏,我们甚至要排值班表,谁负责本周的发布窗口。有一次升级基础镜像,因为四个服务的基础镜像不统一,导致同一个漏洞要打四次补丁。后来我把所有服务的Dockerfile拿过来对比,发现至少有三种不同的基础镜像版本,有的还停留在Ubuntu 18.04。这能怪谁?怪我们当初没有做平台工程?其实根源是我们这个团队规模根本撑不起微服务的治理成本。

图片

如果你问我什么时候该用微服务,我的判断标准只有一条:你的团队是不是能同时并行推进两个以上独立上线的需求,并且这些需求不会涉及跨模块的频繁改动。如果是,那就拆;如果不是,单体加模块化是更好的选择。我见过一个做SaaS的团队,30个开发人员,产品线却很杂,他们用了微服务,每个服务很薄,但服务间调用的链路很深。结果每次改动都要画调用链路图,靠人工影响分析。后来他们引入了OpenTelemetry,但还是解决不了“不知道改哪个服务”的问题,因为问题出在领域建模上。架构不是用来炫技的,它是用来支撑业务演进的。我越来越觉得,那些天天喊“高并发”“弹性扩展”的人,可能连QPS 1000都没跑过。我们当时拆微服务,客户量总共不到10万,日订单峰值不到5000。你说有什么必要?

图片

最后我想说,我在这次重构里学到的最重要的一件事:不要为了简历上的技术栈而选择架构。技术债不是写烂代码欠下的,而是用不合适的架构支撑不匹配的组织形态欠下的。现在我也学会了,每次立项先画一张简单的表格,列出需要共享的数据、需要同步的流程、需要独立发布的频次。如果这三个维度的耦合度都很高,那就老老实实写单体。别觉得单体丢人——等你看到微服务的新人入职两周还理不清服务间的鉴权关系时,你就明白,简单才是长期主义。当然,这并不意味着微服务没有未来。对于业务域清晰、团队规模在百人以上、DevOps成熟度高的组织,微服务仍然有它的价值。关键是,你的团队有没有对应的治理能力,如果没有,那就别装样子了。

图片

🏷️ 标签: