Spring Cloud Sentinel 熔断降级详解
在微服务架构中,服务间的依赖关系错综复杂。一旦某个下游服务出现故障或响应过慢,请求堆积可能导致上游服务资源耗尽,最终引发雪崩效应。熔断降级机制就像电路中的保险丝,当检测到异常时自动切断调用链路,保护整体系统的稳定性。
什么是熔断降级
定义
熔断降级是分布式系统中保护服务稳定性的核心机制。当目标服务故障率或响应时间超过阈值时,系统会自动停止对该服务的调用,快速返回降级结果,避免故障蔓延。
为什么需要它?
假设用户请求经过 A -> B -> C 的链路。如果 C 挂掉:
- 无熔断:B 和 A 会等待超时,线程池耗尽,整个链路瘫痪。
- 有熔断:B 检测到 C 异常,直接返回预设的降级数据(如默认值、缓存),A 正常响应用户,系统其余部分不受影响。
Sentinel 核心概念
Sentinel 是阿里巴巴开源的流量治理组件,主要提供以下能力:
- 流量控制:限制 QPS,防止系统过载。
- 熔断降级:服务异常时快速失败。
- 实时监控:提供控制台面板监控指标。
| 概念 | 说明 | 示例 |
|---|---|---|
| 资源 | 任何需要保护的逻辑 | 接口、方法、代码块 |
| 规则 | 流控、熔断的策略 | QPS>100 限流,失败率>50% 熔断 |
| 指标 | 统计数据 | QPS、RT、失败率 |
| 策略 | 处理方式 | 直接拒绝、Warm Up、匀速排队 |
相比 Hystrix,Sentinel 在性能、实时监控和扩展性上更有优势,且已停止维护的 Hystrix 逐渐被替代。
Sentinel 实战教程
环境准备
1. 添加依赖
在 pom.xml 中引入 Spring Cloud Alibaba Sentinel 及 Nacos 持久化依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2022.0.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Sentinel 核心依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Sentinel 数据源-Nacos(持久化规则) -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2. 配置文件
配置 application.yml,指定 Sentinel 控制台地址及降级处理类:
server:
port: 8080
spring:
application:
name: order-service
cloud:
sentinel:
enabled: true
transport:
dashboard: localhost:8080
port: 8719
web-context-unify: false
block-handler: com.example.handler.BlockExceptionHandler
fallback: com.example.handler.FallbackExceptionHandler
management:
endpoints:
web:
exposure:
include: '*'
基础示例:注解方式
3. 主启动类
标准的 Spring Boot 启动类即可。
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
4. 创建订单服务
使用 @SentinelResource 注解标记受保护的资源。注意区分 blockHandler(限流/熔断)和 fallback(降级)。
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
/**
* 创建订单接口
*/
@SentinelResource(
value = "createOrder",
blockHandler = "handleBlock",
fallback = "handleFallback"
)
public String createOrder(String productId, Integer count) {
System.out.println("创建订单:商品 ID=" + productId + ", 数量=" + count);
// 模拟异常情况(用于测试降级)
if ("error".equals(productId)) {
throw new RuntimeException("商品不存在");
}
return "订单创建成功!";
}
/**
* 限流/熔断处理方法
* 注意:方法签名必须与原方法一致,最后添加 BlockException 参数
*/
public String handleBlock(String productId, Integer count, BlockException ex) {
return "系统繁忙,请稍后再试(限流/熔断)";
}
/**
* 降级处理方法
* 注意:方法签名必须与原方法一致,最后可添加 Throwable 参数
*/
public String handleFallback(String productId, Integer count, Throwable ex) {
return "服务暂时不可用,已启动降级处理";
}
}
5. 控制器
暴露 REST 接口供测试。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/create")
public String createOrder(@RequestParam String productId, @RequestParam Integer count) {
return orderService.createOrder(productId, count);
}
/**
* 测试接口:模拟慢调用(用于测试 RT 熔断)
*/
@GetMapping("/slow")
@SentinelResource(value = "slowApi", blockHandler = "handleBlock")
public String slowApi() throws InterruptedException {
Thread.sleep(1000); // 模拟慢调用
return "正常响应";
}
public String handleBlock(BlockException ex) {
return "接口响应太慢,已触发熔断";
}
}
高级配置:规则定义
可以通过代码动态加载规则,也可以持久化到 Nacos。这里展示代码初始化方式。
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SentinelRuleConfig {
@PostConstruct
public void initRules() {
initFlowRules();
initDegradeRules();
}
/**
* 流量控制规则
*/
private void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
// 规则 1:创建订单接口限流
FlowRule rule1 = new FlowRule();
rule1.setResource("createOrder");
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule1.setCount(10); // 每秒最多 10 个请求
rule1.setStrategy(RuleConstant.STRATEGY_DIRECT);
rules.add(rule1);
// 规则 2:慢查询 API 限流
FlowRule rule2 = new FlowRule();
rule2.setResource("slowApi");
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule2.setCount(2);
rules.add(rule2);
FlowRuleManager.loadRules(rules);
}
/**
* 熔断降级规则
*/
private void initDegradeRules() {
List<DegradeRule> rules = new ArrayList<>();
// 规则 1:慢调用比例熔断
DegradeRule rule1 = new DegradeRule();
rule1.setResource("slowApi");
rule1.setGrade(RuleConstant.DEGRADE_GRADE_RT);
rule1.setCount(500); // 响应时间超过 500ms 视为慢调用
rule1.setTimeWindow(10); // 熔断时长 10 秒
rule1.setMinRequestAmount(5);
rule1.setSlowRatioThreshold(0.5); // 慢调用比例阈值 50%
rules.add(rule1);
// 规则 2:异常比例熔断
DegradeRule rule2 = new DegradeRule();
rule2.setResource("createOrder");
rule2.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
rule2.setCount(0.5); // 异常比例 50%
rule2.setTimeWindow(10);
rule2.setMinRequestAmount(5);
rules.add(rule2);
DegradeRuleManager.loadRules(rules);
}
}
OpenFeign 集成
若使用 Feign 调用远程服务,需开启 Sentinel 支持并配置降级类。
1. 开启 Feign 支持
feign:
sentinel:
enabled: true
2. Feign 客户端与降级处理
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(
name = "inventory-service",
path = "/inventory",
fallback = InventoryServiceFallback.class
)
public interface InventoryServiceClient {
@GetMapping("/deduct")
String deductStock(@RequestParam("productId") String productId, @RequestParam("count") Integer count);
}
import org.springframework.stereotype.Component;
@Component
public class InventoryServiceFallback implements InventoryServiceClient {
@Override
public String deductStock(String productId, Integer count) {
return "库存服务暂时不可用,已为您预留库存,稍后将自动扣减";
}
}
规则持久化(Nacos)
生产环境建议将规则配置在 Nacos 中,以便动态调整。
1. 添加 Nacos 数据源配置
spring:
cloud:
sentinel:
datasource:
flow:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}-flow-rules
group-id: SENTINEL_GROUP
rule-type: flow
data-type: json
degrade:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}-degrade-rules
group-id: SENTINEL_GROUP
rule-type: degrade
data-type: json
2. Nacos 规则配置示例
流控规则 (JSON)
[{"resource":"createOrder","limitApp":"default","grade":1,"count":10,"strategy":0,"controlBehavior":0}]
熔断规则 (JSON)
[{"resource":"slowApi","grade":0,"count":500,"timeWindow":10,"minRequestAmount":5,"slowRatioThreshold":0.5}]
全局异常处理
统一捕获 Sentinel 抛出的异常,返回友好的 JSON 格式。
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BlockException.class)
public Map<String, Object> handleBlockException(BlockException ex) {
Map<String, Object> result = new HashMap<>();
result.put("code", 429);
result.put("message", "服务限流或熔断,请稍后重试");
if (ex instanceof FlowException) {
result.put("type", "限流");
} else if (ex instanceof DegradeException) {
result.put("type", "熔断降级");
} else if (ex instanceof ParamFlowException) {
result.put("type", "热点参数限流");
} else if (ex instanceof AuthorityException) {
result.put("type", "授权规则不通过");
}
return result;
}
}
完整工作流程
- 请求拦截:Sentinel 拦截器捕获进入的资源请求。
- 规则校验:检查是否命中流控或熔断规则。
- 执行逻辑:
- 若未命中,执行业务逻辑并统计指标。
- 若命中流控,直接返回限流结果。
- 若命中熔断,返回降级结果。
- 状态流转:
- 关闭:正常状态,统计失败率。
- 打开:失败率超阈值,快速失败。
- 半开:冷却期后允许少量探测请求,恢复则关闭,失败则继续打开。
测试验证
可以使用 Apache Bench 进行压测,观察控制台变化。
# 1. 测试流控规则
ab -n 100 -c 20 http://localhost:8080/order/create?productId=123&count=1
# 2. 测试慢调用熔断
for i in {1..10}; do curl http://localhost:8080/order/slow; done
# 3. 测试异常熔断
curl http://localhost:8080/order/create?productId=error&count=1
访问 Sentinel 控制台 (http://localhost:8080) 可查看实时 QPS、响应时间及熔断状态。
最佳实践与生产建议
1. 熔断阈值设置建议
| 场景 | 慢调用 RT 阈值 | 异常比例阈值 | 熔断时长 |
|---|---|---|---|
| 核心接口 | 1000ms | 30% | 5-10 秒 |
| 普通接口 | 2000ms | 50% | 10-30 秒 |
| 非核心接口 | 3000ms | 70% | 30-60 秒 |
2. 降级策略建议
降级不是简单的报错,应尽可能提供可用数据:
- 返回缓存数据:优先使用本地缓存或 Redis 缓存。
- 返回默认值:如空列表、默认价格等。
- 友好提示:告知用户稍后重试。
3. 监控告警
定期扫描熔断状态,发现异常频繁触发时应及时优化或扩容。
4. 生产环境检查清单
- 核心接口配置流控规则
- 依赖服务配置熔断规则
- 所有降级方法经过测试
- 规则持久化到配置中心
- 配置监控告警
- 定期演练故障恢复
总结
熔断降级是微服务架构中保障高可用的最后一道防线。通过 Sentinel,我们可以灵活地控制流量、隔离故障,确保核心业务不受影响。关键在于合理设置阈值、完善降级策略,并结合监控告警形成闭环。从非核心接口开始实践,逐步覆盖核心链路,能有效提升系统的健壮性。

