大家好,今天我们再来来聊聊微服务。
几年前,微服务几乎是每位架构师挂在嘴边的“最佳实践”,不管业务规模如何,不搞微服务仿佛就落伍了。我此前也写过一篇文章,讨论为何要做微服务架构:
但近两年,情况正悄然发生变化。Amazon、Twitter、Shopify、Uber 等头部公司陆续开始回归单体架构,技术社区的讨论也逐渐从盲目推崇走向更为冷静的思考。
怎么大家开始又不搞微服务了?是微服务不好吗?上面那篇文章的做法过时了吗?本文我将详细说明下。
对于多数处于探索期或快速发展期的团队来说,速度、稳定性与开发效率往往比服务拆分更重要。
本文将结合多个真实案例与技术背景,系统剖析微服务的常见误区与适用边界,并给出一种更稳妥、更现实的架构路径。
1. 为什么大家对微服务趋之若鹜?
如果你向一位刚接手系统的技术负责人询问架构设计,常常在聊到业务之前,就会听到“微服务”这个词。微服务架构似乎早已成为现代系统设计的默认选项,但这种选择,并不总是基于理性的判断。
许多团队相信,系统一旦需要扩展,就必须采用微服务架构。这个观点听起来合理,但现实往往更为复杂。当部署一次服务需要 40 分钟,当接口兼容性频繁引发通信故障,当团队将大量时间花在排查分布式追踪 ID,而非交付业务功能时,扩展性不仅没有提升,开发效率反而显著下降。
那么,为什么微服务受到如此多团队的青睐?
1.1 技术趋势的影响力
1.1.1 微服务的盛行
很多时候,这种架构选择并非基于具体需求,而是受到行业趋势的驱动。常见的路径大致如下:
一个团队从单体架构起步,系统运行良好,但随着业务增长,逐渐遇到瓶颈。此时,他们读到一篇关于 Netflix 或 Uber 如何成功迁移到微服务的文章,开始向这种模式倾斜,甚至将 Kubernetes 架构图搬上白板,作为解决当前问题的“标准答案”。
问题在于,这类案例往往难以复制。像 Netflix 这样的公司,每个服务背后都有一个专门的团队来保障其独立运行。而对于大多数工程团队来说,可能只有一两个开发者同时负责多个模块的开发与运维。在这种资源受限的现实下,照搬大型公司架构往往会带来更多负担,而非收益。
1.1.2 微服务的反思
在这种“大厂示范效应”之下,微服务曾一度风靡,但随着越来越多“回摆单体”的真实案例被披露,大家开始意识到:拆分并不是越多越好,过度拆分反而会带来以下沉重代价。于是大家又重新思考微服务架构的利弊,我这里列举了一些公司面对微服务带来的问题所做的应对措施:
公司 | 回摆原因 | 新架构/措施 |
---|---|---|
Amazon Prime Video | VQA 服务基于 Step Functions+Lambda 的无服务器微服务成本高、扩展瓶颈[1] | 重构为长驻容器化微服务(ECS 容器),成本↓90%,吞吐量显著提升 |
停用 ~80% “微服务 bloatware”导致 SMS 2FA 短暂中断 | 关闭冗余微服务,精简服务列表,恢复核心功能 | |
Uber | 上千微服务过度拆分,域间治理与调用链复杂[2] | 推行 Domain‑Oriented Microservice Architecture,按业务域分组中粒度服务 |
Shopify | 过度微服务导致维护与发布节奏放慢[3] | 采用模块化单体(Modular Monolith),组件化解耦,保持单一部署单元 |
服务过度拆分引发频繁调用与高延迟[4] | 引入 Domain‑Driven Services,将服务重组为中等粒度域服务 |
2. 微服务带来的代价
尽管微服务被视为现代架构的“标准解”,但在实际落地中,它引入的问题常常被低估。其中几个关键挑战尤为值得注意。
2.1 不易察觉的延迟成本
微服务的性能开销往往并不体现在单个服务中,而是出现在它们之间的调用链路上。以电商结账流程为例,多个服务分别承担购物车、库存、定价、税费、支付等功能,哪怕每个服务的处理时间只有十几毫秒,累加起来也轻易超过百毫秒。而这还未计入网络抖动、重试机制、TLS 握手等附加成本。
相比之下,将这些逻辑整合在一个进程内的单体架构,不仅调用延迟可忽略不计,还能简化调用链、提升稳定性。即便在高性能语言中,跨服务通信依然是明显的性能瓶颈。
以电商平台的结账流程为例,微服务架构下的各服务响应时间可能如下:
服务 | 延迟(毫秒) |
---|---|
商品服务 | 10 |
库存服务 | 18 |
优惠服务 | 12 |
税费服务 | 20 |
支付服务 | 45 |
安全校验 | 30 |
通知服务 | 14 |
总计 | 149ms |
这还没有考虑网络延迟、重试、TLS 握手等附加因素。
如果这些逻辑统一运行在一个单体应用中,结构可能如下:
1 | public OrderResult placeOrder(Order order) { |
逻辑相同,但所有调用都在进程内完成,避免了跨服务通信的开销,系统响应时间也因此显著降低。
2.2 部署与运维复杂度
微服务拆分带来的不是“轻量模块”,而是运维任务的指数增长。每个服务都需要独立维护构建脚本、部署模板、监控面板、访问控制和配置管理。一旦服务数量超过十个,团队就需要投入大量精力管理一个“迷你云平台”。
这类复杂度在早期阶段尤为突出。一些初创公司甚至表示,他们维护微服务花费的时间已远超新功能开发。
相比之下,单体应用只需一次构建和部署,回滚也简单直接,能有效降低发布风险和运维负担。
2.3 组织结构的不匹配
微服务本质上是一种组织形式的反映。根据康威定律,系统架构会趋向于复制团队的沟通结构。因此,只有在拥有独立职能团队的前提下,“每个团队负责一个服务”才可能成立。
但现实中,很多团队规模有限,开发、测试、运维资源紧张,却试图运营十多个微服务。最终的结果往往是服务无人维护、接口陈旧、告警静默、技术栈混乱,架构形同失控。
只有在你的组织结构支持的前提下,微服务才是合理的选择。
康威定律(Conway’s Law):系统的架构会趋向于复制组织的沟通结构。
如果你的团队结构是这样的:
- 1~2 名开发
- 1 名测试
- 1 名运维
- 1 名产品经理
那你根本没有能力去管理 20 个服务。
所谓“每个团队负责一个服务”的理想状况,在你没有专属服务团队时就注定会崩塌。
2. 4忽视上线效率
多数初创团队最需要的是一种快速响应的交付方式,而不是复杂的服务编排和异步通信系统。单体应用配合一个可靠的数据库,常常是最直接、最高效的选择。
但在盲目追求“现代架构”的趋势下,一些团队在早期就引入了 Kafka、RabbitMQ 等组件,将简单功能拆解为多个微服务,结果不仅上线周期拉长,稳定性也难以保障。
大多数早期创业公司真正需要的是:
但他们常常误打误撞地搭成了这样:
你猜哪个架构能更快部署上线?
在实际交付中,单体架构往往更有利于快速试错和持续迭代。相比复杂架构,稳定上线才是更重要的目标。
3. 应该如何做更合理?
3.1 先从单体构建
微服务是一种实用的架构模式,但它并不适用于所有场景。即便是微服务的支持者也指出,这种架构会带来不小的“溢价”成本(Microservice Premium),主要体现在服务治理、部署运维、系统协调等方面的额外开销。对于需求尚不复杂的系统,这种成本往往超过了其带来的收益,反而可能拖慢开发进度。因此,很多团队在面对新应用时,更倾向于从单体架构入手。
这也强化了“单体优先”的架构策略:即便预期系统未来可能发展为适合微服务的规模,也应优先以单体方式启动,待实际需要明确后,再逐步拆分。这种方式在初期能有效降低复杂度,提升迭代效率,更契合多数项目从小规模起步、逐步演进的现实路径。
为什么要先从单体构建?
选择单体架构作为新应用的起点,背后有两个关键考虑。
首先,是一种典型的 YAGNI(You Aren’t Gonna Need It)思维方式。在项目早期,往往无法确定某个软件创意是否真正对用户有价值。相比投入大量精力构建一个可扩展但复杂的系统,快速验证想法更为重要。一个架构不够理想但能被用户接受的产品,至少证明了方向成立;而一个设计精巧却没人使用的系统,则是更大的资源浪费。也正因为如此,初期更应优先追求开发速度和反馈效率,避免微服务架构所带来的管理开销。
其次,微服务的有效实施依赖于对系统边界的清晰划分,也就是合理的边界上下文(Bounded Context)设计。然而,定义这些边界并非易事,即便是经验丰富的架构师,在熟悉的业务领域也难以在一开始就划分出稳定、合适的服务边界。相比之下,从单体架构入手,可以让团队在一个统一代码库中逐步识别、验证这些边界,为后续拆分成服务提供更稳妥的基础。这也为满足微服务实施前提(Microservice Prerequisites)提供了必要的准备过程。
3.2 什么时候构建微服务?
先说清楚:微服务不是坏东西,它们只是常常被用得太早。
以下这些场景中,使用微服务是有充分理由的:
只有在以下场景同时成立时,采用微服务才真正值得:你的组织已经拥有多个自治团队(通常意味着团队规模已超 50 人),每个团队可以独立负责一个或多个服务;你的系统中存在职责高度分离、部署和技术栈迥异的子域,例如计费与搜索模块需要独立节奏;部分子系统对吞吐或性能具有极高需求,需要单独扩展支持;以及必须处理敏感数据或合规要求(如 PII),需要隔离日志、加密和审计边界。在这些条件不具备的情况下,从模块化单体出发,保持简单与灵活性,往往比过早引入复杂的微服务架构更加可靠
3.3 如何迁移到微服务?
“单体优先”并不意味着放弃未来的演进空间,关键在于如何为可能的迁移做好铺垫。在实践中,团队通常会采用不同策略,将单体架构逐步过渡到微服务。
一种较为稳妥的做法,是在设计单体应用时就注重内部的模块化,明确各模块的 API 边界和数据访问方式。通过有意识地控制耦合和划分责任,这类“结构良好的单体”在需要拆分时能更顺利地演进为微服务体系。虽然这种方法听起来理想,但是大量遗留系统并不会做的这么理想化,而是一堆意大利面条式的代码块,也许给他取个中文名更好,类似炒粉。
更常见的策略,是从单体应用入手,在后续演进中逐步将部分功能以微服务的形式向边缘剥离。这种方式往往形成一个“核心单体 + 周边微服务”的结构:核心系统保持相对稳定,而新功能、新需求则通过微服务来扩展,降低对主系统的干扰。
还有一种较激进但现实的方式,是将初期的单体应用视为一种“牺牲式架构”(Sacrificial Architecture),即接受它未来会被完全替换的命运。在这种策略下,单体应用的主要价值在于帮助团队快速推向市场、验证需求。一旦业务模型和服务边界更加清晰,再基于已有经验重构为更合理的微服务系统。这种方法强调的是节奏优先,而非一开始就追求“完美架构”。
3.4 不用微服务,你也能实现模块化
构建单体应用并不等于写一堆意大利面条式的耦合代码。糟糕的单体(如完全耦合、缺乏分层)一样会导致“技术债地狱”,不是说不拆服务就一劳永逸了。可以先通过领域建模、限界上下文划分,再结合技术指标和团队能力逐步演进。
比如可以采用如下模块化设计:
1 | /modules |
每个模块都可以:
- 独立测试
- 拥有自己的限界上下文(Bounded Context)
- 在将来需要时再拆分成微服务
这正是 Martin Fowler 所称的 模块化单体(Modular Monolith)。Martin Fowler 提出的 Modular Monolith[5],是一种非常务实的折中方案。它允许你:
- 保持业务逻辑隔离
- 在早期快速开发
- 到达一定规模后有条不紊地拆分服务
这比一开始就上 Kubernetes、Istio、Kafka 要靠谱得多。
4. 真正该问的问题不是“我们需要微服务吗?”
而是:
“我们现在最需要优化的是什么?”
如果你的团队正处于这样的阶段:
- 产品方向尚未稳定,仍在持续调整
- 团队规模小,正在组建核心开发力量
- 每周都需快速迭代、持续上线新功能
那么你最需要关注的不是“未来可扩展性”,而是开发速度、系统简单性与上线效率。
在系统尚未成熟之前,过早引入微服务,只会增加复杂度,拉低交付节奏。
单体架构 vs 微服务架构 对比表
应用场景 | 单体架构 ✔️ | 微服务架构 ✔️ | 说明 |
---|---|---|---|
小型、简单应用 | ✅ | ❌ | 单体结构更直接,部署简单 |
团队资源有限(如早期创业团队) | ✅ | ❌ | 小团队更适合维护一个整体系统 |
运维复杂度要求低 | ✅ | ❌ | 单体更易于部署与监控 |
系统变化频率低 | ✅ | ❌ | 不常更新的系统无需微服务拆分 |
快速部署与频繁迭代需求 | ❌ | ✅ | 微服务适合独立模块快速上线 |
高可扩展性与故障隔离需求 | ❌ | ✅ | 微服务能按服务独立扩展与容错 |
技术栈多样化(不同服务用不同语言) | ❌ | ✅ | 微服务允许按模块选择最佳技术 |
产品或市场快速演变 | ❌ | ✅ | 确确的说微服务更适合那些已经完成领域划分、 需要大规模并行迭代、服务稳定复用、 团队足够成熟的系统在快速变化中保持灵活。 结构良好的单体系统,同样可以支撑产品在 早期实现快速演变,甚至更具效率和稳定性。 |
5. 总结
微服务不是问题的起点,也不是答案的终点。它是一种应对复杂系统演进的策略,但前提是你已经清晰理解了系统的复杂性本身。
太早采用微服务,就像在还没有稳定收入前提前背上房贷。表面上看似专业、前瞻,实则是在为一套尚未成熟的系统增加运维负担和组织压力。延迟控制、部署治理、接口演进、团队协作……这些“利息”一旦积累起来,足以让开发效率长期陷入低谷。
相比之下,把单体架构打磨扎实,让系统在早期具备清晰的结构和良好的可演化性,反而更能为将来的拆分打下基础。等到真正需要演进为微服务时,你也已经积累了足够的上下文和经验,能以更低的成本、做出更贴合实际的设计决策。我见过太多复杂的单体了,他们不是因为没实施微服务而导致复杂,本身上是没做好领域边界划分,没有任何业务模块化的划分,更多是技术上的分层架构,比如典型的三层架构,业务代码全部平铺在每层里面,最终导致难以维护的大型单体系统。
架构的选择从来不是“用不用微服务”的问题,而是“系统是否真的需要它”。保持理性,尊重阶段,是每一位工程决策者应有的判断力。
References
Scaling up the Prime Video audio/video monitoring service and reducing costs by 90%. Retrieved from https://www.wudsn.com/productions/www/site/news/2023/2023-05-08-microservices-01.pdf ↩︎
Introducing Domain-Oriented Microservice Architecture. Retrieved from https://www.uber.com/en-US/blog/microservice-architecture/ ↩︎
Deconstructing the Monolith: Designing Software that Maximizes Developer Productivity. Retrieved from https://shopify.engineering/deconstructing-monolith-designing-software-maximizes-developer-productivity ↩︎
Domain-Driven Services – Just the Right Size. Retrieved from https://www.architectureandgovernance.com/applications-technology/domain-driven-services-just-the-right-size/ ↩︎
Monolith First. Retrieved from https://martinfowler.com/bliki/MonolithFirst.html ↩︎