深入探寻微服务【第三篇微服务的组件】

前言:

好的,今天我们进入这个系列的第三篇

第一篇我们聊了"为什么需要微服务"以及它带来了哪些挑战。如果把第一篇比作"心法",那今天这篇就是"兵器谱"------我们要把微服务架构里最核心的几件兵器(组件)逐一掰开来看。

为了避免枯燥的"说明书式"罗列,这篇我会先挨个剖析每个组件的本质 ,然后在最后用一个完整的"用户下单"请求,把所有这些组件串成一条线,让你看到它们到底是怎么协同工作的。

由于我接触的最多的就是阿里生态,所以我这里大部分都是阿里开源的组件但是思想其实都差不多。

组件逐个剖析

服务注册与配置中心:Nacos

它是干什么的?

Nacos在中文里通常读作"纳科斯",它的全称是 Dynamic Naming and Configuration Service。它干两件核心事:

  1. 服务注册与发现(通讯录):服务启动时,把自己的IP、端口、健康状态登记到Nacos上;调用方要调用某个服务时,从Nacos查地址。

  2. 动态配置管理(遥控器) :把应用的各种配置(数据库连接、开关、阈值)存放在Nacos中,修改配置后无需重启服务即可生效。

为什么需要它?

没有它,服务调用必须写死IP(比如http://192.168.1.5:8080)。在云原生时代,服务随时可能扩容、缩容、故障重启,IP是动态变化的。写死IP等于自杀式架构。有了它,调用方只问"谁叫订单服务",Nacos回答"现在有3个实例在运行",调用方拿去用就行。

有什么替代品?

  • 服务发现替代:Consul(自带健康检查更丰富)、Eureka(Netflix出品,但官方已停止维护,生产慎用)、ZooKeeper(老牌协调者,但AP性能不如Nacos)。

  • 配置中心替代:Apollo(携程开源的专精配置中心,权限和灰度发布极强)、Spring Cloud Config(配合Git,但缺少实时推送能力)。

  • 综合推荐 :国内企业几乎清一色选 Nacos,因为它既是注册中心又是配置中心,且支持CP(一致性)和AP(可用性)模式切换,适配各种场景。

API网关:Gateway(以Spring Cloud Gateway为例)

它是干什么的?

网关是系统的"总门卫"和"交警"。所有外部请求(Web、App、OpenAPI)必须先打到网关。它干三件事:

  • 路由转发 :判断请求路径(如/order/**),转发给对应的微服务集群。

  • 统一鉴权:在这里统一校验JWT Token或OAuth2令牌,不用每个微服务都写一遍鉴权代码。

  • 过滤增强:添加全局请求ID(用于链路追踪)、响应头统一格式化、限流(全局限流)。

为什么需要它?

没有网关,前端需要维护几十个微服务的地址列表,且每个服务都要自己写鉴权和限流。那将是巨大的灾难。网关把所有"横切关注点"(认证、日志、限流)剥离出来,让后端服务专心写业务逻辑。不过在实际中并不是所有限流都放在网关,也可以针对不同的服务进行更细腻度的限流。

有什么替代品?

  • Java生态:Spring Cloud Gateway(当前事实标准,基于WebFlux,非阻塞)、Zuul 1.x/2.x(旧版,性能不如Gateway)。

  • 高性能代理:Kong(基于OpenResty/Nginx,性能极高,适合大流量)、Nginx(只能做反向代理,缺乏服务发现和动态路由能力,需要配合Lua脚本)。

  • 云原生:Traefik(专为K8s设计,自动监听Ingress)。

  • 综合推荐 :如果你项目是Java Spring Cloud,Spring Cloud Gateway 是最平滑的选择;如果是超高并发,可以考虑 Kong

客户端负载均衡:Spring Cloud LoadBalancer

它是干什么的?

当"订单服务"从Nacos拿到了"库存服务"的3个实例地址(192.168.1.10:8001...11:8001...12:8001)时,具体选哪一个来调用?

负载均衡 就是做这个决策的。Spring Cloud LoadBalancer 默认提供**轮询(Round Robin)、随机(Random)、权重(Weighted)**等策略。

为什么需要它?

这里必须强调一个概念:服务端负载均衡(如Nginx)客户端负载均衡(如LoadBalancer) 的区别。

  • Nginx是集中式的,所有请求都经过它转发,它成了瓶颈。

  • LoadBalancer是嵌入在调用方进程里的。订单服务自己就知道所有库存实例,自己决定选谁。这样压力分散,没有中心瓶颈,也更灵活(可以按响应时间动态调整权重)。

有什么替代品?

  • Netflix Ribbon :曾经的王者,但现在进入维护模式,Spring Cloud官方已建议迁移到 Spring Cloud LoadBalancer(它是默认的)。

  • 服务端替代:如果你不想用客户端负载均衡,可以配合Kubernetes的Service(ClusterIP)来实现,服务名自动解析为Pod IP,由kube-proxy做转发。

流量控制与熔断降级:Sentinel

它是干什么的?

这是微服务系统的"保险丝"和"减压阀"。它干三件救命的事:

  • 流量控制(限流):瞬间流量暴增(比如秒杀),直接拒绝掉部分请求,防止系统被冲垮(比如设置订单接口QPS上限为1000)。

  • 熔断降级 :如果订单服务调库存服务,库存突然响应超时或报错率达到50%。Sentinel会立即"熔断" ------接下来5秒内,订单服务不再调库存服务,而是直接返回降级数据(比如"库存查询繁忙,请稍后重试"或读取本地缓存)。这避免了线程池被耗尽的"雪崩效应"。

  • 热点参数限流:比如针对特定商品ID(爆款)单独设置限流规则。

为什么需要它?

因为网络不可靠,依赖服务一定会挂。如果没有熔断,订单服务调用库存超时(等待3秒),100个请求进来,线程池就堵死了;接下来连订单自己的查询接口也卡死了,这就是级联故障 。Sentinel存在的意义,就是优雅地接受失败,而不是让失败蔓延

有什么替代品?

  • Hystrix(Netflix出品):功能类似,但仅支持线程池隔离和信号量隔离,且停止维护,配置繁琐。

  • Resilience4j(Hystrix官方替代):轻量级,函数式风格,但缺少实时监控大盘。

  • Sentinel (阿里出品):国内主流首选。支持动态规则、丰富的流量整形(排队等待、预热)、实时监控控制台,非常适合互联网高并发场景。

分布式事务:Seata

它是干什么的?

这是微服务里最难啃的骨头。Seata(Simple Extensible Autonomous Transaction Architecture)旨在解决跨数据库、跨服务的数据一致性问题。

它提供了三种模式,最常见的是 AT模式(自动补偿)

  • 业务执行前,Seata会解析SQL,记录数据"快照(Before Image)"。

  • 订单服务创建订单、库存服务扣库存、账户服务扣余额。如果全部成功,提交并清理快照。

  • 如果其中任何一步失败(比如余额不足),Seata的协调者(TC)会发送"回滚命令"。各个服务根据快照(After Image)生成逆向SQL,把数据自动恢复成修改前的样子

为什么需要它?

在单体里,直接用数据库@Transactional注解就行。但在微服务里,订单库、库存库、账户库是三个独立的物理库,数据库本身无法跨库回滚。

如果没有Seata,你必须自己写一堆复杂的"补偿接口"并处理各种异常重试,代码量巨大且极易出Bug。

有什么替代品?

  • 最终一致性(MQ方案) :不追求强一致,而是用RocketMQ/RabbitMQ发送事务消息。订单创建后发消息,库存消费消息扣减。如果扣减失败,发补偿消息取消订单。这是最常用的轻量级替代,性能比Seata好,但数据一致性延迟更高。

  • TCC模式(手动补偿):Try-Confirm-Cancel。需要自己写三个接口(预扣、确认、取消),侵入性强,但灵活性高。Seata也支持TCC。

  • XA协议:利用数据库本身对XA的支持(两阶段提交),性能较差,锁资源时间长。

  • 综合推荐 :对一致性要求极高的金融、支付场景,用 Seata ATTCC ;对一致性要求不高的业务(如积分、日志),优先用 消息队列(RocketMQ事务消息),性能最好。

一个贯穿全流程的例子:用户"下单"请求

概念说完了,现在我们模拟一次真实的"用户下单"请求

场景:用户在App点击"立即购买"(商品ID=100,数量=1,总价=299元)。

第1步:抵达网关(预处理)

  • 请求 POST /order/create 打到 Spring Cloud Gateway

  • 网关拦截请求,解析Header中的JWT Token,调用用户服务校验身份(这一步通常用网关的过滤器完成)。

  • 鉴权通过,网关根据路由规则(/order/** 转发到 order-service),将请求转发出去。

第2步:调用方获取服务地址(服务发现 + 负载均衡)

  • order-service 收到请求后,业务逻辑需要调用 inventory-service(扣库存)和 account-service(扣余额)。

  • order-service 内置的 Spring Cloud LoadBalancerNacos 发起询问:"库存服务在哪?" Nacos返回 [192.168.1.10:8080, 192.168.1.11:8080]

  • LoadBalancer 按轮询策略选中了 192.168.1.10:8080

第3步:开启分布式事务(Seata 开端)

  • order-service 准备发起调用前,向 Seata Server(TC) 申请开启一个全局事务,Seata 生成一个全局唯一的 XID(比如 192.168.1.1:8091:123456789)。

  • 这个 XID 会随着 HTTP Header(或者RPC上下文)透传给库存服务和账户服务。

第4步:执行核心业务(涉及容错保护)

  • 订单服务在自己的库里插入订单记录(状态:待支付)。

  • 订单服务 通过 Feign/HTTP 调用 库存服务 (扣减库存)。库存服务接收到 XID,执行本地SQL update stock set count=count-1 where id=100但先不提交(Seata 拦截,记录回滚日志)。

  • 订单服务 调用 账户服务 (扣余额)。账户服务执行 SQL update account set balance=balance-299 where user_id=1同样先不提交

关键时刻(Sentinel介入)

假设此时 库存服务 因为数据库连接池满了,响应变得极其缓慢(超过 2 秒)。

订单服务内的 Sentinel 监测到调用库存服务的耗时超过阈值且错误率上升。Sentinel 立即熔断 ------订单服务不再继续傻等库存响应,而是快速失败(降级),直接抛出"库存扣减超时"异常。

第5步:分布式事务回滚(Seata 收尾)

  • 因为 Sentinel 触发了熔断,业务代码抛出异常,流程走不下去。

  • Seata(TC) 感知到全局事务执行失败,立即向所有已参与的服务(订单、库存、账户)下发"回滚"指令。

  • 各个服务根据之前记录的"修改前快照(Before Image)"生成补偿 SQL。

    • 库存服务:update stock set count=count+1 where id=100(加回库存)

    • 账户服务:update account set balance=balance+299 where user_id=1(退回余额)

    • 订单服务:删除刚才插入的待支付订单。

  • 数据完美恢复原状,整个分布式事务回滚成功。

第6步:优雅响应与监控

  • 订单服务最终返回给网关一个 Json:{"code":500, "msg":"库存扣减繁忙,请稍后重试"}

  • 网关将响应返回给App,用户看到友好的错误提示。

  • 在整个过程中,所有组件(网关、订单、库存、账户)的日志、耗时、调用链全部上抛给 SkyWalking/Prometheus,运维在监控大盘能清楚看到"库存服务"是故障点,立即报警扩容。

总结与思考

通过这个例子,你应该清晰感受到了各个组件的分工哲学

组件 扮演角色 一句话精髓
Nacos 通讯录 + 遥控器 解决"人在哪"和"配置怎么改"
Gateway 总门卫 解决"谁能进"和"往哪走"
LoadBalancer 分拣员 解决"具体找哪个人干活"
Sentinel 保险丝 解决"扛不住时怎么办"(保护自己)
Seata 后悔药 解决"砸了摊子怎么复原"(数据一致性)

"每个组件都是为了解决微服务引入的某一个特定副作用(分布式复杂性)"

  • 服务拆分了,地址找不到?→ 诞生了 Nacos。

  • 服务拆分了,请求量分散不均?→ 诞生了 LoadBalancer。

  • 服务拆分了,入口太多难管理?→ 诞生了 Gateway。

  • 服务拆分了,网络调用不可靠导致雪崩?→ 诞生了 Sentinel。

  • 服务拆分了,数据库事务无法跨库回滚?→ 诞生了 Seata。

总结

这篇文章总共介绍了服务注册与发现,分布式事务,熔断降级限流,网关,负载均衡,后续会针对每一个部分更加深入的探索。同时我会结合我自己的项目设计进行介绍。

相关推荐
智脑API2 小时前
Codex config.toml check_for_update_on_startup 怎么关闭?离线环境与版本提醒排查
运维·服务器·前端
ltl2 小时前
混沌工程:主动验证系统的韧性
架构
ltl10 小时前
限流与过载保护:保命的最后一道防线
架构
2401_8685347810 小时前
数仓开发落地手册
linux·运维
年小个大11 小时前
受 go-zero 启发,我给 Flutter 写了一套 CLI 脚手架
android·flutter·架构
正在走向自律12 小时前
使用atop工具监控Linux系统指标
linux·运维·php·实时监控·atop分析内存
岭南灯火12 小时前
前端通用交互式几何编辑器的开发经验
前端·设计模式·架构
岭南灯火12 小时前
前端通用交互式几何编辑器的设计法则 7 - 设计模式与原则
前端·设计模式·架构
岭南灯火12 小时前
前端通用交互式几何编辑器的设计法则 4 - 绘制、悬停与编辑
前端·设计模式·架构