1. 微服务链路雪崩:Sentinel要解决的那个实际问题
1.1 一次线上雪崩的形成过程
先讲一个真实场景。我之前维护过一个订单服务,核心链路上要调用库存服务。平时库存服务响应很快,大概20ms,订单服务用默认的200个Tomcat线程完全够用。某天库存服务背后的数据库出现了一条慢查询,接口RT从20ms直接涨到2秒。这时候订单服务的200个线程里,每一个请求都要占用2秒才能释放,1秒钟最多处理100个请求,而系统入口QPS是200。请求开始堆积,Tomcat线程池被打满,后面的请求全部排队等线程。问题到这里还不算完,订单服务超时后,上游支付服务又开始重试,流量被再次放大,最终整条链路上的服务全部不可用。
这就是微服务里最典型的雪崩:一个下游节点变慢,通过线程堆积和超时重试逐级传染,最终拖垮整个调用链。熔断与限流要解决的就是这个问题。SpringCloud生态里,Sentinel就是专门做这件事的组件——限流保护自己,熔断保护调用关系,降级提供兜底。这篇就沿着我自己接入Sentinel的完整过程,把熔断和限流从原理到落地一步步讲清楚。
1.2 限流、熔断、降级三者的边界
很多初学者容易把这三个概念混在一起,实际它们的分工完全不同。
限流是控制进入系统的流量,保护的是自身处理能力。比如一个订单接口只能扛100 QPS,那超过的请求直接拒绝或排队,不让系统被打垮。
熔断是调用下游失败时的一种快速失败机制。当下游接口连续出错或响应过慢,触发熔断后,调用方会在一段时间内不再真正请求下游,直接返回错误或走兜底逻辑。熔断保护的是调用关系,避免故障蔓延。
降级则是当系统压力过大或者依赖不可用的时候,主动放弃一些非核心功能,返回一个默认值或缓存数据,保证主流程还能跑通。降级是结果处理策略,熔断是触发条件之一。
打个比方:限流是小区门口的门禁,控制每小时进去多少人;熔断是发现电梯坏了立刻贴出停运公告,不让大家继续按按钮;降级是电梯坏了以后,引导大家走楼梯或者安排摆渡车,反正保证你还能到家。
1.3 为什么这个时代选Sentinel而不是继续用Hystrix
Hystrix在微服务早期几乎是熔断降级的代名词,但它的维护状态已经持续很久了。更关键的是,Hystrix的线程池隔离机制开销很大,每个被保护的下游服务都要单独分配一组线程池,线程上下文切换的成本在高并发场景下非常扎眼。它的Dashboard控制台也比较基础,想在上面直接调整规则几乎不可能。
Sentinel的思路完全不同:它基于滑动窗口做实时统计,不搞线程池隔离,资源开销小得多。默认情况下,一个方法、一个URL、一个Feign调用都能自动成为被保护资源,不需要手动包一层线程池。再加上Sentinel提供了功能完整的控制台,可以实时看到每个接口的QPS、RT、Blocked数量,直接在界面上修改限流阈值和熔断规则,这是Hystrix时代不敢想的体验。
当然选型还要看团队技术栈。如果你用的是Spring Cloud Alibaba这套体系,注册中心是Nacos,那Sentinel基本是顺理成章的选择,因为它和Nacos、OpenFeign、Gateway的整合非常顺滑,后面我会专门讲和OpenFeign配合时的配置。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Spring Cloud Alibaba环境准备:版本匹配与控制台启动
2.1 版本对应关系:最容易翻车的第一步
SpringCloud Alibaba对版本极其敏感,很多人项目跑不起来,十有八九是版本对不上。落地Sentinel之前,先把BOM版本理清楚。
我整理了一张常用的版本对应表,注意以官方发布为准:
| Spring Cloud Alibaba Version | Spring Cloud Version | Spring Boot Version | Sentinel Version |
|---|---|---|---|
| 2.2.x.RELEASE | Hoxton.SR12 | 2.3.x.RELEASE | 1.8.x |
| 2021.0.5.0 | 2021.0.5 | 2.6.13 | 1.8.6 |
| 2022.0.0.0 | 2022.0.0 | 3.0.x | 1.8.6 |
| 2023.0.1.0 | 2023.0.1 | 3.2.x | 1.8.8 |
我自己生产环境用的是2021.0.5.0这一档,Spring Boot 2.6.13,Sentinel 1.8.6,跑了很久没有出现兼容性问题。如果你是新项目,优先选择官方推荐的最新稳定组合,不要瞎配版本。
引入依赖时,不要手动加版本号,统一用BOM管理:
xml复制<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后在具体的模块里引入Sentinel starter:
xml复制<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.2 客户端基础配置
在application.yml里加上Sentinel的配置:
yaml复制spring:
application:
name: order-service
cloud:
sentinel:
transport:
dashboard: localhost:8080
port: 8719
eager: true
web-context-unify: false
这里有一个新手经常忽略的点:transport.port是客户端和控制台通信的端口,默认8719。如果这个端口被其他进程占用了,Sentinel会自动向后顺延一个端口,也就是8720、8721这样。这个特性看似智能,但如果防火墙只放行了8719,客户端端口顺延后控制台仍然能通过心跳看到,但反向通信就可能失败。所以生产环境最好固定端口并且同步到安全组规则里。
还有一个eager: true,它的作用是让客户端在应用启动时就主动注册到控制台,而不是等第一次网络请求进来。没有这个配置,你启动服务后会发现在控制台看不到任何服务实例,这也是下面要说的懒加载陷阱。
2.3 控制台启动与登录
Sentinel的控制台是一个单独的Jar包,从官方GitHub的release页面下载对应版本。下载后直接启动:
bash复制java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar sentinel-dashboard-1.8.6.jar
启动完成后,浏览器访问http://localhost:8080,默认账号密码都是sentinel。登录后你会看到一个空白的首页,这时候不要怀疑控制台坏了,是因为还没有服务接入。
2.4 首次接入的"懒加载"陷阱
Sentinel的客户端接入控制台后,如果一直没有实际流量,控制台的"机器列表"里就是空的。这个坑我踩过一次,当时怎么查都
