配合架构图一起看。我们用一个电商系统(包含商品、订单、搜索、推荐)作为例子,从最简单的做法出发,一步步看着它"长大",你就会自然明白:微服务是什么、为什么会出现、它对开发又意味着什么。 整个系统的成长,分成三个阶段(也就是架构图从上到下的三行):

| 阶段 | 一句话 | 适合的场景 |
|---|---|---|
| ① 单体应用 | 所有功能打成一个包 | 项目起步、用户少 |
| ② 集群 | 同一个包复制好几份 | 用户变多,单台扛不住 |
| ③ 微服务 | 按功能拆成多个独立的小系统 | 团队变大、业务变复杂 |
一句话先记住:架构不是越复杂越好,而是被业务"逼"出来的。
第一阶段:单体应用(Monolith)
对应架构图最上方那一行。
用户 ──▶ 前端(页面渲染) ──▶ 后端(商品/订单/搜索/推荐) ──▶ 数据库
它长什么样
- 一个前端负责显示页面;
- 一个后端程序,里面装着所有功能:商品、订单、搜索、推荐全在一起;
- 一个数据库存所有数据。
打个比方:这就像一家夫妻店,老板一个人又收银、又上货、又记账,所有事一个人全包。
它的优点
- ✅ 简单:一个项目、一份代码,打一个包就能上线。
- ✅ 好调试:所有代码在一起,从头跟到尾很方便。
- ✅ 开发快:不需要一堆额外的"配套设施"。
单体不是落后。小项目用单体,才是正确选择,不要一上来就嫌它"low"。
它的痛点(业务变大后开始难受)
- 改一行代码,整个系统都要重新部署——只改"推荐","商品""订单"也得跟着停机更新。
- 一处出 Bug,可能拖垮整个系统——"搜索"写了个死循环占满 CPU,"下单"也跟着崩。
- 没法只给"忙"的部分加资源——大促时只有"订单"压力大,但你只能整个一起加机器。
- 代码越来越大,团队互相踩脚——十几个人改同一个项目,天天冲突。
这些痛点,逼着我们走向下一阶段。
第二阶段:集群(Cluster)
对应架构图中间那一行,注意多了一个
nginx,后端也"叠"成了好几个。
用户 ──▶ 前端 ──▶ nginx(负载均衡) ──▶ 后端 × N(同一份代码的多个副本) ──▶ 数据库
要解决的问题:一台机器扛不住了
用户变多,一台服务器忙不过来。最直接的办法:把一模一样的后端复制几份,多开几台机器一起干活。 架构图里那几个"叠在一起的后端"框,就是同一份代码部署的多个副本。
那请求该发给哪一台?——这就是 nginx 干的事
nginx(负载均衡)就像银行大厅里的叫号员:后面开了 5 个窗口(5 个后端副本),客户(请求)来了,叫号员就把他分给当前最空的窗口,让每个窗口压力均摊。
"负载均衡"翻成大白话:把活儿尽量平均分给后面的多台机器,别让一台累死、其他闲死。
集群的好处
- ✅ 能扛更多用户:不够就再加机器(这叫横向扩展)。
- ✅ 更稳:挂了一台,nginx 自动把请求发给还活着的机器,用户基本无感。
集群没解决的问题(关键)
集群只是把"同一个夫妻店"开了好几家分店,每家分店还是什么都干。所以单体的痛点依然在:
- 改一行代码,所有副本还是要一起重新部署;
- "搜索"出问题,照样可能拖垮整台机器上的"订单";
- "订单"压力大时,你只能把整个大包复制好几份,没法单独只扩"订单"。
于是我们想:能不能干脆把不同功能拆开? —— 这就是微服务。
第三阶段:微服务(Microservices)
对应架构图第三行 + 下半部分,元素最多。
核心思想(一句话)
把原来挤在一个大项目里的"商品、订单、搜索"……每个功能拆成一个独立的小程序,各自开发、各自部署、各自用自己的数据库。
还用开店打比方:从"什么都管的夫妻店",升级成"专业分工的连锁商场"——有专门管商品的部门、专门管订单的部门、专门管搜索的部门,各干各的,谁也不影响谁。
每一个这样的小程序,就叫一个服务(Service)。
微服务好在哪
- ✅ 独立部署:改了"推荐",只重新部署推荐服务,其他服务照常运行。
- ✅ 故障隔离:"搜索"崩了,最多搜索用不了,"下单"还能正常进行。
- ✅ 按需扩展:大促时只给"订单服务"多开几台,不浪费资源在闲着的服务上。
- ✅ 团队解耦:商品组、订单组各管各的代码仓库,互不干扰。
代价:多了一堆"配套设施"
用户 ─▶ 前端 ─▶ nginx ─▶ 【网关 gateway】 ─▶ 商品服务 ─▶ 商品库
│ 订单服务 ─▶ 订单库
│ 搜索服务 ─▶ 搜索库
│
【注册中心】(nacos / eureka / zookeeper)
很多人以为"微服务 = 把代码拆开就完事了"。恰恰相反,拆开只是第一步,真正的工作量在下面这些配套设施上。 这也是为什么微服务对开发的要求更高。下面逐个认识它们。
1️⃣ 网关 Gateway —— 系统的大门 / 总前台
对应图中
gateway 网关。
服务被拆成好多个后,前端犯难了:"我到底该调哪个服务?地址那么多怎么记?"于是在所有服务前面立一个统一入口,就是网关。
网关就像公司大楼的前台 + 保安:所有访客(请求)都先到前台,前台再告诉你"找商品去 3 楼,找订单去 5 楼",并帮你带路。
网关通常负责:
- 统一入口:前端只需知道网关一个地址,不用记一堆服务地址;
- 路由转发:根据请求路径,决定转给商品服务还是订单服务;
- 统一鉴权:在大门口先检查"你有没有登录、有没有权限"(后面专门讲);
- 还能做限流、日志等。
2️⃣ 注册中心 —— 服务的通讯录 / 大众点评
对应图中
注册中心,常用软件:nacos / eureka / zookeeper。
服务那么多、数量还随时在变(大促时订单服务从 2 台变 10 台),网关怎么知道每个服务现在有哪些机器、地址是多少?答案:搞一个注册中心,让所有服务"上线来登记,下线来注销"。
注册中心就像一个实时更新的通讯录:
- 服务一启动,就主动告诉注册中心:"我是订单服务,地址是 192.168.x.x,我上线了!"(服务注册)
- 网关想找"订单服务"时,来注册中心查:"订单服务现在有哪几台可用?"(服务发现)
- 服务挂了,注册中心把它从名单划掉,不再给它发请求。
nacos、eureka、zookeeper都是常用的注册中心软件,作用一样,选一个用即可,新手记住 nacos 最常用就行。
3️⃣ 服务之间怎么互相调用?—— Feign
对应图中"服务调用流程":
请求方 ─ Feign ─ 响应方。
业务经常需要跨服务协作。比如"下单"时,订单服务要去问商品服务:"这个商品还有库存吗?"在单体里这就是一次普通方法调用,现在两个服务在不同机器上,怎么调?这就用 Feign。
Feign 让"调用别的服务"像"调用本地方法"一样简单:你只要声明一个接口,写上"我要调订单服务的这个方法",Feign 在底层帮你把它变成一次网络请求,你完全不用自己写复杂的网络代码。
订单服务(请求方) ──Feign调用──▶ 商品服务(响应方)
"请问商品123还有货吗?"
◀────────────────────── "还有,剩 50 件"
一句话:Feign = 让远程调用看起来像本地调用的"翻译官"。
4️⃣ 服务调用出问题怎么办?—— Sentinel 熔断降级
对应图中右下角
Sentinel 熔断降级流程,以及调用图里的sentinel标注。
微服务最大的风险是服务之间会互相"传染故障":
订单服务要调商品服务,结果商品服务卡住了(比如数据库慢)。订单服务傻等,请求越积越多,自己也被拖垮;然后调订单服务的服务也跟着垮…… 像多米诺骨牌一样全倒了。这个现象叫 "雪崩"。
为了防雪崩,用 Sentinel,它主要做两件事:
- 熔断(断路):发现"商品服务"老是失败/超时,就暂时不调它了,直接快速返回。
就像家里电路短路,保险丝"啪"地跳闸,先断开这条线,免得烧了整间屋;过一会儿再试着合上看恢复没有。
- 降级:被熔断后,不让用户对着报错干瞪眼,而是返回一个兜底的、能用的结果。
就像奶茶店"芋圆"卖光了,店员说"给您换成同价位的椰果好吗?"——保证你有东西喝,体验不至于崩。
右下角那张流程图,描述的就是 Sentinel 在什么情况下触发熔断、怎么判断要不要降级、过多久尝试恢复的判断逻辑。现在只要记住两个核心:熔断 = 及时断开止损,降级 = 给个兜底结果。
5️⃣ 数据库也要拆 —— 各服务用各自的库
对应图中
商品库 / 订单库 / 搜索库。
真正的微服务,连数据库都是分开的:
- 商品服务用商品库,订单服务用订单库,互不直接访问对方的库;
- 好处:一个库压力大可单独优化/扩容,一个库挂了不连累其他服务;
- 代价:以前一条 SQL 联表就能查的数据,现在可能要跨服务调用来拼。
原则:谁的数据谁管,别人想要数据,找它要(通过 Feign 调接口),而不是直接连它的库。
微服务对"开发"的真实影响
听起来微服务很好,那代价是什么?这一节回答这个问题。把这几点搞清楚,你才不会盲目崇拜微服务。
影响 1:要做公共 SDK / 公共模块
服务拆开后,很多东西是每个服务都要用的:统一的返回格式、通用工具类、公共实体、错误码、日志规范……如果每个服务各写一套,就会重复又不统一。所以要把这些公共的东西抽成一个公共 SDK(公共依赖包),让所有服务都引用它。
就像连锁店总部统一定制的"员工手册 + 工具箱",每家分店直接拿来用,保证大家做事方式一致。
影响 2:要做统一认证鉴权
单体时代,用户登录一次,信息就在一个程序里随便用。现在服务拆成好几个,"用户登录了没?有没有权限?"每个服务都要知道——总不能让用户在每个服务都登录一遍。所以需要统一认证鉴权:
- 用户在一个地方登录,拿到一张"通行证"(通常是 Token,如 JWT);
- 之后每次请求都带着这张通行证;
- 网关在大门口统一校验这张证,通过才放进来;服务之间也认这张证。
就像游乐园的手环:进门验一次票换成手环,之后园内所有项目都认这个手环,不用每个项目重新买票。
影响 3:部署和运维变复杂
- 单体:1 个包,部署 1 次就好。
- 微服务:N 个服务,每个都要单独部署、配置、监控,还要管它们之间的网络。
所以微服务几乎离不开这些工具:
- Docker:把每个服务连同运行环境一起打包成标准"集装箱",到哪都能跑,不再有"我电脑上是好的呀"的问题;
- Kubernetes(K8s):管理这一堆集装箱,负责自动部署、自动扩容、挂了自动拉起,相当于自动化的"码头调度系统";
- 配置中心:把各服务配置集中管理(nacos 通常也兼这个活);
- 监控 / 链路追踪:一个请求横跨好几个服务,出问题要能查出到底卡在哪一环。
总结一句:微服务把"开发的复杂度"降下来了(每个服务变小变简单),却把"运维和协作的复杂度"提上去了。
影响 4:调试和排错变难
单体里点点点就能跟完整个流程;微服务里一个请求可能经过 网关 → 订单服务 → 商品服务 → …… 出问题要在好几个服务的日志里来回找。所以前面说的"链路追踪"才那么重要。
总结:一张表带走
| 对比项 | 单体应用 | 集群 | 微服务 |
|---|---|---|---|
| 代码组织 | 全在一个项目 | 全在一个项目(复制多份) | 按功能拆成多个项目 |
| 部署 | 部署 1 个包 | 部署同一个包多份 | 每个服务独立部署 |
| 扩展 | 整体扩 | 整体复制扩 | 想扩哪个扩哪个 |
| 故障影响 | 一处挂全挂 | 单台挂有备份 | 故障被隔离在单个服务 |
| 数据库 | 一个库 | 一个库 | 每个服务独立库 |
| 配套设施 | 几乎不需要 | + 负载均衡(nginx) | + 网关 + 注册中心 + Feign + Sentinel + 统一认证 + Docker/K8s |
| 开发难度 | 低 | 低~中 | 高(配套多) |
| 适合谁 | 小项目/起步 | 用户变多 | 业务复杂、团队大 |
三句话收尾
- 架构是演进出来的,不是一开始就上微服务。 小项目用单体,别过度设计。
- 微服务的核心是"拆",但难点全在"拆完之后怎么协作"——网关、注册中心、调用、熔断、认证、部署,缺一不可。
- 没有最好的架构,只有最适合当前业务规模的架构。