微服务架构和单体架构的区别:拆之前你得先想清楚这件事

0 阅读9分钟

大家好,我是晚安code。

这篇不讲「微服务是先进架构」那一套。我们从它到底解决什么问题讲起,说清楚微服务架构和单体架构的区别在哪、微服务能做什么又不能做什么,最后给你一条能直接照着用的判断线,帮你判断自己该不该拆。

点个收藏,我们开始。

一、微服务架构到底是什么?先别急着背定义

微服务架构(Microservices Architecture):把一套系统按业务边界切成多个能独立开发、独立部署、独立运行的小服务,服务之间只通过网络接口协作。你可以理解为「把一个大食堂拆成一条美食街」。

单体架构(Monolithic Architecture):整套系统的所有功能打包成同一个部署单元,一次构建、一次发布、一起上线。类比就是一个大食堂、一位总厨管所有档口。

这两个定义里,真正关键的字不是「小」,而是「独立」。很多人背完定义就只记住一个「拆」字,回去把代码按技术层拆成 controller 一层、service 一层、dao 一层——那不叫微服务,那叫把单体切碎了再拌一遍。

一个服务算不算真的独立,我一般看三条:

1)能不能独立部署:改了它的代码,只重启它一个,别的服务不用跟着发版。 2)数据归不归自己:它的库只有它能写,别人要数据只能走它的接口。 3)能不能单独扩缩容:它压力大的时候,只给它加机器,不用整包复制。

三条都满足,才算摸到了微服务的门。缺一条,你大概率只是给单体加了一层网络调用。

下面这张类比图:

左边是一个窗口出所有菜,右边是每家店只管自己那道菜——微服务拆的是边界,不是数量。

二、微服务架构和单体架构的区别,不只是「拆没拆」

微服务架构和单体架构的区别,从来不是「拆没拆」,而是「边界画在哪」——单体是一个边界装下所有事,微服务是每个边界只装一件事。

先看结构上的差别,一眼就能看明白:

微服务架构与单体架构的结构对比:单体共用一个数据库,微服务每个服务独占自己的库

左边是单体:Web 入口往下调用,所有模块在同一个进程里互相打招呼,底下共用同一个库。右边是微服务:所有流量先过 API 网关,网关按业务路由到订单、库存、用户三个服务,每个服务只写自己的库,需要别人的数据就发一次远程调用。

结构之外,两者的差别落在五个具体的维度上:

对比维度单体架构微服务架构
部署单元一个包,整体一起发布每个服务独立发布
数据归属一个库,所有模块共用每服务一个库,只能走接口访问
调用方式进程内方法调用跨网络调用
故障范围一个模块出问题可能拖垮整个进程单个服务挂了,其余可以降级
团队协作所有人改同一份代码各自仓库、各自排期,靠接口约定

这张表里,前三行是技术差异,后两行才是真正让人纠结的地方——它们说的其实是「组织」。

有个坑要说:很多对比文把「微服务更容易扩容」写成理所当然的优势。可你的单体如果本来就跑不满一台机器,扩容这件事你压根没遇到过,那这条优势对你就是零。

三、微服务架构能做什么?这四个能力才是它真正的卖点

微服务架构真正值钱的地方,不是它更「先进」,而是它能把一部分组织问题变成技术问题。

1、按需扩容,钱花在刀刃上

单体扩容是整包复制。秒杀把下单接口压满,你加三台机器,连同几乎没人用的报表模块也一起复制了三份。拆开之后,你只给订单和库存两个服务加实例,报表服务一个实例都不用动。

2、故障隔离,别让一个模块带走全局

单体的进程模型里,一个模块的内存泄漏或者线程池打满,整个应用一起完蛋。微服务里评论服务挂了,下单链路照常跑,前端把评论区降级成「暂时不可用」就行。

3、技术异构,老代码可以不动

这个能力被低估了。单体想换语言基本等于重写;微服务里那个跑了五年的 Java 老服务可以继续用,新做的推荐服务用 Go 或者 Python 起一个新的,中间加个接口约定就好。

4、团队并行,不用排队等发版

十个后端挤在一个仓库里,谁合并谁就得处理冲突,谁上线谁就得通知所有人。按业务边界拆成三四个服务、三四个小组各自发布之后,这个排队就消失了。这其实是大多数公司拆微服务的第一动机——不是因为技术,是因为人。

四、但微服务架构的缺点也在这里:它不能帮你做什么

微服务架构不会让你的代码变好,它只会让你的烂代码更难改——因为烂代码现在分散在五个仓库里。

先看最直观的一项。说个示例场景:一个下单请求,在单体里就是「下单接口调扣库存方法、再调写订单方法」,全在同一个进程内,加起来大约 20ms。拆成订单、库存、支付三个服务之后,同一个请求变成三次网络往返加一次跨服务事务,我按常见的内网 RTT 和重试策略推演过一版,P99 大概会涨到 200ms 上下——具体数字取决于你的网络和链路层数,但方向是确定的:机器没变慢,是调用变多了。

下单请求在单体与微服务中的调用链路对比:单体一次本地调用,微服务多次网络往返并需要跨服务事务

除了延迟,还有三笔账要算。

第一笔,分布式事务。 单体里一个本地事务搞定的事,微服务里要做最终一致:本地消息表、Saga、TCC,每一种都得你自己写补偿逻辑,而补偿逻辑本身就是 bug 高发区。

第二笔,运维复杂度。 单体上线是「把包传上去重启」。微服务上线要变成:服务注册与发现、配置中心、网关路由、链路追踪、日志聚合、健康检查——这些你得先有,才能拆。没有就硬拆,等于蒙着眼睛开车。

第三笔,排查成本。 单体查一个 bug 是看一份日志。微服务查一个 bug 是拿一个 trace id 在五个服务的日志里拼时间线,还得判断到底是网络超时还是业务逻辑错。

可能有人会问:那微服务是不是就是当年的 SOA?

不是同一件事。SOA 通常靠一个集中的企业服务总线(ESB)来做编排和协议转换,服务粒度粗、中心化重;微服务强调的是去中心化——每个服务自己管自己的数据和逻辑,网关只做路由不做业务编排。一句话概括:SOA 像总部统一调度,微服务像各家门店自负盈亏。

五、什么时候该用微服务?一条可操作的判断线

该不该拆微服务,看的从来不是技术栈有多新,而是你的团队规模和业务边界走到了哪一步。

这里绕不开一条规律。

康威定律(Conway's Law):一个系统最终长成的结构,往往和设计它的那个组织的沟通结构是一致的。类比一下:五个人围着同一张桌子干活,你非要他们产出五条互不干扰的流水线,结果只能是天天开会。

不是先画好架构再往里塞人,而是人怎么协作,架构就会长成什么样。

所以我一般用这几个信号来判断。

先看「不该拆」的信号:

1)团队不到十个人,还都坐在同一个办公室——沟通成本接近于零,拆开纯属自我惩罚。 2)业务边界还没稳定,需求一周一变——今天按订单拆出来的边界,下个月就过时了。 3)没有自动化部署和监控——靠手工传包的团队拆微服务,是在给自己上刑。

再看「该拆」的信号:

1)某个模块的发布节奏,跟别的模块天天打架。 2)某个模块的扩容需求,和别的模块差了一个数量级。 3)团队多到改同一份代码时,解决合并冲突比写代码还费时间。

三条里中了两条,再动手不迟。

至于微服务怎么拆分,我给的建议是别从核心链路开刀。先找一个读写边界最清楚、依赖最少的服务拆出去——通知服务、文件服务、字典服务这一类。用这种边缘服务把注册中心、配置中心、CI/CD、链路追踪这套基础设施跑通,团队摸熟了,再去碰订单和支付这种核心链路。

可能有人会问:那我现在是不是得先把单体写好再说?

对,而且这个答案对绝大多数团队都成立。模块化单体(Modular Monolith):整套系统仍然是同一个部署单元,但代码内部严格按业务边界划分模块,模块之间只能通过公开接口通信。可以理解成「一栋楼里的独立办公室」——门牌分得清清楚楚,楼还是那一栋。等哪天团队和业务真的把你逼到那一步,你会发现在模块化单体上按边界拆服务,是成本最低的一种拆法,因为边界早就画好了。

结语

说白了,微服务架构和单体架构的区别不在「先进和落后」,而在你把复杂度放在了哪:单体把复杂度留在代码里,微服务把复杂度搬到了网络上。

你更需要管住哪一种,就选哪一种。而绝大多数不到十个人的团队,答案是先把单体写成模块化单体——不是微服务架构不能上,是那笔账现在还划不来。


我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你们团队现在是单体架构还是微服务架构,拆分过程中踩过最痛的坑是什么?