SpringCloud Alibaba 核心组件解析:服务熔断与降级(Sentinel)
技术栈 :Spring Boot 3.2.0 + Spring Cloud Alibaba 2023.0.0.0-RC1 + Sentinel + Nacos
4.1 是什么 --- Sentinel 定位与核心能力
4.1.1 一句话定义
Sentinel = 流量控制 + 熔断降级 + 系统负载保护 的高可用防护组件。阿里双十一核心链路验证。
4.1.2 生活化类比:景区限流
景区最大承载 5000 人:
→ 到达 4500 人:预警,减缓入园
→ 到达 5000 人:停止售票(限流)
→ 某个游乐设施排队超过 2 小时:引导去别的项目(降级)
→ VIP 通道:特殊游客不受限制(授权规则)
4.1.3 四大核心能力
| 能力 | 说明 | 类比 |
|---|---|---|
| 流量控制 | QPS/并发线程数超阈值时拒绝 | 景区限流 |
| 熔断降级 | 慢调用/异常比例过高时快速失败 | 游乐设施排队太久关闭 |
| 热点参数 | 对某个参数值精细化限流 | 热门项目单独限流 |
| 授权规则 | 白名单/黑名单控制来源 | VIP 通道 |
4.2 为什么 --- Sentinel vs Hystrix vs Resilience4J
4.2.1 控制台对比
| 能力 | Sentinel | Hystrix | Resilience4J |
|---|---|---|---|
| 实时监控 | ✅ 秒级 | Dashboard(废弃) | ❌ |
| 规则热更新 | ✅ 控制台实时下发 | ❌ | ❌(需重启) |
| 规则持久化 | ✅ Nacos/Apollo/Redis | ❌ | ❌ |
| 链路追踪 | ✅ 自带 | ❌ | ❌ |
| Spring Cloud | @SentinelResource |
@HystrixCommand |
@CircuitBreaker |
4.2.2 选择建议
小项目:Resilience4J(够用,零运维)
中等规模:Sentinel(有控制台,好排查)
阿里生态/大流量:Sentinel(唯一选择)
4.3 怎么做 --- Sentinel 完整实战
4.3.0 启动控制台
bash
java -Dserver.port=8080 -jar sentinel-dashboard-1.8.6.jar
# 访问 http://localhost:8080 账号/密码:sentinel/sentinel
4.3.1 项目模块
| 模块 | 端口 | 说明 |
|---|---|---|
cloudalibaba-sentinel-service8401 |
8401 | Sentinel 完整功能演示 |
clooudalibaba-sentinel-gateway9528 |
9528 | Sentinel + Gateway 整合(见第 6 章) |
4.3.2 步骤 ①:依赖与配置
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
yaml
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
web-context-unify: false # 关闭 URL 收敛
datasource: # 规则持久化到 Nacos
ds1:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
4.3.3 步骤 ②:流控 --- 直接模式
java
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
控制台 → 簇点链路 → 对
/testA新增流控规则 → QPS=1 → 快速刷新 → 触发限流返回Blocked by Sentinel。
三种流控效果:
| 效果 | 说明 | 场景 |
|---|---|---|
| 快速失败 | 直接拒绝(默认) | 保护系统不被冲垮 |
| Warm Up | 预热/冷启动,逐步放开 QPS | 缓存预热、新实例上线 |
| 排队等待 | 匀速排队,超时才拒绝 | 消息队列削峰填谷 |
4.3.4 步骤 ③:流控 --- 链路模式
java
// 公共 Service
@Service
public class FlowLimitService {
@SentinelResource(value = "common")
public void common() {
System.out.println("------FlowLimitService come in");
}
}
// Controller
@RestController
public class FlowLimitController {
@Resource
private FlowLimitService flowLimitService;
@GetMapping("/testC")
public String testC() {
flowLimitService.common();
return "------testC";
}
@GetMapping("/testD")
public String testD() {
flowLimitService.common();
return "------testD";
}
}
为
common资源设链路流控,入口资源填testC→ 则 /testC 限流,/testD 不受影响。
4.3.5 步骤 ④:熔断 --- 三种策略
java
// 慢调用比例
@GetMapping("/testF")
public String testF() {
try { TimeUnit.SECONDS.sleep(1); }
catch (InterruptedException e) { e.printStackTrace(); }
return "------testF 慢调用比例";
}
// 异常比例
@GetMapping("/testG")
public String testG() {
int age = 10 / 0; // ← 触达异常
return "------testG";
}
// 异常数
@GetMapping("/testH")
public String testH() {
int age = 10 / 0; // ← 触达异常
return "------testH";
}
4.3.6 步骤 ⑤:@SentinelResource --- blockHandler vs fallback
java
@RestController
@Slf4j
public class RateLimitController {
// 按资源名限流
@GetMapping("/rateLimit/byResource")
@SentinelResource(value = "byResourceSentinelResource",
blockHandler = "handleException")
public String byResource() {
return "按资源名称SentinelResource限流测试OK";
}
public String handleException(BlockException exception) {
return "服务不可用@SentinelResource启动 o(╥﹏╥)o";
}
// blockHandler + fallback 同时使用
@GetMapping("/rateLimit/doAction/{p1}")
@SentinelResource(value = "doActionSentinelResource",
blockHandler = "doActionBlockHandler",
fallback = "doActionFallback")
public String doAction(@PathVariable("p1") Integer p1) {
if (p1 == 0) throw new RuntimeException("p1等于零直接异常");
return "doAction";
}
public String doActionBlockHandler(@PathVariable("p1") Integer p1,
BlockException e) {
log.error("sentinel配置自定义限流了:{}", e);
return "sentinel配置自定义限流了";
}
public String doActionFallback(@PathVariable("p1") Integer p1,
Throwable e) {
log.error("程序逻辑异常了:{}", e);
return "程序逻辑异常了" + "\t" + e.getMessage();
}
// 热点参数限流
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",
blockHandler = "dealHandler_testHotKey")
public String testHotKey(
@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "------testHotKey";
}
public String dealHandler_testHotKey(String p1, String p2,
BlockException exception) {
return "-----dealHandler_testHotKey";
}
}
blockHandler vs fallback 对比:
| blockHandler | fallback | |
|---|---|---|
| 触发条件 | Sentinel 规则(流控/降级/热点) | 业务运行时异常 |
| 方法签名 | (参数, BlockException) |
(参数, Throwable) |
| 谁调用 | Sentinel 框架 | 你的代码 |
4.3.7 步骤 ⑥:授权规则 + 来源解析
java
// 自定义来源解析器
@Component
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
return request.getParameter("serverName");
}
}
// Controller
@RestController
@Slf4j
public class EmpowerController {
@GetMapping(value = "/empower")
public String requestSentinel4() {
log.info("测试Sentinel授权规则empower");
return "Sentinel授权规则";
}
}
控制台为
/empower配置授权规则 → 流控应用填serverName=test→ 只有带?serverName=test的请求才能访问。
4.3.8 步骤 ⑦:规则持久化到 Nacos
yaml
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
在 Nacos 中创建配置(JSON 格式):
json
[
{
"resource": "/testA",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0
}
]
4.4 深入原理 --- Sentinel 滑动窗口
时间轴 →
├──── 窗口1 ────┼──── 窗口2 ────┤
│ QPS=10 │ QPS=3 │ → 滑动窗口总 QPS=13
└──────────────┴───────────────┘
Sentinel 使用滑动窗口统计 QPS,比固定窗口更平滑,避免临界突发流量。
4.5 面试题
Q1:Sentinel 的 blockHandler 和 fallback 有什么区别?
答 :blockHandler 处理 Sentinel 规则触发的异常(流控、降级、热点),fallback 处理业务代码的运行时异常。前者由框架调用,后者是开发者兜底。
Q2:Sentinel 规则持久化怎么做?为什么需要?
答 :默认规则存在内存中,应用重启即丢失。通过配置 datasource 将规则同步到 Nacos/Apollo/Redis 中实现持久化。生产环境必须持久化,否则每次发版都要重新配置。
4.6 踩坑指南
| 坑 | 现象 | 原因 | 解决 |
|---|---|---|---|
| 🔴 控制台不显示应用 | 簇点链路为空 | Sentinel 是懒加载,需先访问一次接口 | 先 curl 一次被保护的接口 |
| 🔴 web-context-unify | 多个接口共享一个限流阈值 | 默认将所有 /foo/{id} 收敛为 /foo/* |
配置 web-context-unify: false |
| 🔴 规则重启丢失 | 应用重启后规则没了 | 默认内存存储 | 配置 datasource 持久化到 Nacos |
| 🔴 @SentinelResource 不生效 | 限流了但返回默认错误页 | 未配 blockHandler | 加上 blockHandler 指定兜底方法 |
4.7 章节总结
| 要点 | 说明 |
|---|---|
| 四大能力 | 流控 + 熔断 + 热点 + 授权 |
| 核心注解 | @SentinelResource(value, blockHandler, fallback) |
| 流控三种效果 | 快速失败 / Warm Up / 排队等待 |
| 熔断三种策略 | 慢调用比例 / 异常比例 / 异常数 |
| 规则持久化 | 配置 datasource → Nacos,应用重启不丢失 |
| 控制台 | sentinel-dashboard-1.8.6.jar,实时监控 + 规则热更新 |