前言
在微服务架构中,服务之间的相互调用可能会因为某个服务的故障或性能问题导致整个系统雪崩。Sentinel 作为阿里开源的流量控制组件,可以帮助我们实现流量控制、熔断降级、系统负载保护等功能,保障微服务系统的稳定性。
本文将从零开始,带你快速掌握 Sentinel 的核心功能和实战应用。
一、快速上手
1.1 引入依赖
在需要保护的微服务模块中引入 Sentinel 依赖:
java
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
1.2 配置 Sentinel
在 application.yml 中添加 Sentinel 配置:
java
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 # Sentinel 控制台地址
eager: true # 启动时立即连接控制台
web-context-unify: false # 每个请求独立资源,不共享
配置说明:
-
dashboard: Sentinel 控制台地址 -
eager
:true: 应用启动时就连接控制台(但簇点链路仍需实际请求才会注册) -
web-context-unify
:false: 关闭后每个请求都有自己的 Sentinel 资源
1.3 启动 Sentinel 控制台
-
从 GitHub 下载
sentinel-dashboard.jar -
启动控制台:
java
java -jar sentinel-dashboard.jar --server.port=8080
- 访问**
http://localhost:8080** ,使用默认账号密码sentinel/sentinel登录
1.4 重要提示
⚠️ Sentinel 是懒加载机制 - 簇点链路只有在请求真正经过某个资源时才会注册。虽然配置了 eager: true,但仍需要先访问一次接口,才能在控制台看到簇点链路。
二、自定义异常处理
Sentinel 限流/熔断后默认会抛出异常,我们需要自定义异常处理来返回友好的提示。
2.1 方式一:Web 接口统一处理
处理流程: 请求 → 触发限流 → BlockException → SentinelInterceptor → BlockExceptionHandler
实现步骤:
创建自定义异常处理类,实现 **BlockExceptionHandler**接口:
java
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
String resourceName, BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
response.setStatus(429); // 429 Too Many Requests
PrintWriter writer = response.getWriter();
R error = R.error(500, resourceName + "被Sentinel限制了" + e.getClass());
String json = objectMapper.writeValueAsString(error);
writer.write(json);
writer.flush();
writer.close();
}
}
测试方式: 在 Sentinel 控制台的簇点链路中给接口添加流控规则(QPS=1),快速访问接口即可触发限流。
2.2 方式二:@SentinelResource 细粒度处理
处理流程: 请求 → 触发限流 → BlockException → @SentinelResource→ SentinelResourceAspect → blockHandler / fallback
两种回调的区别:
-
blockHandler : 专门处理 Sentinel 限流/熔断异常(
BlockException) -
fallback : 可以处理所有异常,包括业务异常(如
ArithmeticException)
实现示例:
java
@Service
public class OrderServiceImpl implements OrderService {
@SentinelResource(value = "createOrder", blockHandler = "createOrderFallBlock")
@Override
public Order createOrder(Long productId, Long userId) {
Product product = productFeignClient.getProductById(productId);
// 业务逻辑...
return order;
}
// 限流/熔断时的兜底方法
public Order createOrderFallBlock(Long productId, Long userId, BlockException e) {
Order order = new Order();
order.setUserId(userId);
order.setAddress("服务限流:" + e.getClass().getSimpleName());
return order;
}
}
Controller 中使用 fallback:
java
@GetMapping("/seckill")
@SentinelResource(value = "seckill", fallback = "seckillFallback")
public Order seckill(@RequestParam(value = "userId", required = false) Long userId,
@RequestParam("productId") Long productId) {
return orderService.createOrder(productId, userId);
}
// fallback 可以处理所有异常,包括业务异常
public Order seckillFallback(Long userId, Long productId, Throwable e) {
Order order = new Order();
order.setUserId(userId);
order.setAddress("异常信息:" + e.getClass().getSimpleName());
return order;
}
优先级规则: 有 blockHandler 时优先使用 blockHandler ,没有才走 fallback。
三、流控规则详解
流控规则用于限制多余请求,保护系统资源不被耗尽。
3.1 核心概念
-
资源名: 接口路径或方法名
-
流控策略: QPS(每秒请求数) / 并发线程数
-
流控模式: 直接、关联、链路
-
流控效果: 快速失败、Warm Up、排队等待
3.2 流控模式
1) 直接模式(默认)
直接对当前资源进行限流。
场景: 保护单个接口,如秒杀接口 QPS 限制为 1000。
2) 关联模式
当关联资源达到阈值时,限流当前资源。
场景: 资源竞争保护。例如:
-
给 /readDb添加流控规则,关联资源为
/writeDb -
当大量写入请求(
/writeDb)触发阈值时,限制读取请求(/readDb) -
保证写入操作的优先级
实战配置:
java
资源名: /readDb
流控模式: 关联
关联资源: /writeDb
阈值: QPS = 1
3) 链路模式
根据调用链路进行选择性限流。
场景: 同一个服务方法被多个接口调用,只对特定调用链路限流。
示例:
-
createOrder方法同时被/create和/seckill调用 -
给
createOrder添加链路流控,入口资源为/seckill -
结果: 调用
/create不限流,调用/seckill时触发限流
实战配置:
java
资源名: createOrder
流控模式: 链路
入口资源: /seckill
阈值: QPS = 1
3.3 流控效果
1) 快速失败(默认)
达到阈值时直接拒绝请求,抛出 FlowException。
2) Warm Up(预热)
系统逐步增加处理能力,应对冷启动场景。
配置示例:
java
阈值: QPS = 10
预热时长: 3 秒
效果: 初始只能处理约 3.3 QPS(阈值的 1/3),经过 3 秒后逐步达到 10 QPS。
应用场景: 系统刚启动时,缓存未预热、数据库连接池未满,需要逐步增加流量。
3) 排队等待
请求匀速通过,超出阈值的请求排队等待。
限制:
-
不支持 QPS > 1000
-
不支持关联/链路模式
-
需设置超时时间,超时的请求会被拒绝
应用场景: 消息队列消费、数据库批量写入等场景,需要匀速处理避免突刺。
⚠️ 注意: 排队等待和 Warm Up 不支持关联/链路模式,因为它们是对请求进行处理,而非资源处理。
四、熔断降级规则
熔断降级用于切断不稳定的调用,避免雪崩效应。
4.1 断路器工作原理
断路器有三种状态:
java
关闭(Closed) → 打开(Open) → 半开(Half-Open) → 关闭
工作流程:
-
关闭状态: 正常请求通过,统计失败率
-
打开状态: 失败率超过阈值,断路器打开,直接返回降级结果
-
半开状态: 熔断时长后,尝试放行一个请求
-
恢复关闭: 请求成功则关闭断路器,失败则继续打开
4.2 熔断策略
1) 慢调用比例
当慢调用比例超过阈值时熔断。
配置参数:
-
最大 RT: 最大响应时间(毫秒),超过视为慢调用
-
比例阈值: 慢调用比例,范围 0-1,如 0.5 表示 50%
-
最小请求数: 触发熔断的最小请求数
-
统计时长: 统计窗口时长(毫秒)
-
熔断时长: 熔断持续时间(秒)
场景: 下游服务响应变慢,及时熔断避免拖垮上游。
2) 异常比例
当异常比例超过阈值时熔断。
配置参数:
-
比例阈值: 异常请求比例,范围 0-1
-
最小请求数: 触发熔断的最小请求数
-
统计时长: 统计窗口时长(毫秒)
-
熔断时长: 熔断持续时间(秒)
场景: 下游服务频繁报错,快速熔断保护上游。
3) 异常数
当异常数超过阈值时熔断。
配置参数:
-
异常数阈值: 触发熔断的异常请求数
-
最小请求数: 触发熔断的最小请求数
-
统计时长: 统计窗口时长(毫秒)
-
熔断时长: 熔断持续时间(秒)
场景: 低流量场景,异常比例不适用时使用异常数。
五、热点参数限流
热点参数限流针对特定参数值进行细粒度流控。
5.1 基本配置
参数:
-
参数索引: 第几个参数作为热点参数(从 0 开始)
-
单机阈值: 单机 QPS 阈值
-
统计窗口时长: 统计窗口时长(秒)
5.2 实战场景
场景 1: 参数可选时的行为
java
@SentinelResource(value = "seckill")
public Order seckill(@RequestParam(value = "userId", required = false) Long userId,
@RequestParam("productId") Long productId) {
// 业务逻辑...
}
热点规则:
java
参数索引: 0 (userId)
单机阈值: 10
行为 : 携带 **userId**参数的请求参与流控,不携带的不参与流控。
场景 2: VIP 用户不限制
给 SVIP 用户(userId=6)设置更高的 QPS 阈值。
配置:
java
基础阈值: QPS = 10
参数例外项:
- 参数类型: Long
- 参数值: 6
- 限流阈值: 1000
场景 3: 下架商品禁止访问
禁止访问 666 号商品。
配置:
java
参数索引: 1 (productId)
基础阈值: QPS = 100
参数例外项:
- 参数类型: Long
- 参数值: 666
- 限流阈值: 0
六、授权规则
授权规则用于控制调用来源的黑白名单。
6.1 配置方式
在控制台配置:
java
资源名: createOrder
流控应用: order-service,user-service
授权类型: 白名单/黑名单
白名单 : 只允许列表中的调用方访问 黑名单: 拒绝列表中的调用方访问
6.2 应用场景
-
内部服务间调用鉴权
-
防止非法服务调用
-
灰度发布时的流量控制
七、整合 OpenFeign
Sentinel 可以无缝整合 OpenFeign,实现远程调用的熔断降级。
7.1 配置
java
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
eager: true
feign:
sentinel:
enabled: true # 开启 Feign 对 Sentinel 的支持
7.2 实现
当 Feign 调用失败时,会自动触发 fallback 方法:
java
@FeignClient(name = "service-product", fallback = ProductFeignFallback.class)
public interface ProductFeignClient {
@GetMapping("/product/{id}")
Product getProductById(@PathVariable("id") Long id);
}
@Component
public class ProductFeignFallback implements ProductFeignClient {
@Override
public Product getProductById(Long id) {
// 返回降级数据
Product product = new Product();
product.setId(id);
product.setName("商品服务暂时不可用");
return product;
}
}
八、实战总结
8.1 最佳实践
-
合理设置阈值: 根据系统实际容量和压测结果设置,不要拍脑袋
-
分层保护: 网关层 + 服务层双重保护
-
优雅降级: 提供有意义的降级数据,而非简单报错
-
监控告警: 关注 Sentinel 监控面板,及时发现异常
-
持久化规则: 生产环境使用 Nacos 等配置中心持久化规则
8.2 注意事项
-
⚠️ Sentinel 控制台的规则是内存级别,重启后失效,生产环境需配置持久化
-
⚠️
blockHandler和 **fallback**方法的签名要与原方法匹配 -
⚠️ 热点参数限流不支持复杂对象,只支持基本类型和 String
-
⚠️ 链路模式需要设置
web-context-unify: false
8.3 常见问题排查
问题 1: 控制台看不到应用
-
检查 **
dashboard**配置是否正确 -
确认应用已发起过请求(懒加载机制)
-
检查网络连通性
问题 2: 限流不生效
-
检查资源名是否匹配
-
确认规则已正确配置
-
查看 **
web-context-unify**配置(链路模式必须为 false)
问题 3: fallback 未执行
-
检查方法签名是否正确(参数、返回值、异常参数)
-
确认方法访问权限(必须是 public)
-
查看是否配置了
blockHandler(优先级更高)
九、总结
Sentinel 作为微服务保护的利器,提供了丰富的流量控制和熔断降级能力。掌握以下核心要点,就能在实际项目中灵活运用:
✅ 流控 : 直接/关联/链路三种模式应对不同场景 ✅ 熔断 : 慢调用/异常比例/异常数三种策略保护系统 ✅ 热点 : 针对特定参数值的细粒度流控 ✅ 降级 : blockHandler 处理限流,fallback 处理所有异常 ✅ 监控: 实时监控面板,快速发现和定位问题
通过本文的学习,你已经掌握了 Sentinel 的主要核心功能和实战技巧。
相关资源: