核心观点: 熔断器是微服务架构的安全气囊,通过快速失败隔离故障,防止雪崩。Sentinel是当前生产环境的最佳选择。
熔断器核心原理
什么是熔断器?
熔断器(Circuit Breaker)借鉴了电路中的断路器概念:
电路断路器:
正常 → 短路 → 断路器跳闸 → 保护电路
服务熔断器:
正常 → 下游故障 → 熔断器打开 → 保护上游
核心思想: 当下游服务故障时,快速失败优于漫长等待。
熔断器状态机
熔断器有三种状态:
错误率>阈值
Closed ───────────→ Open
↑ │
│ │ 等待恢复时间
│ ↓
│ Half-Open
│ │
│ 探测成功 │ 探测失败
└──────────────────┘
状态说明:
Closed(闭合): 正常状态
- 放行所有请求
- 统计错误率
- 错误率>阈值 → 转Open
Open(打开): 熔断状态
- 拒绝所有请求,快速失败
- 不调用下游服务
- 等待一段时间 → 转Half-Open
Half-Open(半开): 探测状态
- 放行少量请求(探测)
- 成功 → 转Closed
- 失败 → 转Open
手写熔断器
/**
* 简化版熔断器
*/
public class SimpleCircuitBreaker {
// 状态枚举
enum State { CLOSED, OPEN, HALF_OPEN }
private State state = State.CLOSED;
private int failureCount = 0;
private int successCount = 0;
private long lastFailureTime = 0;
// 配置
private final int failureThreshold; // 失败阈值
private final long timeoutMillis; // 熔断时长
private final int halfOpenSuccessThreshold; // 半开成功阈值
public SimpleCircuitBreaker(int failureThreshold, long timeoutMillis) {
this.failureThreshold = failureThreshold;
this.timeoutMillis = timeoutMillis;
this.halfOpenSuccessThreshold = 3;
}
/**
* 执行受保护的调用
*/
public <T> T execute(Callable<T> callable, Function<Exception, T> fallback) {
// 检查状态
if (state == State.OPEN) {
// 检查是否可以进入半开状态
if (System.currentTimeMillis() - lastFailureTime >= timeoutMillis) {
state = State.HALF_OPEN;
successCount = 0;
} else {
// 快速失败,调用降级
return fallback.apply(new CircuitBreakerOpenException());
}
}
try {
// 调用实际方法
T result = callable.call();
// 调用成功
onSuccess();
return result;
} catch (Exception e) {
// 调用失败
onFailure();
return fallback.apply(e);
}
}
private synchronized void onSuccess() {
failureCount = 0;
if (state == State.HALF_OPEN) {
successCount++;
if (successCount >= halfOpenSuccessThreshold) {
// 连续成功,恢复闭合
state = State.CLOSED;
}
}
}
private synchronized void onFailure() {
lastFailureTime = System.currentTimeMillis();
if (state == State.HALF_OPEN) {
// 半开状态失败,立即打开
state = State.OPEN;
successCount = 0;
} else if (state == State.CLOSED) {
failureCount++;
if (failureCount >= failureThreshold) {
// 失败次数达到阈值,打开熔断器
state = State.OPEN;
}
}
}
public State getState() {
return state;
}
}
// 使用示例
public class UserService {
private SimpleCircuitBreaker breaker =
new SimpleCircuitBreaker(5, 10000); // 5次失败,熔断10秒
public User getUser(Long userId) {
return breaker.execute(
// 实际调用
() -> userServiceClient.getUser(userId),
// 降级方法
(ex) -> {
log.warn("用户服务熔断,返回默认用户");
return User.defaultUser(userId);
}
);
}
}
工作流程:
请求1-4: 成功 → state=CLOSED, failureCount=0
请求5-9: 失败 → state=CLOSED, failureCount=5 → 达到阈值
请求10: 失败 → state=OPEN (熔断打开)
请求11-20: 快速失败(1ms),不调用下游
10秒后:
请求21: state=HALF_OPEN,放行探测
└─ 成功 → successCount=1
请求22-23: 继续探测,成功
└─ successCount=3 → state=CLOSED (恢复)
请求24+: 正常调用
Hystrix vs Sentinel
核心差异
| 维度 | Hystrix | Sentinel |
|---|---|---|
| 隔离策略 | 线程池隔离 | 信号量隔离 |
| 性能 | 低(线程切换) | 高(无切换) |
| 熔断规则 | 错误率 | 慢调用/异常率/异常数 |
| 限流功能 | 无 | 强大(多种算法) |
| Dashboard | 简单 | 丰富 |
| 维护状态 | ❌ 停止维护 | ✅ 活跃 |
| 推荐度 | ⭐⭐ | ⭐⭐⭐⭐⭐ |
Hystrix:线程池隔离
原理:
主线程池 → Hystrix线程池 → 下游服务
优势: 完全隔离,下游故障不影响主线程
劣势: 性能开销大(线程切换、上下文切换)
代码示例:
public class GetUserCommand extends HystrixCommand<User> {
public GetUserCommand(Long userId) {
super(HystrixCommandGroupKey.Factory.asKey("UserService"));
}
@Override
protected User run() {
// 在Hystrix线程池中执行
return userServiceClient.getUser(userId);
}
@Override
protected User getFallback() {
return User.defaultUser();
}
}
// 使用
User user = new GetUserCommand(userId).execute();
Sentinel:信号量隔离
原理:
主线程 → 信号量控制 → 下游服务
优势: 性能高,无线程切换
劣势: 隔离性弱于线程池
代码示例:
@Service
public class UserService {
@SentinelResource(
value = "getUser",
fallback = "getUserFallback"
)
public User getUser(Long userId) {
// 主线程直接调用
return userServiceClient.getUser(userId);
}
public User getUserFallback(Long userId, Throwable ex) {
return User.defaultUser(userId);
}
}
性能对比
JMH基准测试结果(模拟远程调用50ms):
Hystrix(线程池):
- 吞吐量: 2000 ops/s
- 响应时间: P99=55ms(额外5ms开销)
Sentinel(信号量):
- 吞吐量: 18000 ops/s
- 响应时间: P99=51ms(额外1ms开销)
性能差异: Sentinel快9倍
选择建议
选择Sentinel:
- ✅ 性能要求高(99%场景)
- ✅ 需要丰富的限流功能
- ✅ 需要可视化Dashboard
- ✅ 生产环境推荐
选择Hystrix:
- 已有Hystrix代码,短期不迁移
- 对隔离性要求极高的场景(罕见)
实际上: Hystrix已停止维护,强烈建议使用Sentinel。
Sentinel快速上手
1. 依赖引入
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2022.0.0.0</version>
</dependency>
2. 配置文件
# application.yml
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel Dashboard地址
port: 8719 # 客户端端口
eager: true # 立即加载
3. 基本使用
@RestController
@RequestMapping("/api")
public class OrderController {
@Autowired
private UserService userService;
@GetMapping("/orders")
@SentinelResource(
value = "getOrders", // 资源名称
blockHandler = "handleBlock", // 限流/熔断处理
fallback = "handleFallback" // 异常降级
)
public Result getOrders(@RequestParam Long userId) {
User user = userService.getUser(userId);
List<Order> orders = orderService.getByUserId(userId);
return Result.success(orders);
}
// 限流/熔断处理
public Result handleBlock(Long userId, BlockException ex) {
log.warn("请求被限流或熔断: userId={}", userId);
return Result.fail("系统繁忙,请稍后重试");
}
// 异常降级
public Result handleFallback(Long userId, Throwable ex) {
log.error("服务异常降级: userId={}", userId, ex);
return Result.fail("服务暂时不可用");
}
}
4. 编程式配置规则
@Configuration
public class SentinelConfig {
@PostConstruct
public void initRules() {
// 限流规则
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule("getOrders");
flowRule.setCount(100); // 100 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
// 熔断规则
List<DegradeRule> degradeRules = new ArrayList<>();
// 规则1: 慢调用比例
DegradeRule slowRule = new DegradeRule("getOrders");
slowRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
slowRule.setCount(1000); // RT>1秒为慢调用
slowRule.setSlowRatioThreshold(0.5); // 慢调用比例50%
slowRule.setMinRequestAmount(10); // 最小请求数10
slowRule.setStatIntervalMs(1000); // 统计时长1秒
slowRule.setTimeWindow(10); // 熔断10秒
degradeRules.add(slowRule);
// 规则2: 异常比例
DegradeRule exceptionRule = new DegradeRule("getOrders");
exceptionRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
exceptionRule.setCount(0.5); // 异常比例50%
exceptionRule.setMinRequestAmount(10);
exceptionRule.setStatIntervalMs(1000);
exceptionRule.setTimeWindow(10);
degradeRules.add(exceptionRule);
DegradeRuleManager.loadRules(degradeRules);
}
}
5. Sentinel Dashboard
启动Dashboard:
# 下载sentinel-dashboard.jar
wget https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar
# 启动(端口8080)
java -jar sentinel-dashboard-1.8.6.jar
# 访问
http://localhost:8080
用户名: sentinel
密码: sentinel
功能:
- ✅ 实时监控:QPS、响应时间、错误率
- ✅ 规则配置:限流、熔断、热点、系统规则
- ✅ 调用链路:可视化依赖关系
- ✅ 集群管理:多实例统一管理
生产最佳实践
1. 熔断阈值配置
慢调用比例熔断:
DegradeRule rule = new DegradeRule("resourceName");
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
// RT阈值 = P99响应时间 × 2
// 示例:正常P99=500ms,设置1000ms
rule.setCount(1000);
// 慢调用比例 = 50%(容错率)
rule.setSlowRatioThreshold(0.5);
// 最小请求数 = 10(避免样本过少)
rule.setMinRequestAmount(10);
// 熔断时长 = 10秒(快速恢复)
rule.setTimeWindow(10);
配置建议:
RT阈值配置:
- 快速接口(P99<100ms): RT阈值 = 200ms
- 一般接口(P99=100-500ms): RT阈值 = P99 × 2
- 慢接口(P99>500ms): RT阈值 = P99 × 1.5
慢调用比例:
- 严格模式: 30%(敏感)
- 标准模式: 50%(推荐)
- 宽松模式: 70%(容忍度高)
熔断时长:
- 快速恢复: 5-10秒(推荐)
- 中等恢复: 30秒
- 长期恢复: 60秒(慎用)
2. 降级策略设计
分级降级:
@Service
public class OrderService {
// L1: 核心接口 - 返回兜底数据
@SentinelResource(value = "createOrder", fallback = "createOrderFallback")
public Order createOrder(OrderRequest request) {
return orderRepository.save(buildOrder(request));
}
public Order createOrderFallback(OrderRequest request, Throwable ex) {
// 降级:返回pending状态订单,后台异步处理
log.warn("订单创建降级,userId={}", request.getUserId());
Order order = new Order();
order.setStatus(OrderStatus.PENDING);
order.setUserId(request.getUserId());
// 发送到消息队列,异步处理
mqProducer.send(request);
return order;
}
// L2: 重要接口 - 返回缓存
@SentinelResource(value = "getOrderDetail", fallback = "getOrderDetailFallback")
public Order getOrderDetail(Long orderId) {
return orderRepository.findById(orderId);
}
public Order getOrderDetailFallback(Long orderId, Throwable ex) {
// 降级:返回缓存数据
return cacheService.get("order:" + orderId);
}
// L3: 非核心接口 - 快速失败
@SentinelResource(value = "getRecommendation", fallback = "getRecommendationFallback")
public List<Product> getRecommendation(Long userId) {
return recommendService.getForUser(userId);
}
public List<Product> getRecommendationFallback(Long userId, Throwable ex) {
// 降级:返回空列表
return Collections.emptyList();
}
}
降级策略矩阵:
| 接口类型 | 降级策略 | 示例 |
|---|---|---|
| 核心写接口 | 异步处理 | 创建订单→MQ异步 |
| 核心读接口 | 返回兜底数据 | 用户信息→默认用户 |
| 重要接口 | 返回缓存 | 商品详情→缓存数据 |
| 非核心接口 | 快速失败 | 推荐服务→空列表 |
| 边缘功能 | 功能降级 | 统计报表→提示维护中 |
3. 规则持久化
Sentinel默认规则存储在内存,重启丢失。生产环境需要持久化到配置中心。
Nacos集成:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
spring:
cloud:
sentinel:
datasource:
# 流控规则
flow:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-flow-rules
groupId: SENTINEL_GROUP
rule-type: flow
# 熔断规则
degrade:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-degrade-rules
groupId: SENTINEL_GROUP
rule-type: degrade
Nacos配置示例:
[
{
"resource": "getOrders",
"grade": 0,
"count": 1000,
"slowRatioThreshold": 0.5,
"minRequestAmount": 10,
"statIntervalMs": 1000,
"timeWindow": 10
}
]
4. 监控告警
核心指标:
// 自定义监控指标
@Component
public class SentinelMetrics {
@Scheduled(fixedRate = 60000)
public void collectMetrics() {
// 获取所有资源的统计信息
Map<String, Node> nodeMap = ClusterBuilderSlot.getClusterNodeMap();
for (Map.Entry<String, Node> entry : nodeMap.entrySet()) {
String resource = entry.getKey();
Node node = entry.getValue();
// 关键指标
long passQps = node.passQps(); // 通过QPS
long blockQps = node.blockQps(); // 拒绝QPS
long exceptionQps = node.exceptionQps(); // 异常QPS
double avgRt = node.avgRt(); // 平均响应时间
// 上报到监控系统
metricsReporter.report(resource, passQps, blockQps, exceptionQps, avgRt);
}
}
}
告警规则:
# Prometheus告警规则
groups:
- name: sentinel_alerts
rules:
# 熔断告警
- alert: CircuitBreakerOpen
expr: sentinel_circuit_breaker_state == 1
for: 1m
labels:
severity: critical
annotations:
summary: "熔断器打开"
description: "{{ $labels.resource }} 熔断器已打开"
# 限流告警
- alert: HighBlockRate
expr: rate(sentinel_block_qps[1m]) > 100
for: 5m
labels:
severity: warning
annotations:
summary: "限流次数过多"
description: "{{ $labels.resource }} 限流 > 100次/min"
# 响应时间告警
- alert: HighResponseTime
expr: sentinel_avg_rt > 1000
for: 5m
labels:
severity: warning
annotations:
summary: "响应时间过长"
description: "{{ $labels.resource }} P99 > 1秒"
核心对比总结
Hystrix vs Sentinel 终极对比
| 维度 | Hystrix | Sentinel | 推荐 |
|---|---|---|---|
| 性能 | 2000 ops/s | 18000 ops/s | Sentinel |
| 隔离方式 | 线程池(强隔离) | 信号量(轻量) | Sentinel |
| 限流功能 | ❌ 无 | ✅ 强大 | Sentinel |
| 熔断规则 | 错误率 | 慢调用/异常率/异常数 | Sentinel |
| 热点限流 | ❌ 无 | ✅ 支持 | Sentinel |
| 系统自适应 | ❌ 无 | ✅ 支持 | Sentinel |
| Dashboard | 简单 | 功能丰富 | Sentinel |
| 规则持久化 | ❌ 难 | ✅ 易(Nacos等) | Sentinel |
| 维护状态 | ❌ 停止维护 | ✅ 活跃 | Sentinel |
| 学习曲线 | 中等 | 中等 | 平手 |
| 社区支持 | ❌ 弱 | ✅ 强 | Sentinel |
结论: Sentinel全面优于Hystrix,生产环境强烈推荐Sentinel。
快速配置检查清单
生产环境上线前检查:
熔断配置:
- RT阈值 = P99响应时间 × 2
- 慢调用比例 = 50%
- 最小请求数 ≥ 10
- 熔断时长 = 10秒
降级策略:
- 核心接口有降级方法
- 降级方法经过测试
- 降级日志记录完整
- 降级数据合理(不返回null)
监控告警:
- 熔断事件告警
- 限流次数告警
- 响应时间告警
- 错误率告警
规则持久化:
- 规则存储到配置中心(Nacos)
- 规则版本控制
- 规则变更有审批流程
压测验证:
- 正常流量下验证
- 2倍流量下验证
- 下游故障场景验证
- 熔断恢复场景验证
总结
核心要点
熔断器是微服务必备
- 防止雪崩扩散
- 快速失败优于漫长等待
- 状态机:Closed → Open → Half-Open
Sentinel是最佳选择
- 性能:比Hystrix快9倍
- 功能:限流+熔断+热点+自适应
- 生态:活跃维护,丰富Dashboard
生产配置建议
- RT阈值 = P99 × 2
- 慢调用比例 = 50%
- 熔断时长 = 10秒
- 规则持久化到Nacos
降级策略分级
- 核心接口:返回兜底数据
- 重要接口:返回缓存
- 非核心接口:快速失败
下一步行动
- 快速上手:Spring Boot集成Sentinel(10分钟)
- 压测验证:验证熔断效果(30分钟)
- 配置优化:根据P99调整阈值(1小时)
- 监控告警:接入Prometheus(2小时)
- 规则持久化:集成Nacos(1小时)
总耗时: 半天即可完成生产环境熔断降级方案。
系列文章:
- ✅ 为什么需要熔断限流?从一次生产事故说起
- ✅ 限流算法深度解析:从计数器到令牌桶
- ✅ 熔断降级实战:从Hystrix到Sentinel(本文)
参考资料:
- Sentinel官方文档: https://sentinelguard.io/
- Sentinel GitHub: https://github.com/alibaba/Sentinel
- Spring Cloud Alibaba: https://spring.io/projects/spring-cloud-alibaba
📢 如果这篇文章对你有帮助,欢迎点赞、收藏、转发!