我见过太多团队在微服务这件事上栽跟头,不是因为他们技术不行,而是因为他们把架构选型当成了一种信仰。前几年微服务架构几乎成了“先进技术”的代名词,谁不在搞微服务谁就落后,谁还在写单体谁就是老古董。结果呢?我在技术社区见过不少当初热烈拥抱微服务的开发者,现在又开始在讨论怎么把服务合并回去。
这篇文章不打算劝你站队,也不打算证明微服务好还是坏。我想结合自己这些年参与和目睹过的实际项目,聊聊架构选型这个事儿背后的真实逻辑:什么样的团队、什么样的业务阶段、什么样的问题,才真正需要微服务;而哪些情况,坚持单体或者采用模块化单体,反而会让你晚上睡得更安稳。
1. 狂热期的驱动力:我们当年为什么非拆不可
1.1 技术舆论场的推力
2018年到2021年那阵子,微服务相关的技术分享几乎占领了所有技术大会的日程表。容器技术、编排平台、服务网格……这些东西轮番登场,加上大厂动辄“几千个微服务”的分享,直接把“微服务=现代化”这个等式刻进了很多人的脑子里。
我当时所在的团队也是在这样的氛围里开始拆服务的。老板去开了一次行业会议,回来就跟我们说:现在业界都在搞微服务,我们也得跟上。这个场景我相信很多同行都遇到过。当时我们团队总共就八个人,后端只有五个,系统是一个运行了三年的交易平台,每天几万单的规模,数据库也就二十几张表。
从现在的视角回头看,这个条件距离微服务的门槛差了十万八千里。但那时候没有人会去算这个账,大家只关心一件事:咱们搞不搞。搞了,以后简历好看,技术交流有面子;不搞,就显得落伍,下个季度的技术规划都不好意思往上写。
1.2 拆的时候很爽,拆完开始难受
我们当时的拆法也很有代表性:照葫芦画瓢,按照用户、订单、商品、支付这样的大模块把服务切出来。切的那一个月确实很爽,新建项目、写接口、搭网关、配注册中心,全是新鲜事,每天都有新东西在产出。团队成员的情绪高涨,觉得总算干上“正事”了。
但爽完之后的代价,是所有人都没预料到的。原来单体架构下一个事务能搞定的事情,拆了之后变成了跨服务调用;原来改一个接口只需要本地改完重启,现在要走完整的上线流程,还要协调依赖方一起发版。更要命的是测试环节,一次完整的回归测试要同时启动六个服务,开发机的内存直接吃紧,本地调试成了噩梦。
这不是我们一个团队的问题。我在技术社群里跟很多同行聊过,大家的经历高度相似:拆分带来的阵痛,几乎都发生在系统上线运行后的第三个月到半年之间。原因很简单,拆服务是“体力活”,而拆完之后维持这套分布式系统正常运作,才是真正的“技术活”。
1.3 一个被严重低估的隐性成本
如果说运维、测试、联调这些还只是表面成本,那数据一致性这个问题才是真正隐藏在水面下的巨坑。单体时代,订单状态和库存扣减可以在同一个数据库事务里完成,要么全部成功,要么全部回滚。拆成订单服务和库存服务之后,这个问题突然就变成了分布式事务难题。
当时我们为了解决这个事,尝试过很多方案。先是本地消息表,接着上事务消息中间件,后来又因为业务需要对账逻辑本来就复杂,再加了一层补偿机制。一个原本三十行代码就能搞定的事务逻辑,硬生生写成了几百行还不敢保证完全没有问题。
现在回头看,这个代价根本不该付。因为我们的业务量远没有达到单库性能瓶颈,也没到需要独立伸缩某个模块的规模。纯粹是为了拆而拆,结果给自己制造了一堆原本不存在的问题。这是微服务狂潮里最典型的教训:问题是先制造出来的,然后大家再去发明工具解决自己制造的问题。
2. 冷静期看微服务:它真正解决的是什么问题
2.1 微服务的本质是“组织工具”,不是“性能工具”
这两年行业里有一种越来越清晰的声音:微服务与其说是一种技术架构,不如说是一种组织管理工具。这个说法我深有体会。一个几百人的研发团队如果维护同一个代码仓库,光是代码合并、发布协调、需求并行就会把人逼疯。这时候把产品线切成不同的服务,让每个团队各管一块,独立开发和交付,才是微服务真正的价值所在。
换句话说,微服务解决的核心问题是大型组织下的研发效率问题,而不是系统的性能问题。如果你们团队只有十几个人,业务就一个核心闭环,那服务拆得再小也不会带来效率提升,反而会因为沟通、联调、部署这些事把效率拖垮。
你可以把微服务理解成一条食品加工流水线。一个十人的小作坊,一个人从头到尾做好一整锅卤味,是最省事、最灵活的。硬要把它拆成十个工位——一个人洗菜,一个人切菜,一个人调味,一个人打包——结果只会是每一站都在等人、传话和交接,整个产出效率反而更低了。只有当产量大到一锅卤味根本供不上的时候,流水线拆分工位才有意义。
2.2 从官方定义反推真正的适用条件
微服务的经典定义里有几条关键描述:围绕业务能力组织服务、自动化部署、去中心化管理、轻量级通信机制。这些字眼单独拎出来看都很有道理,但在实际落地时,每个词都对应着一套严苛的前提。
先说“围绕业务能力组织服务”,这意味着团队的沟通结构和业务模块的边界必须清晰。如果连业务模块的边界都画不清楚,两个团队对同一个客户概念的认知都不一致,那服务边界注定会变成一团乱麻。再说“自动化部署”,它意味着完善的基础设施支撑——持续集成流水线、环境管理、监控告警、日志采集、链路追踪,一样都不能少。最后说“轻量级通信机制”,看似简单,但通信链路一旦拉长,你马上会遇到超时重试、幂等、分布式事务、数据最终一致性这一整套问题。
把这些前提翻译成大白话就是:**你需要的不是微服务,而是能够支撑微服务运转的能力体系。**这个能力体系包括成熟的工程团队、完善的基础设施、清晰的组织边界和经过验证的运维体系。当一个团队具备这些条件时,微服务才能发挥它该有的作用。如果没有,那拆分再多服务,也只是把单体的问题复制了N份,然后加上分布式的复杂度。
2.3 什么样的系统真的需要微服务
聊完理论,说点实际的。我根据自己的观察总结了几个相对靠谱的判断信号,如果一个系统满足其中大部分,那确实可以考虑微服务架构。
第一个信号是模块之间的变更频率差异足够大。比如说核心交易链路一个月才发一次版,而营销活动模块三天一个小版本、一周一个大版本,这种情况下把它俩揉在同一个仓库里,确实会互相牵制。这种节奏差才是拆分的正当理由。
第二个信号是某个模块的资源消耗特征明显异于其他模块。比如一个图片处理服务,CPU密集且高负载,而其他业务模块是IO密集和低负载。这种场景下,把图片处理独立成服务才有独立伸缩的意义。
第三个信号是团队组织结构已经相应成型。比如系统已经有了清晰的业务组划分,每个组有完整的产品、研发、测试角色,且各组之间就接口达成过实际的协作共识,那微服务的落地难度会大大降低。反过来,如果仅仅是想着把代码拆开,团队还是那一拨人、还是同一个汇报线,那大概率拆完还是会因为“反正都是一拨人”而逐渐腐败,最终和在单格里也没什么本质区别。
3. 被误解的单体:它没有你想的那么不堪
3.1 单体的真正优势是“省事”与“一致”
很多人对单体架构嗤之以鼻,觉得它是历史遗留问题、技术债的代名词。这种印象不能说毫无根据,但对单体也不公平。单体架构最大的两个优势——简单和强一致——在绝大多数中小业务场景下,恰恰是比什么都重要的东西。
简单意味着低门槛。新同学上手快,遇到问题排查路径短,不需要跨服务追链路;改动影响范围容易评估,出问题回滚也方便。强一致意味着业务正确性好维护。数据库事务保证要么全成要么全败,不需要额外写补偿逻辑,业务代码写起来就是用自然语言描述业务规则,而不是处理分布式协调的边边角角。
我参与过一个传统行业的信息化改造项目,业务本身的流程并不复杂,但涉及后端的逻辑判断非常多,一张单据从创建到完成要经过十几步状态流转。这种系统如果用微服务来做,状态机要拆到多个服务里,跨服务的状态同步、并发控制、数据一致性,这些问题的写代码量比业务逻辑本身还多。最后我们选的就是一个大单体,把所有状态机逻辑放在同一个服务里,配合一套本地事务,整个系统稳稳当当运行了三年,几乎没出过生产事故。
3.2 你不一定需要微服务,但你需要“模块边界”
那是不是说单体就永远不用做任何结构化设计了?也不是。我见过很多单体系统走到另一个极端:所有代码堆在一起,没有分层,没有边界,app包下面直接挂一堆业务类,方法一多就一团乱麻。这种“大泥球”让维护它的人痛苦不堪,于是大家把这笔账算在了“单体架构”头上,说单体不可维护,还是得拆微服务。
其实错的不是单体,而是这个系统已经腐朽到根本谈不上“架构”了。一个合格的单体,内部应该有清晰的模块划分,模块与模块之间通过接口通信,依赖方向明确,不搞循环调用。这种风格在业内有个词叫“模块化单体”。它的实践思路是:在代码层面为将来可能的拆分预留好清晰的物理边界,但在部署层面依然保持一个可运行的单元。
模块化单体的好处是它两头都不吃亏。对内,模块边界清晰,同事之间不会互相踩脚;对外,整体部署和单体一样简单,不需要分布式基础设施,不需要处理网络调用和数据一致性问题。等哪天某个模块的独立伸缩需求大到真的忍不了了,再把它单独抽出去部署也不迟,因为边界已经画好了,抽出去的改造成本远比从大泥球里拆要低。
3.3 坚持“不拆”也是一种需要勇气的选择
我记得有一个阶段,不管什么项目做到后期,总有人会问一句:这块要不要拆成微服务?尤其是新来的同事,特别喜欢拿这个刷存在感。但真正负责过线上系统的人应该明白,做架构决策最怕的不是“选错”,而是“反复”。
如果一条核心支付链路在单体里已经稳定跑了两三年,你不要因为没有用微服务就觉得自己落后;如果你评估下来拆分没有带来任何用户可以感知的收益,那按兵不动就是最理性的选择。不动,就是最大的确定性。微服务不是一套“上了就高级”的架构,它是为特定类的复杂问题准备的解决方案。没有那个复杂度,就没有用它的必要。
4. 理性选型决策表:五个问题告诉你该走哪条路
4.1 一张可以“抄作业”的评估流程
为了不让这篇分享停在“既要又要”的务虚层面,我给自己和团队设计了一套选型评估表,按顺序回答下来,方向基本就清楚了。分享给你做参考。
问题一:团队有多少人?后端加上运维,少于十个人,不建议碰微服务。因为每个服务的创建、部署、监控、排障都要占用人的时间,人少了运转不起来。如果是十到二十人,可以考虑渐进式拆分,先只拆最合适的模块。超过二十人且有清晰的组织边界,才谈得上全量微服务。
问题二:业务模块的变更频率差异大不大?如果所有业务模块的发布节奏都差不多,比如都是一个星期一版,那拆分带来的最大好处“独立发布”就基本不存在。只有当有些模块按周发、有些按月发,且这个月更模块完全不关心周发模块的内容时,“独立发布”才有真实价值。
问题三:模块之间的数据耦合强不强?这是很多人容易忽略的硬指标。如果A服务和B服务虽然代码分开部署了,但数据库还是同一个,各自业务直接读写同一张表,那这个拆分就是假拆分。数据层面的强耦合不解决,服务拆得再漂亮,依然是单体,而且比普通单体更难维护。真正的服务边界必须包含数据边界。
问题四:你们有完善的基础设施吗?配置中心、注册中心、链路追踪、日志聚合、监控告警、CI/CD管道,这些工具链缺任何一项,微服务的日常运维都会非常痛苦。硬件可以买,但这些工程能力和配套工具的搭建成本,是很多人选型时容易忽略但后期找补起来代价极高的一笔账。
问题五:组织架构能跟上吗?如果的团队还是所有模块的人混在一起,没有明确的owner分工,那微服务的代码边界很快就会被频繁的跨模块需求侵蚀。微服务的最佳实践是“康威定律”在起作用:系统架构会和沟通结构同构。沟通结构不调整,光调代码是不行的。
4.2 不同答案组合下的推荐方案
把上面的答案组合起来,大致可以得到下面几个方向:
| 团队规模 | 模块变更频率差 | 数据耦合 | 基础设施 | 推荐方向 |
|---|---|---|---|---|
| <10人 | 小 | 强 | 不完善 | 模块化单体,别拆 |
| 10-20人 | 中等 | 中等 | 基本具备 | 渐进式拆分,只拆1-2个边界最清晰的模块 |
| >20人 | 大 | 弱 | 完善 | 可以按业务域完整落地微服务 |
| 任意 | 大 | 强 | 任意 | 先做数据解耦,否则任何拆分都白搭 |
这张表没有覆盖所有情况,但大方向是明确的。核心逻辑就一条:如果拆分的直接收益(独立部署、独立伸缩、独立发布)在你当前的场景里不被需要,那么拆分带来的成本就全都是纯损耗。
4.3 渐进式演进:大部分团队的最优解
如果你的系统已经跑了不少业务,又确实有很多迫切的模块独立需求,那最稳的路线不是“大爆炸式”重构,而是渐进式地拆。
我的建议是先从一个“新功能”下手。找一个和现有核心链路关系不那么紧密的新业务模块,从最开始就独立成服务,让它走自己的数据库、自己的接口、自己的发布流程。这样团队可以完整地走一遍微服务的开发、部署、联调、监控流程,把基础设施和团队习惯都盘活了,而旧系统还没受任何影响。
等这条“试验链路”跑顺了,团队对微服务的“手感”建立了,再去挑选真正有拆分收益的老模块慢慢迁移。迁移优先级参考这几个原则:边界清晰优先于耦合复杂的、异步非核心优先于强一致核心的、低变更风险优先于高变更风险的。按这个顺序走,过程中每一步都稳,团队心里也有底,不会因为一次大翻车而对架构方案完全失去信心。
5. 已经在微服务坑里的,怎么科学止损
5.1 过度拆分的常见信号
有很多团队上了微服务的车之后,其实日子并不好过,但碍于沉没成本又不敢下来。如果你不确定自己是不是处在“不该拆但拆了”的状态,我列几个信号,你可以对照一下。
第一个信号:日常开发中高频出现跨服务联调。每写一个功能都要拉上两三个别的服务的同事开会对齐接口,一次功能要分到好几个服务里各自写代码,联调一个星期的场景开始变得常态化。
第二个信号:数据一致性代码比业务代码还多。对账、补偿、重试、幂等判断……这些和业务本身没关系的代码占据了你大部分的工作量,而你根本说不清到底哪部分代码在真正产出业务价值。
第三个信号:一个“事务”要经过五六个服务。用户下单一次,背后是用户服务、商品服务、库存服务、订单服务、支付服务五个服务轮番调用,任何一环超时都让用户看到失败页,然后你又得用各种手段去补偿和修复。
第四个信号:发布一个功能需要多个服务同步上线。改进一个涉及多模块的功能,A服务改了接口、B服务改了逻辑、C服务改了数据结构,结果必须掐着点一起发版,否则就线上错乱。这就等于把单体的发布耦合原样带回了微服务,但多了一层分布式复杂度。
如果你命中了两个以上信号,说明当前的拆分模式并没有帮你解决实际问题,反而是制造了新的问题。这种时候不需要犹豫,该合并就合并。
5.2 服务合并的实操策略
服务合并不是什么丢人的事。我第一次参与合并服务的时候也有点压力,觉得这是把之前的“技术成果”给推翻了。但后来想通了:做工程不是做收藏,不是看你有多少件精美的瓷器,而是看你能不能把东西做出来、跑得稳。合并掉该合并的服务,是为团队减负,是止损,不是退步。
实操层面,合并可以分三步走。第一步先把数据层统一,多个服务如果有各自的小库但共享业务逻辑,优先把数据源收敛到一个主库,代码里先做到共库不共表;第二步再把无状态的服务逻辑合并到一个部署单元里,接口层还是保留原有路径,让上游服务无感知;第三步等稳定跑一段时间后,再去清理内部的重复逻辑和死代码,逐步收敛成真正干净的模块化单体结构。
这个过程不需要一步到位,尤其是线上业务,稳字当头。每并一个服务都要像拆一个服务一样谨慎,做好灰度、做好回滚方案,让流量逐渐平滑切换。
5.3 把目光从“架构风格”移回“业务价值”
最后想聊一个更本质的东西。很多团队在做架构选型的时候,讨论的其实不是“业务需要什么”,而是“什么技术听起来更高级”。这个倾向非常危险。
架构永远不是目的,架构是服务于业务的手段。如果你的业务还在验证期、还在快速迭代期,那最好的架构就是让你改得快、试错便宜、不拖后腿的架构。如果你的业务已经稳定增长,那最好的架构就是让你睡得着觉、线上不出事的架构。技术栈是不是微服务、用的是哪家的容器编排、有没有服务网格,用户根本不关心,也不该被放到决策的最高优先级上。
我在做技术决策的时候,现在习惯先问三个问题:这个改动用户能感知到什么价值?这个架构调整是降低了团队的协作成本还是增加了?如果明天要加一个新功能,这个架构能不能让我们做得比原来更快?这三个问题各想一遍,很多选型的答案其实自己就浮出来了。
写在最后的一点个人体会
调了这么多年架构,我最大的变化是变得“保守”了。以前看到新东西就想试,现在会先算成本。微服务确实是解决复杂系统问题的重要手段,但它不是银弹,更不是技术能力的勋章。
如果你正在为选型纠结,我的建议是,不妨把“要不要用微服务”这个问题,替换成“当前团队面临的最大瓶颈到底是什么”。瓶颈是人手不够,那微服务帮不了你;瓶颈是某个模块需要独立伸缩,那微服务可以帮你解决;瓶颈是代码太乱没法维护,那先把单体内部的模块边界理清楚,见效一定比拆分快。
架构选型这条路,从来没有标准答案,只有适合与不适合。能拍板说“我们这里不用微服务”的人,和对微服务有深刻驾驭能力的人,同样值得尊敬。多数情况下,我反而觉得前者更清醒。