
“为什么需要微服务”这个问题几乎每隔一段时间就会在开发群里被重新翻出来一次。有意思的是问这个问题的人往往已经看过一遍微服务架构图听过一遍“高并发、高可用、分布式”的宣讲甚至能背出注册中心、配置中心、网关这些名词。但真要他解释“自己所在的项目到底为什么要拆”或者“拆了之后具体多付出了哪些成本”他又说不太清楚。这不是个例。很多团队上微服务并不是因为业务复杂度到了那个临界点而是因为微服务听起来像“更先进”的架构很多团队犹豫要不要上微服务也不是因为单体真的还能撑住而是被分布式系统的各种坑吓住了。这两类判断其实都偏离了问题本身。所以我想把“为什么需要微服务”这件事重新拆一遍不是从架构图出发而是从一个更实际的角度单体应用到底在什么时候会成为真实瓶颈拆成微服务到底换来了什么、付出了什么以及哪些团队其实根本不应该急着拆。1. 先搞清楚微服务真正解决的是哪一类复杂度先给一个偏个人的判断微服务真正解决的不是性能问题不是代码量问题甚至不是技术问题而是组织协作和持续交付的复杂度问题。它让一个大型软件系统从“一个团队、一个仓库、一个进程、一个发布节奏”变成了“多个团队、多个仓库、多个进程、多个发布节奏”从而避免团队之间的相互拖累。1.1 多数人把微服务当作“架构升级”但它更像“组织协作升级”如果只看技术名词微服务很容易被理解成一种“更高级的单体”好像只要把代码拆到多个服务里再把服务注册到注册中心系统就自动变强了。但实际情况不是这样。微服务的本质是把系统按业务能力切成多个可以独立开发、独立部署、独立扩展的单元。这个“独立”两个字才是关键。为什么需要独立不是因为一个服务跑不起来而是因为当团队规模变大、业务模块变多时一个共享进程里的任何改动都可能拖住所有人。举一个很常见的例子。一个电商单体应用里订单模块、用户模块、商品模块混在同一个工程里。订单团队想要上线一个功能但用户团队同一天也有发布。因为发布窗口有限两边只能排队。如果某个模块出现线上问题整个进程要回滚所有没问题的模块也得跟着一起等。这种“互相拖累”不是靠写更好的代码能解决的它是一个进程边界带来的物理限制。微服务要拆掉的就是这种“所有模块都在一个进程里共命运”的耦合。1.2 单体不是起点也不是敌人很多人把单体和微服务对立起来好像单体是落后的、微服务是先进的。这个对立本身就有问题。大部分优秀系统都是从单体开始的。单体架构在最早期恰恰是最合理的架构。业务不复杂、团队小、需求变化快一个进程里什么都放开发效率最高调试最简单部署最方便没有任何分布式带来的额外成本。让一个只有五个人、业务还没验证完的团队直接上微服务等于让一个小公司一开始就按大集团的编制设置部门只会增加沟通成本和管理成本不会带来任何收益。所以更准确的理解是单体是一个系统的默认起点微服务是当某种复杂度超过单体能承受的范围之后才需要考虑的结构调整。它不是一个绝对更优的选择而是在特定规模、特定协作方式下更合适的选择。如果从这个角度看“为什么需要微服务”这个问题就变成了另一个更准确的问题我们的组织协作和业务复杂度是否已经到了单体应用难以支撑的阶段2. 单体应用什么时候会变成真实的瓶颈要判断要不要拆先得明白单体在什么情况下会真正变成瓶颈而不是在想象中变成瓶颈。2.1 不是代码量让你崩溃而是“多人同时改一个进程”很多团队把“代码量太大”当成拆微服务的理由这个理由其实不那么成立。一个十万行甚至几十万行的单体工程如果模块边界清晰、测试完善、发布流程规范完全是可以长期维护的。代码量本身不是罪罪往往在于所有代码共享一个进程所有团队共享一个发布节奏。真正的痛感通常出现在这样几个场景里一个服务有上百人同时提交代码合并冲突频繁每次发布要协调多个团队的时间窗口。某个模块一上线就出问题为了回滚其他模块的新功能也被迫延迟。某个模块流量突然上涨但因为所有代码都在同一个进程里无法单独给这个模块扩容只能整体把整个应用扩容。数据库表之间互相耦合一个团队改了表结构另一个团队的程序就崩了。编译、构建、测试时间越来越长一次发布从几分钟变成几十分钟甚至更久。这几个场景的共同点都不是“代码写得多”而是“团队之间的协作成本已经超出了单进程的边界能承受的范围”。2.2 最容易感受到痛的三类场景从实际经验看单体应用真正变得“难用”的临界点通常落在三类场景里。第一类是发布节奏互相拖累。两个团队各自半个月发布一次只要发布窗口撞在一起必然有一方要等。如果系统里有一两个高风险的模块全组人还要陪着一起承担回滚风险。第二类是资源无法独立扩容。对一个电商系统来说大促期间流量压力最大的往往不是所有模块而是商品浏览、购物车、订单等少数几个核心链路。单体应用只能整体扩容等于为了一两个热点模块把整个系统都拉高配置成本高而且不精准。第三类是故障边界模糊。单体进程里所有模块共享同一个内存、同一个进程、同一个日志目录。某个模块发生内存泄漏可能整个进程都挂掉某个模块出现慢查询可能拖垮整个数据库连接池。用户看到的是“系统挂了”但排查时要翻遍所有模块的日志才能找到根因。这不是不能排查而是排查成本随着模块数量增长越来越不可控。2.3 判断拆分的几个信号基于这些场景一个比较实用的判断方式是不要凭感觉判断要不要上微服务而是观察自己团队是否已经频繁出现下面几个信号。单次发布的协调成本已经大于服务拆分的维护成本。不同模块的运维需求、扩容需求、发布频率已经明显分化。团队的职责边界已经清晰到可以按照业务模块划分。某一个模块的故障频繁导致其他无关模块不可用。团队人数和模块数量已经大到让同一个仓库内的协同变得低效。这些信号越多说明单体的结构化瓶颈越明显。反之如果这些场景都还没出现那微服务大概率不是当前最需要解决的问题。3. 拆成微服务你换来了什么又付出了什么微服务不是免费午餐。它更像一笔交易用分布式系统的复杂度置换组织协作和独立扩展的能力。这笔交易值不值取决于你的组织协作成本是不是已经高过了分布式系统的复杂度成本。3.1 换来的独立发布、独立扩容、独立故障边界拆成微服务之后最直接的变化是进程边界变多了。每个服务可以有自己的仓库、自己的发布流程、自己的回滚策略。订单团队要上线不需要等用户团队用户模块的日志和内存出了问题不至于让整个系统都跟着重启。扩容也变得更精准只需要给热点服务增加实例不用把所有模块都拉起来。这一点对大型团队尤其重要。当一个系统需要几个团队并行开发而每个团队都有自己独立的产品节奏时微服务的组织价值往往大于技术价值。它把“技术上能不能改”变成了“组织上能不能互不干扰”。3.2 付出的网络调用、分布式事务、可观测性成本但代价也是实打实的。模块之间的通信从本地方法调用变成了网络调用。本地调用失败了就是异常网络调用失败了可能是超时、可能是网络分区、可能是对端服务已经挂掉。你需要考虑超时时间设置、重试策略、熔断降级需要处理幂等需要防缓存穿透和雪崩。这些在单体应用里基本不需要关心。数据一致性更是重灾区。单体应用里多个表之间的数据一致性可以通过同一个数据库事务来保证。拆成微服务之后每个服务往往有自己的数据库跨服务的数据一致性不能再用本地事务解决只能依靠分布式事务方案。而分布式事务无论选哪种方案都会带来额外的复杂度两阶段提交性能不好TCC 实现成本高本地消息表和最终一致性需要额外的补偿机制。这些都是实实在在的开发和运维成本。还有可观测性。单体应用排查问题打开日志文件从头翻到尾基本就可以了。微服务架构里一次用户请求可能要经过网关、认证服务、订单服务、支付服务、库存服务日志散落在十几个服务、几十台机器上。链路追踪、trace ID、集中日志、监控告警这些都不是可选项而是必须从一开始就建设的基础设施。没有这些微服务拆完之后会变成大型猜谜现场。3.3 一个容易被忽略的成本团队心智负担技术成本之外还有一块容易被忽略的隐性成本那就是团队心智负担。在一个单体应用里一个开发人员基本上可以靠本地启动整个系统改一行代码跑一个进程就能验证结果。微服务架构里本地往往很难启动完整环境至少需要依赖注册中心、配置中心、网关还有一堆下游服务的 mock 或者测试实例。代码写完了提交之前先要确保本地环境能跑起来。出了问题要沿着调用链路一层一层排查。这些工作不是不会做而是每一项都在消耗注意力和时间。如果团队里的人员流动率比较高微服务的认知成本还会被进一步放大。新成员要理解的不再是一个软件系统的数据流而是几十个服务之间的调用关系、每个服务的归属团队、每个团队的发布流程。这种复杂度不会因为你画了漂亮的架构图就消失。4. 为什么很多项目其实不需要微服务说到这你可能已经感觉到了我的倾向微服务不是银弹甚至对很多项目来说它是个陷阱。这不是说微服务不好而是说它有自己的适用边界。4.1 什么时候强行上微服务等于给自己挖坑如果出现下面这些情况我通常不建议引入微服务团队人数不超过二三十人甚至更少。业务处于快速验证阶段需求变化远大于规模变化。系统在线用户量、数据量、并发量都还没有到必须水平扩展的程度。团队里没有人对分布式系统的运维有充足经验也没有专门的 SRE 或运维支持。公司基础设施薄弱没有配套的监控、日志、链路追踪、CI/CD 平台。在这些条件下一股脑拆微服务结果往往不是架构升级而是开发效率断崖式下降。所有本来十分钟能完成的联调被拆成了跨服务的排查所有本来一次事务能解决的写入要绕一圈最终一致性所有本来简单的本地调试变成了环境管理噩梦。业务节奏快的时候这种额外成本是致命的。4.2 先问四个问题在真正动手拆分之前可以给自己和团队做一个快速自测回答四个问题就够了。第一个问题系统是不是真的出现了频繁的、跨团队的发布阻塞如果只是流程不顺先改流程如果改完流程还堵再考虑架构。第二个问题系统是不是存在无法独立扩缩容的模块如果整个系统没有局部热点整体扩容完全够用就没必要拆。第三个问题团队是否已经有清晰的模块职责边界代码本身就纠缠不清、团队职责横跨多个模块拆完服务只会让边界问题变得更难改。第四个问题公司是否具备微服务所需的运维和可观测性能力这不是问“有没有听说过”而是问“能不能在两天内排查一条跨服务失败链路并定位根因”。如果这四个问题里有一个不满足都应该暂时停止拆分计划先把缺的那块补上。4.3 中小团队推荐的渐进式路径对于中小团队我比较推荐的一种路径是先保持单体但把模块边界划清楚。也就是说在单体工程内部用 module 或分层设计把业务模块隔离好禁止跨模块随意引用私有内部类数据库表也按模块归属明确划分。这样就算暂时不拆成微服务团队之间也能减少很多耦合。等业务真的到了需要独立发布、独立扩容的阶段再顺着提前画好的模块边界逐步拆出服务这个过程的成本会低很多。很多团队最后成功拆成微服务并不是因为他们一次性重写了架构而是因为单体阶段就已经把边界控制得足够好拆分只是顺着边界把进程切开来而已。反过来如果单体阶段就是“意大利面条式”的依赖关系那拆微服务等于在重构的同时给系统换骨架难度会成倍上升。5. 微服务落地时最容易出问题的地方如果已经确认业务确实需要微服务并且在征求团队意见后也决定开始拆分那接下来要面对的就是落地过程中的具体问题。这里想重点聊几个真正会卡住人的地方它们通常不会出现在宣传稿里却会出现在上线后的第一个深夜里。5.1 服务拆分后先解决“链路排查”问题很多团队接入微服务的第一件事是搭网关、搭注册中心、搭配置中心这些当然要做但我更建议把链路追踪和日志采集也放进第一批建设清单而不是等到出了问题再补。一个微服务环境下最典型的故障场景是用户反馈下单失败你登录服务器发现订单服务日志里没有任何异常支付服务日志里也没有异常库存服务日志里更是干干净净。然后你花了一个小时才发现问题出在订单服务调用支付服务时超时时间设置太短而支付服务本身只是因为网络抖动慢了一点点。这种问题的查错难度在于故障点不是“某一个服务坏了”而是“服务之间的配合出了问题”。没有全链路 trace ID所有日志都是孤立的只能靠人的脑补串起来。所以一旦确定要上微服务排查链路这件事一定要前置。排查时可以按一个固定顺序走先看入口网关是否有对应请求确认请求有没有到达系统。沿着 trace ID 找到这条请求经过了哪些服务节点。看每个节点的响应时间定位耗时异常的是哪一个跳转。看异常节点所在机器的 CPU、内存、磁盘、GC 日志确认是资源问题还是代码问题。再看依赖的下游服务、数据库、缓存、消息队列的状态。这个链路看起来简单但前提是日志里有 trace ID、每个服务都接入了统一日志平台、监控面板能看到服务之间调用的耗时分布。这些如果等到出问题了再补会非常被动。5.2 数据一致性不是靠“改代码”解决的微服务落地里最容易产生争论的是数据一致性方案。有的人觉得用分布式事务框架就行有的人觉得最终一致性就好有的人觉得直接把所有数据放同一个数据库最省事。这些选择其实没有绝对的对错关键是要想清楚自己业务对“一致性窗口”的容忍度。比如库存扣减和订单创建。如果订单创建之后库存扣减失败用户会看到订单状态和实际库存不一致。你可以选择本地消息表配合消息队列做最终一致也可以选择把库存扣减和订单创建放在同一个事务边界内用 TCC 或者可靠消息。不管选哪个都要为这个选择付出额外的代码量和测试成本。我见过的一个比较稳妥的做法是尽量把需要强一致的数据留在同一个服务边界内不要为了服务拆分的“纯粹性”把天然高内聚的数据强行拆到两个服务里。有些聚合是业务上必须一致更新的硬拆到两个服务里再靠分布式事务拉回来既增加了复杂度也没有带来独立部署的收益。服务拆分的单位应该是业务能力而不是建表逻辑。5.3 开源脚手架带来的误区现在很多开源脚手架比如以“若依微服务plus”为代表的一类后台管理系统已经帮你把网关、认证、用户、菜单、日志这些基础模块都搭好了。对想要快速搭建业务系统的团队来说这类脚手架确实能省不少事。但这里要留个心眼。脚手架的价值在于“把常见基础设施预置好”不代表“你的系统结构自动合理了”。很多脚手架里不同服务之间依然有隐式依赖认证信息可能放在共享 Redis 里基础数据服务被很多业务服务共同调用。一旦业务复杂起来这些公共模块会成为新的瓶颈点改动风险会被放大。更关键的是脚手架里的代码往往比较复杂新手团队直接用它很容易在遇到问题时不知道该改哪里、哪些配置能调、哪些默认行为不能动。我建议使用脚手架时先把它当作参考工程跑通理解它的模块划分和启动流程有精力的话再逐步替换成符合自己团队习惯的实现。把陌生方案消化成自己理解的东西比直接跑起来重要得多。5.4 微服务面试题的表面与实质从“微服务面试题”这个热搜词也能看出很多开发者学习微服务最初的动力其实来自面试。面试官问“为什么需要微服务”时通常不是考你三个优点再加两个缺点而是想看你有没有真正做过架构层面的取舍判断。如果只是背答案可以说“微服务可以做独立部署、独立扩容、技术栈异构、故障隔离”。但面试官追问一句“你们是为什么拆的拆了之后遇到过什么坑”如果答不上来前面的名词列表反而会暴露经验的缺失。比较好的回答方式是从自己实际经历的一个痛点切入。比如当时因为订单和用户两个模块放在一起每次订单改动都要带着整个系统回归测试我们于是把订单服务独立出来。拆了之后才发现需要重新解决日志链路、分布式事务和跨服务调用超时的问题。然后按这个思路讲清楚拆分前的问题、拆分后的收益、踩过的坑和现在的方案。这种回答比罗列概念有说服力得多。6. 建立你自己的微服务判断框架聊到这里“为什么需要微服务”这个问题其实没有一个固定答案。它取决于你的团队规模、业务阶段、基础设施和运维能力。但我可以把整个思考过程收敛成一个可以复用的判断框架你以后遇到相关问题时可以直接套用。6.1 一张判断表而不是一堆概念这张表不一定适合所有场景但至少能帮你从一堆概念里跳出来回到问题本身。判断维度单体适用微服务适用团队规模小团队、单团队多团队、多职责线发布频率低频、可统一窗口各模块节奏差异大模块耦合度边界模糊、可容忍边界已清晰、需要独立演进流量模型整体均衡、整体扩容可行存在明显局部热点故障影响可接受全量回滚需要故障隔离和独立降级运维能力依赖少、人工可控有监控、日志、链路追踪基础业务阶段快速验证、需求变化大模式已验证、需要长期迭代扩展判断的规则很简单如果多个维度都落在左侧就继续用单体如果多个维度都明显落在右侧再考虑微服务。如果一半一半那就先做模块解耦暂时不要拆分进程等真正的一两个硬指标出现后再拆。6.2 一个从单体到微服务的可执行路径确定了要拆分之后不要一上来就追求“全公司所有系统完成微服务化”更可行的方式是分步走从单体工程里先划模块边界和数据库归属明确哪些数据归哪个模块管。把模块之间的调用改为接口调用先在单体内部模拟服务间调用方式。选一个业务上独立性强、团队归属清晰、发布压力最大的模块先拆出来单独部署。观察拆完后的效果发布是否更快、故障定位是否更容易、扩展是否更灵活。跑通一个服务后再逐步复制这套模式去处理其他模块。这条路比“半年内全部拆完”那种大计划靠谱得多。每一步都能验证风险和收益团队也能逐步积累分布式系统的运维经验。6.3 最后说一点长期视角微服务和单体不是二选一的终点而是一个不断演进的过程。有些团队为了追求微服务的“纯正性”把服务拆得特别细结果引入了一堆分布式复杂度也有些团队一开始坚定使用单体等到业务真的变大之后再顺势拆出两三个服务反而走得比较稳。我自己的体会是架构选型最重要的一课不是“微服务更先进”而是“复杂度不会消失只会转移”。单体把复杂度集中在代码内部微服务把复杂度扩散到系统协作和运维层面。你能做的是判断当前阶段自己能更舒服地承担哪种复杂度然后做出选择同时为将来可能发生的变化留好调整空间。所以回到开头的那个问题。如果你问“为什么需要微服务”我的回答会是不是因为微服务是趋势也不是因为别人都在用而是因为你的业务和组织协作已经走到了单体难以支撑的那一步。到那时候微服务是一种代价清晰、边界明确的路径。如果还没到那一步先好好打磨单体把模块边界理清楚把自动化测试和发布流程做扎实说不定到时候你会发现自己并不需要一场伤筋动骨的重构。