读懂微服务

【看图读懂微服务:从单体到 gRPC + 网关的完整演化】

欢迎打开:看图读懂微服务(60张图把5个核心概念讲明白)

这是一份通识科普,不是代码教程。我们一行代码都不写,只讲一件事:为什么要这样设计。

因为读懂"为什么",比记住代码怎么写重要100倍。

我们会沿着一条主线走:从单体架构 出发,一步步拆分服务 ,做服务发现 ,升级到gRPC ,最后加上API网关。整段路讲完,你就能建立起对微服务的整体直觉。

准备好了吗?我们从第一张图开始。

这套内容适合谁?

门槛其实很低。你只要知道 HTTP 是什么,听过 JSON,平时用过 App 或网站就够了。

你完全不需要会写 Go 代码,不用装过 Docker,也不用看过 Kubernetes。这些可以统统划掉。

我们的目标读者是那种听过"微服务、gRPC、服务发现、网关"这些词,但讲不清它们到底怎么协作的人。如果你想快速建立微服务架构的整体直觉,而不是深陷某个框架的细节,那你就是目标读者。

记住:读懂"为什么这样设计",比看懂代码重要得多。

我们用一个最贴近生活的例子贯穿全文:电商下单

整个流程其实就三步:

  1. 查用户信息:确认是不是合法用户。
  2. 扣库存:看这件商品还有没有货。
  3. 创建订单:生成订单号,保存下来。下单成功。

看似简单的三步,背后却藏着微服务所有的核心问题。请记住这句话:当这三部分别由三个独立程序完成时,它们之间怎么协作?

带着这个问题,我们开始一段从单体到微服务的演化之旅。


全文地图:五章解决五个问题

在正式开始前,先看这张全文地图。五章解决五个问题:

  1. 业务刚起步怎么写最简单?单体架构
  2. 服务拆开了,互相怎么找到对方?服务拆分
  3. 服务越来越多,谁管理它们的地址?服务发现
  4. 服务间通信用什么协议最高效?gRPC
  5. 前端调不动内部协议怎么办?API网关

这里有一个重要规律:每一章都遵循同一个节奏:遇到痛点 → 引入方案 → 解决痛点 → 然后出现新的痛点。

这不是巧合,而是技术演化的普遍规律。理解了这个节奏,你就掌握了判断任何新技术该不该用的思维框架。


第一章 单体架构:所有东西住一栋楼里

这一章要回答的核心问题是:业务刚起步怎么写最简单?

答案是把所有功能塞进一个程序里。这就是"单体"。

我们会用一个生活场景让你秒懂,为什么单体是几乎所有项目的起点;也会讲清楚它什么时候开始让你"痛",痛到该拆。记住,单体一点都不落后,它是性价比最高的开局方式。

要理解单体,先想象一栋商住两用的大楼。一楼是餐厅,二楼是超市,三楼是仓库,四楼是收银。所有功能都住在一栋楼里,共享同一套水电、电梯和地下室。软件里的单体应用,就是这栋楼:用户模块、订单模块、库存模块、支付模块全塞在一个程序里,底下共用一个数据库。

这里有一个关键洞察,一定要记住:在单体里,用户模块想调用订单模块,本质上就是一个函数调用,同一个进程,纳秒级完成,零网络成本。

正因为这么直接、这么快,单体才成为几乎所有项目的起点。很多人一听微服务就觉得单体"落后",这是大错特错。单体有四大优点:

  • 开发快:函数直调,没有网络开销,纳秒级完成。
  • 部署简单:一个程序扔上去就行。
  • 调试方便:一个断点能看完整调用链。
  • 资源省:一个进程、一个连接池就够。

所以,项目早期,单体是性价比最高的选择。判断标准也很简单:单体什么时候开始让你"痛",什么时候才考虑拆。 Netflix花了7年才从单体迁到微服务,亚马逊也是业务涨到一定规模才拆。所以,千万不要为拆而拆。

这张时序图是全篇最重要的对比基准,请务必记住它。 后面每一章本质上都在改这张图里的"函数调用"。

看一次下单在单体里怎么发生:客户端发 POST 请求,单体应用收到后,第一步查用户是一次函数调用,第二步扣库存又是一次函数调用,第三步保存订单还是函数调用。全程都在同一个进程里,纳秒级完成,零网络成本。

记住这张图,尤其是"函数调用 = 纳秒级"这一点。因为微服务的所有复杂度,都源于把这种纳秒级调用变成了毫秒级的网络调用。

单体早期很爽,但业务长大后会暴露四个致命问题:

  1. 部署笨重:改一行代码也要重新部署整个应用。
  2. 扩容低效:你只想给库存加机器,结果整个应用都跟着扩了。
  3. 故障蔓延:库存模块一个内存泄漏,整个进程全崩,连登录都用不了。
  4. 协作冲突:多个团队改同一份代码,天天合并冲突。

痛到这份上,团队就会冒出一个想法:能不能把每个模块独立部署、独立扩容、独立背锅?

这个想法,正是微服务的起点。


第二章 服务拆分:从函数调用到网络调用

这一章要回答:把单体拆开后,两个独立程序之间怎么通信?

答案分两步:先用 HTTP 网络请求替代原来的函数调用,然后马上会发现这条路藏着一堆新坑。

副标题是"从函数调用到网络调用"。我们会看到拆分换来哪些好处,又会付出什么代价,尤其是新手最容易踩的第一个坑:把对方的IP地址写死在代码里

拆分的核心动作,就是把住在一栋楼里的模块,搬成住进独立别墅。拆之前,所有模块都在一个进程里,共用一个数据库;拆之后,Order服务和User服务各自独立,连数据库都分家了,每个服务有自己的库,互相不能直接访问。

但注意,右边多出了一条虚线,标注着"怎么协作?"。这就是拆分后立刻撞上的核心问题:原来模块之间是函数调用,现在变成了两个独立程序,它们到底该怎么找到对方、怎么通信?这个问题会贯穿接下来几章。

拆分换来四大收益:独立部署 (改订单不用重启用户)、独立扩容 (大促时只给库存加机器)、故障隔离 (库存崩了不影响登录)、团队解耦(不同团队各管一摊)。

但代价就一个,而且很扎眼:原来的函数调用,必须变成网络调用。 函数调用是纳秒 级,网络调用是毫秒 级,慢了大约100万倍。这个数字差距一定会让你印象深刻。记住,这是微服务天生的代价。第四章的 gRPC,就是为了缩小这个差距而生的。

拆分之后,让 Order 调用 User,新手第一反应往往是直接把对方地址写在代码里。这种做法叫"硬编码IP",短期跑得通,上生产立刻爆炸。它有"四宗罪":

  1. 环境耦合:换开发、测试、生产环境,必改代码。
  2. 重启失效:对方换个端口就调不通。
  3. 无法扩容:写死的IP没法做负载均衡。
  4. 配置爆炸:几十个服务互相写死IP,改一处要查十处。

对比三种方案------硬编码、配置文件、服务发现------只有服务发现能做到动态、自愈,还天然支持扩容。 这就引出了第三章。

本章的核心结论是:拆分完成了,但调用地址写死,换个环境就崩。顺着这个痛点往下问:怎么让服务动态地找到对方?答案呼之欲出:我们需要一个"服务电话簿",让每个服务自己上报位置,调用方动态查询。这个东西,就叫 服务发现


第三章 服务发现:让服务自己找到彼此

这是整个微服务架构的心脏。要回答的问题是:服务越来越多,谁在哪台机器、哪个端口?硬编码IP一换环境就崩。

答案是引入一个"服务电话簿",让服务自己上报位置,调用方动态查询。这一章我们会先讲一个你天天在用的类比,再拆解注册、心跳、发现这三个动作。

讲服务发现之前,先想一个你每天都在用的东西:外卖App。你想点麦当劳,会去背每家餐厅的电话吗?不会。你打开App搜"麦当劳",App从商家电话簿里查到号码,下单。商家搬家了?在App上更新一下,下次你查到的就是新号码。服务发现一模一样:Order想调User,不记IP,去问 Consul 这个注册中心。User换机器了,自己重新登记,下次查询自动拿到新地址。

一句话定义:服务发现就是所有服务登记位置的"电话簿",动态查询,位置变了不用改代码。

整个服务发现机制可以用三个动作完整概括,这张图建议截图保存:

  1. 注册:服务一启动,就告诉 Consul "我叫什么,在哪台机器,哪个端口"。就像新员工入职第一天去HR那登记。
  2. 心跳:服务每隔几秒发一次"我还活着"。就像值夜班的保安,每小时按一次报平安钮。
  3. 发现:调用方要调谁,先问 Consul 拿到对方的健康地址。就像寄快递前先查收件人地址再寄出。

光注册还不够,万一某个进程崩了,Consul还以为它在线,调用方就会惨兮兮地拿到一个死地址。于是有了第二个动作:心跳。服务每隔10秒向Consul发一次"我还活着",Consul收到了就把它标记为健康。那进程真崩了怎么办?心跳会超时,连续三次没收到,Consul就把这个实例从列表里剔除,调用方再也拿不到它。整个过程完全自动,不需要人工干预。这就是为什么我们说微服务能"自愈":服务挂了,系统自己感知,自己摘除,照样能跑。

把注册、心跳、发现三步合起来,就得到一张全景图:中间是 Consul 这个注册中心,左边是服务提供方(User, Order, Inventory),他们启动时注册,定期发心跳;右边是消费方(Order和网关),他们要调别人时就来查询地址。

这里有一个关键洞察:在微服务里,每个服务都同时扮演两个角色。 同一个服务,启动时是 Provider 去注册,调别人时是 Consumer 来查询,这两件事就在同一个进程里完成。所以,服务发现不是某个独立组件,而是每个服务都自带的能力。

常见的工具:Consul 最通用,功能丰富;Eureka 是Java经典,但已停止维护;etcd 是Kubernetes底层用的;Nacos 在国内很流行,发现加配置中心一体。如果已经在用K8s,直接用K8s Service就行,不用额外装组件。原理都一样,只是实现细节不同。

至此,第二章硬编码IP的"四宗罪"全部治愈:位置无关、自动自愈、天然支持扩容、集中管理。但新痛点又来了:HTTP + JSON 又慢又啰嗦,还没类型保障。 这就引出了第四章的gRPC。


第四章 gRPC:服务间通信的高速公路

要回答的问题是:HTTP + JSON 又慢又啰嗦,还没类型保障,改一个字段名,调用方就崩。

答案是用 gRPC + Protobuf,把通信契约写得清清楚楚,速度还能快5-10倍。这一章我们会从一个真实的事故场景讲起,看清JSON到底错在哪。

来看一个会让你感同身受的真实场景:某个周三,User团队为了统一风格,把字段 userId 改成了 user_id。单元测试过了,编译过了,部署也成功了。可 Order 服务毫不知情,还在按 userId 取值,结果解析出来全是零,下了一大堆 userId=0 的脏订单。凌晨两点,大家被叫醒排查。根因是什么?JSON是无Schema的文本协议,没有契约约束。 你改了字段名,编译器不报错,运行时才崩。

gRPC的解法就是用 Proto契约文件 强约束。改了字段,对方重新生成代码时,编译期立刻报错,根本到不了生产。

gRPC有三大秘密武器,每个都对应解决HTTP+JSON的一个痛点:

  1. Protobuf:一种二进制编码格式,体积小、解析快,专治"慢和啰嗦"。
  2. HTTP/2:新的传输协议,支持多路复用,并发高、延迟低。
  3. Proto契约文件:一份Schema,改了字段编译期就报错,专治"无类型"。

其中,契约是gRPC的灵魂。它最大的价值,就是把原本的"运行时事故"提前到了"编译器报错",工程质量直接提升一个数量级。

Protobuf凭什么这么快?拿传输一个用户对象举例(ID是1,Name是小明)。同样的数据,JSON大约要28字节,Protobuf只要11字节,体积小了六成。两个技巧:第一,用编号代替字段名,"user"这七个字符压缩成字段编号只要一个字节;第二,紧凑二进制,数字1不再存成文本字符,而是直接存成八位二进制。结果就是体积小六成,解析快5-10倍。单个请求感觉不明显,但每天几十亿次内部调用,省下来的带宽和CPU是惊人的。

gRPC这么好,为什么不全用它?因为它们适合不同场景:

  • REST + JSON:对外友好。HTTP协议、文本格式,浏览器、App、第三方都能直接调。
  • gRPC + Protobuf:内部高效。HTTP/2、二进制格式,性能快5-10倍,但浏览器原生不支持。

一句话记住:对外的门面用 REST,内部的管道用 gRPC。

看一次完整的gRPC调用时序:Order作为客户端,构造一个强类型请求调用 client.GetUser,就像调本地函数一样。底层用Protobuf编码成几十个字节发出去。User服务收到后,强类型解码,查到结果返回。Order拿到的也是强类型响应,编译期就做完类型检查。对比第二章的HTTP版本,差异很明显:类型安全、二进制小快稳、代码还简洁。

但这时候,前端同学找上门了:"gRPC我调不动啊!"浏览器不原生支持,每个服务开公网端口不安全,鉴权还得在每个服务重复实现。这就引出了第五章的API网关。


第五章 API网关:统一对外的大门

要回答的问题是:前端调不动gRPC,每个服务都暴露端口既混乱又不安全。

答案是引入一个网关,对外用 REST,对内用 gRPC,由它来承担协议翻译和统一入口。这一章会用"大厦前台"这个最贴切的类比开场。

理解网关,用大厦前台来类比最贴切。访客来办事,不会直接冲进各个部门,而是先到前台。前台做的四件事,正是网关的四大职责:

  1. 路由分发:问访客找谁、有什么事,对应按URL把请求转发到对应服务。
  2. 协议翻译:像给外宾当翻译,对外说REST,对内说gRPC。
  3. 统一鉴权:查访客证件、登录态校验,所有服务共享。
  4. 横切关注点:记录来访登记,对应日志、限流、熔断、监控。

一句话:API网关就是系统对外的唯一大门。

加上网关后,整个系统变成了三层:最上面是接入层(前端、App、第三方),全部用REST+JSON;中间是网关层,对外开一个REST端口,对内说gRPC,同时承担鉴权、路由、限流、日志;最下面是服务层(User, Order, Inventory),全用gRPC内部通信。而服务发现 Consul 贯穿这三层,网关要调内部服务,也得先通过Consul查地址。

三个关键变化:前端从此只和一个地址打交道;内部服务完全隐藏;网关承担所有的翻译和鉴权。

网关最大的价值是收口横切关注点 。什么叫横切关注点?就是所有服务都需要、但又跟业务核心无关的功能,比如鉴权、日志、限流、熔断、调用链追踪。没有网关时,每个服务都得自己实现一遍,同样逻辑写三遍,改一处要改三处。有了网关,这些统一在网关做一遍,全局生效。业务服务就能专注业务。这就是网关最实在的价值:让写业务的人,不用再操心那些重复的杂活。

这张全家福时序图是全篇的高潮,它把第一到第四章的所有组件完整串了起来:前端发一个POST请求,先到网关,网关做鉴权和路由,接着通过Consul查到Order的地址,把REST翻译成gRPC调过去。Order又通过Consul查到User的地址,gRPC调用拿回用户信息。最后,网关把gRPC响应翻译回REST,返回给前端。

三个关键结论:

  1. 前端全程只感知 REST。
  2. 内部全是 gRPC 高效通信。
  3. 网关承担了所有的翻译和鉴权。

这就是一套完整的微服务架构。


回顾与地图:记住这五件事

用一张时间线回顾你走过的每一步:

  1. 第一站,单体:所有功能放进一个进程,函数调用纳秒级。业务长大,模块相互拖累。
  2. 第二站,拆分:把一栋楼拆成多栋楼,函数调用变成网络调用。硬编码IP,换环境就崩。
  3. 第三站,服务发现:服务越来越多怎么找?引入Consul当电话簿,注册、心跳、发现三步走。
  4. 第四站,gRPC:HTTP+JSON又慢又没类型。协议升级,用上Protobuf、HTTP/2和契约。
  5. 第五站,网关:前端调不动,内部全暴露。对外REST,对内gRPC,鉴权、路由、横切全收口。

"遇到痛点 → 引入方案 → 解决痛点 → 又出现新痛点",这张图是整篇教程的灵魂。

如果你只能记住五件事,请记住这张图:

  1. 服务拆分:按业务边界拆,各自独立部署。
  2. 服务发现:Consul当电话簿,注册、心跳、发现。
  3. gRPC:Protobuf编码 + HTTP/2 + 契约。
  4. API网关:对外的唯一入口,做协议翻译和鉴权。
  5. 服务间通信:对外REST,对内gRPC。

这五者不是孤立的:拆分产生寻址需求,于是有服务发现;拆分产生通信需求,于是有gRPC;gRPC对外收口,于是有网关。五个概念,缺一不可。

最后,给你一张进阶地图。学习路径按这个顺序性价比最高:

  • 先用 Docker + Compose 一键拉起多服务。
  • 再学链路追踪,不然多服务报错你会抓狂。
  • 然后是熔断限流,因为第一次线上事故多半是雪崩。
  • 接着配置中心,服务一多配置散落就是噩梦。
  • 再到 Kubernetes,真正的云原生。
  • 最后才是 go-zero、Kitex 这些框架。先懂原理,再用框架,事半功倍。

也要记住五个反模式:别一开始就拆;别按技术拆,要按业务拆;别共享数据库;别追求强一致;别盲目堆组件。

比记住任何具体技术更重要的,是建立痛点驱动的工程思维。助你在微服务的路上越走越稳。

相关推荐
阿里云云原生3 小时前
亚太唯一!阿里云跻身 Gartner 可观测魔力象限“挑战者”象限
云原生
小二·3 小时前
云原生2026:Kubernetes + Wasm + Serverless 深度实战
云原生·kubernetes·wasm
啊啊啊迈 旋棍4 小时前
终端后端【重要,操作实用】
云原生·eureka
熊猫钓鱼>_>4 小时前
2026 鸿蒙全栈开发实战:从新能力落地到多设备上架的完整路径
华为·架构·app·harmonyos·arkts·鸿蒙·运营
XUHUOJUN4 小时前
Azure Stack Hub 证书管理:PKI / SAN / 信任链 / 验证 / 轮换
架构·azure stack
FII工业富联科技服务5 小时前
从85% AI应用覆盖到规模化运营:制造企业灯塔AI转型架构与落地方法解析
人工智能·架构·制造
带娃的IT创业者5 小时前
从印度私营火箭首飞成功看新兴航天架构的技术突围
大数据·架构·架构设计·系统工程·控制系统·火箭发射·商业航天
向夏威夷 梦断明暄5 小时前
从架构特点到功能缺陷,重新认识分析型分布式数据库
数据库·分布式·架构
淼澄研学6 小时前
大模型应用开发实战:从API调用到RAG与Agent架构的5个核心落地方案
人工智能·架构