Sentinel简介
官方定义:Sentinel 是阿里巴巴开源的分布式系统流量防卫兵,专注于流量控制、熔断降级、系统负载保护和热点防护,目的是保障分布式系统的稳定性。
通俗理解:Sentinel 就像我们服务的"智能保镖",它24小时监控服务的流量、接口调用、系统资源状态,当发现异常(流量超负载、下游服务故障、系统资源耗尽)时,会自动采取"限流、熔断、降级"等措施,挡住风险,保护服务不被拖垮,同时尽可能保证核心功能的可用性。
与传统的限流工具(如Guava RateLimiter)相比,Sentinel 的核心优势在于"分布式支持、可视化管控、动态规则、场景丰富",不仅能解决单体服务的流量问题,更能适配大规模微服务集群的治理需求。
一、核心定位与价值
- 定位:面向分布式、多语言架构的流量控制 / 熔断降级组件,以流量为切入点保障服务稳定。
- 核心价值 :
- 防止流量洪峰压垮服务(如秒杀、大促)
- 阻断服务故障雪崩(依赖服务异常不扩散)
- 提供实时监控与动态规则,降低运维成本
二、三大核心能力
1. 流量控制(限流)
- 目标 :限制资源访问的QPS / 线程数,削峰填谷。
- 策略 :
- 直接拒绝(快速失败)
- 排队等待(匀速通过)
- 预热启动(冷启动场景)
- 热点参数限流(如按用户 ID / 商品 ID 限流)
2. 熔断降级
- 目标 :当依赖服务异常 / 超时 / 错误率过高时,快速切断调用,返回降级结果。
- 触发条件 :
- 异常比例 / 错误数
- 慢调用比例(RT 超过阈值)
- 并发线程数
- 降级策略:返回默认值、执行本地逻辑、静默失败。
3. 系统自适应保护
- 目标 :从全局系统维度(CPU/Load/RT/QPS)自动调整流量,防止整体过载。
- 机制:根据系统负载实时调整准入阈值,避免单点故障拖垮全局。
三、核心组件与架构
| 组件 | 作用 | 部署方式 |
|---|---|---|
| Sentinel Client | 核心 SDK,嵌入应用,执行限流 / 熔断逻辑、采集指标 | 引入 Jar 包(Java)/SDK(Go/C++) |
| Sentinel Dashboard | 可视化控制台:配置规则、实时监控、查看集群状态 | 独立 Web 应用(Spring Boot) |
| 规则中心 | 存储限流 / 熔断规则(支持 Nacos/Apollo/ 本地文件) | 独立配置中心 |
四、工作流程
- 定义资源:接口 / 方法 / URL / 代码块(Sentinel 保护的最小单元)。
- 埋点统计:Client 实时统计资源的 QPS、RT、异常数等指标。
- 规则匹配:按预设规则判断是否限流 / 熔断。
- 执行策略:放行、拒绝、排队或降级。
- 监控上报:数据同步到 Dashboard,可视化展示。
下载控制台
sentinel-dashboard 是阿里巴巴 Sentinel 流量治理组件的可视化控制台,核心用来:
- 监控:实时查看业务服务中各接口 / 方法的流量、QPS、异常、限流熔断触发情况;
- 配置:通过网页界面快速设置 / 修改限流、熔断、降级等规则,规则实时生效无需重启服务;
- 管理:统一维护所有流量规则,是管控 Sentinel 核心能力的「操作面板」。
安装sentinel-dashboard ,访问https://github.com/alibaba/Sentinel/releases,下载对应jar包,下载好之后放到指定目录,在下载目录输入cmd打开控制台
控制台打开后输入java -jar sentinel-dashboard-1.8.8.jar,启动控制台
启动完成访问8080端口打开控制台
账号密码默认为:sentinel
集成 Sentinel
- 引入依赖
在services父模块中引入sentinel依赖:
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.加配置:
在项目的yml文件中加上一段sentienl的配置

配置加完打开控制台,就能在控制台中定义一些规则
3.标记资源(@SentinelResource注解)
使用@SentinelResource注解标记需要保护的资源(接口、方法),并配置限流/熔断的兜底方法(自定义异常提示)
例如在订单服务的创建订单的方法上添加一个@SentinelResource,value为createOrder然后我们去请求一下create
请求成功之后我们可以来到sentienl控制台簇点链路中可以看到调用链的过程
我们可以看到我们发起了一个create请求然后他认为create是一个资源,而create请求又调用了createOrder而createOrder是我们通过注解定义的资源,sentienl也会认为这是一个资源,我们可以对任意一个资源进行一些控制,比如上面的,流控、熔断、热点、授权。
我们来测试一下流控
点击流控,可以看到我们可以配置QPS也就是每秒的并发数,并设置阈值,或者并发线程的数量
我们配置一个QPS为1来进行测试
创建好以后可以在流控规则中看到对应的规则
我们来测试一下流控是否有效,继续访问localhost:8000/create,并快速点击刷新让其每秒访问次数超过1次
可以看到他会出现一个Blocked by Sentinel (flow limiting)也就是被Sentinel给限制访问了
Sentienl异常处理
从上面的例子可以看到如果我们的请求被Sentienl限制默认会返回Blocked by Sentinel (flow limiting)这当然不是我们需要的,那我们可以进行处理
当我们触发了Sentienl限制后他会抛出一个BlockException异常这是个父类异常:
BlockException 的继承体系,它是 Sentinel 触发防护规则时抛出的顶层异常,下面有 5 个具体的实现类,分别对应不同的防护场景:
| 异常类名 | 全限定名 | 触发场景 |
|---|---|---|
| AuthorityException | com.alibaba.csp.sentinel.slots.block.authority |
触发授权规则(如未授权的来源 IP / 服务调用) |
| DegradeException | com.alibaba.csp.sentinel.slots.block.degrade |
触发降级规则(如下游服务熔断、RT / 异常比例超标) |
| FlowException | com.alibaba.csp.sentinel.slots.block.flow |
触发流控规则(如 QPS / 线程数超过阈值) |
| ParamFlowException | com.alibaba.csp.sentinel.slots.block.flow.param |
触发热点规则(如热点参数访问频率超标) |
| SystemBlockException | com.alibaba.csp.sentinel.slots.block.system |
触发系统规则(如 CPU / 负载 / 线程数超过阈值) |
而对于这些异常由于资源方式的不同又会有不同的处理机制,我们先来针对Web接口来做一个处理
BlockExceptionHandler实现
1.创建一个MyBlockExceptionHandel类并实现BlockExceptionHandel这是Sentinel专门用于处理SpringMVC这些web接口的异常,再去重写它的handle方法:
2.在方法内只需要通过httpServletResponse.getWriter()去写一个JSON数据对于这个JSON数据我们可以定义一个通用的返回对象 R对象,在公共的Model模块下去创建一个通用的包common,去创建一个R对象:
完整代码:
java
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code;
private String message;
private T data;
private Long timestamp;
public R() {
this.timestamp = System.currentTimeMillis();
}
public R(Integer code, String message) {
this();
this.code = code;
this.message = message;
}
public R(Integer code, String message, T data) {
this(code, message);
this.data = data;
}
// 成功响应,无数据
public static <T> R<T> ok() {
return new R<>(200, "操作成功");
}
// 成功响应,带消息
public static <T> R<T> ok(String message) {
return new R<>(200, message);
}
// 成功响应,带数据
public static <T> R<T> ok(T data) {
return new R<>(200, "操作成功", data);
}
// 成功响应,带消息和数据
public static <T> R<T> ok(String message, T data) {
return new R<>(200, message, data);
}
// 失败响应,默认500错误
public static <T> R<T> error() {
return new R<>(500, "操作失败");
}
// 失败响应,带消息
public static <T> R<T> error(String message) {
return new R<>(500, message);
}
// 失败响应,指定状态码和消息
public static <T> R<T> error(Integer code, String message) {
return new R<>(code, message);
}
// 失败响应,指定状态码、消息和数据
public static <T> R<T> error(Integer code, String message, T data) {
return new R<>(code, message, data);
}
// getter和setter方法
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
return "R{" +
"code=" + code +
", message='" + message + '\'' +
", data=" + data +
", timestamp=" + timestamp +
'}';
}
}
3.MyBlockExceptionHandle完整实现:
java
@Component
public class MyBlockExceptionHandle implements BlockExceptionHandler {
// 创建一个ObjectMapper对象
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void handle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, String s, BlockException e) throws Exception {
// 设置响应的Content-Type为JSON
httpServletResponse.setContentType("application/json;charset=UTF-8");
// 获取响应的输出流
PrintWriter writer = httpServletResponse.getWriter();
// 创建一个R对象,并设置错误信息
R<Object> error = R.error(500, s + "被Sentinel限制了,原因:" + e.getClass());
String json = objectMapper.writeValueAsString(error); // 将对象转为JSON
// 将JSON写入响应的输出流
writer.write(json);
writer.flush();
writer.close();
}
}
4.重启项目进行测试,注意重启项目后需要再次配置规则,然后连续点击刷新触发限流查看它的响应:
可以看到成功的响应了JSON格式
@SentinelResource注解实现
通过@SentinelResource注解的两个核心属性,分别处理"阻塞异常"和"业务异常",配置简单、无侵入,适合绝大多数业务场景,也是实战中最常用的方式。
核心属性说明:
-
blockHandler:专门处理 BlockException(阻塞异常),兜底方法需满足两个条件:① 与原方法参数完全一致;② 最后多一个 BlockException 类型的参数(用于接收具体的阻塞异常);
-
fallback:专门处理 业务异常(包括自定义异常、运行时异常),兜底方法需与原方法参数完全一致,无需额外参数;
-
fallbackClass(可选):当兜底方法不在当前类时,指定兜底类(兜底类中的方法需为 static 修饰),解决"兜底方法冗余"问题。
blockHandler实现:

java
// 兜底处理
public Order createOrderFallBack(Long productId, Long userId, BlockException throwable){
Order order = new Order();
order.setId(0L);
order.setTotalAmount(new BigDecimal(0));
order.setUserId(0L);
order.setNickName("未知用户");
order.setAddress("未知地址");
order.setProductList(null);
return order;
}
流控规则
一、流控模式(决定对谁限流)
-
直接(默认)
- 直接对当前资源(这里是
createOrder)进行流量控制。 - 当
createOrder的 QPS 或并发数超过阈值时,直接触发限流。 - 适用场景:最常用的基础限流,比如限制下单接口每秒最多 100 次。
- 直接对当前资源(这里是
-
关联
- 当关联的另一个资源达到阈值时,对当前资源进行限流。
- 例如:当支付接口
pay超过阈值时,限制下单接口createOrder,以保护核心支付链路。 - 适用场景:读写分离、核心业务优先保障。
-
链路
- 只对从指定调用链路过来的请求进行限流,而不是所有访问该资源的请求。
- 例如:只限制从商品详情页过来的下单请求,而不限制从购物车过来的。
- 适用场景:精细化控制不同入口的流量。
二、流控效果(决定超过阈值后怎么处理)
-
快速失败(默认)
- 当请求超过阈值时,立即拒绝并抛出
FlowException。 - 响应最快,适合对延迟敏感、非核心的接口。
- 适用场景:秒杀、抢购等需要快速拒绝多余流量的场景。
- 当请求超过阈值时,立即拒绝并抛出
-
Warm Up(预热)
- 服务刚启动时,阈值从一个较低值缓慢提升到设定的最大值,避免冷启动时被瞬间流量打垮。
- 例如:设定阈值 100,预热时长 10 秒,则前 10 秒阈值逐步从 30 升到 100。
- 适用场景:服务重启、系统初始化后,防止流量突增导致服务不可用。
-
排队等待
- 请求会进入队列,按照固定的时间间隔依次处理,保证请求间的间隔不小于
1000ms / QPS阈值。 - 如果等待时间超过设定的超时时间,则拒绝请求。
- 适用场景:需要平滑处理流量、避免毛刺的场景,如消息队列消费、定时任务。
- 请求会进入队列,按照固定的时间间隔依次处理,保证请求间的间隔不小于
熔断规则
在 Sentinel 里,熔断规则是为了防止某个不稳定的依赖服务把整个系统拖垮,当它出现大量错误或响应变慢时,就会暂时切断对它的调用,让系统有时间恢复。
一、熔断策略(触发条件)
-
慢调用比例(SLOW_REQUEST_RATIO)
- 以慢调用比例作为阈值。当单位统计时长内,请求的响应时间超过设定的最大 RT(慢调用)的比例超过阈值时,触发熔断。
- 适用场景:依赖服务响应变慢,需要及时切断调用,避免拖慢整个链路。
-
异常比例(ERROR_RATIO)
- 以异常比例作为阈值。当单位统计时长内,业务异常的比例超过阈值时,触发熔断。
- 适用场景:依赖服务频繁抛出业务异常,继续调用也大概率失败,此时熔断可以节省资源。
-
异常数(ERROR_COUNT)
- 以异常数作为阈值。当单位统计时长内,业务异常的次数超过阈值时,触发熔断。
- 适用场景:对异常数量敏感的场景,比如支付接口,短时间内出现多次失败就需要熔断。
二、核心配置项
表格
| 配置项 | 说明 |
|---|---|
| 资源名 | 需要熔断的资源名称,例如 createOrder |
| 熔断策略 | 选择慢调用比例、异常比例或异常数 |
| 阈值 | 触发熔断的阈值,比例为 0-1 之间的小数,异常数为整数 |
| 熔断时长 | 熔断触发后,持续多久不允许访问该资源(单位:秒) |
| 统计时长 | 用于统计慢调用或异常的时间窗口(单位:秒) |
| 最小请求数 | 在统计时长内,至少达到多少请求才开始统计熔断条件,避免少量请求就误判 |
| 最大 RT(慢调用策略) | 超过这个响应时间的请求会被统计为慢调用 |
三、熔断状态流转
- 关闭(CLOSED):服务正常,所有请求都可以通过。
- 打开(OPEN):触发熔断条件,所有对该资源的请求直接被拒绝,返回降级结果。
- 半开(HALF_OPEN) :熔断时长结束后,进入半开状态,允许少量请求通过,用于探测服务是否恢复。
- 如果探测成功,恢复到关闭状态。
- 如果探测失败,再次进入打开状态。
四、示例配置
以 createOrder 为例,配置一个基于异常比例的熔断规则:
- 资源名:
createOrder - 熔断策略:异常比例
- 阈值:0.5(50%)
- 统计时长:10 秒
- 最小请求数:10
- 熔断时长:30 秒
含义:在 10 秒内,如果 createOrder 收到至少 10 个请求,且其中超过 50% 的请求抛出业务异常,就触发熔断,接下来 30 秒内所有对 createOrder 的请求都会被直接拒绝。
热点规则
在 Sentinel 中,热点规则(热点参数限流) 是一种更细粒度的流控策略,它可以针对资源中某个具体的热点参数(比如用户 ID、商品 ID、IP 地址等)进行单独限流,而不是对整个资源进行一刀切的限制。
一、核心概念
- 热点参数:指在请求中频繁出现的参数值,比如某个热门商品 ID、高频访问的用户 ID。
- 隔离限流:对这些热点参数单独设置阈值,防止单个热点参数耗尽整个资源的容量,保证其他参数的请求也能正常处理。
二、适用场景
- 热门商品秒杀:限制单个商品 ID 的请求 QPS,防止某个爆款商品的流量压垮整个下单服务。
- 用户行为限制:限制单个用户 ID 的请求频率,防止恶意刷接口。
- IP 限流:限制单个 IP 地址的访问次数,防止爬虫或攻击。
三、核心配置项
| 配置项 | 说明 |
|---|---|
| 资源名 | 需要限流的资源,如 createOrder |
| 参数索引 | 热点参数在方法参数列表中的位置(从 0 开始),例如 createOrder(String userId, String productId) 中,productId 的索引是 1 |
| 统计窗口时长 | 统计热点参数请求的时间窗口(单位:秒) |
| 单机阈值 | 单个热点参数在统计窗口内的最大请求数 |
| 参数例外项 | 对特定参数值设置单独的阈值,比如对 VIP 用户 ID 不限制,或对特定商品设置更高阈值 |
四、示例配置
以 createOrder(String userId, String productId) 为例,配置热点规则:
- 资源名:
createOrder - 参数索引:1(对
productId限流) - 统计窗口时长:1 秒
- 单机阈值:10
- 参数例外项:
productId = "123456",阈值设置为 100
含义:
- 对所有商品 ID,每秒最多允许 10 次下单请求。
- 对热门商品 ID
123456,单独放宽到每秒 100 次请求。
五、工作原理
- 参数提取:Sentinel 会根据配置的参数索引,从请求中提取热点参数值。
- 统计计数:在滑动时间窗口内,对每个参数值的请求次数进行独立统计。
- 阈值判断:当某个参数值的请求次数超过设定阈值时,对该参数值的后续请求进行限流,其他参数值的请求不受影响。
Sentinel持久化
Sentinel 本身默认是将规则保存在内存中的,应用重启后规则就会消失,所以持久化的核心思路是将规则同步到外部存储(如 Nacos、Apollo、ZooKeeper 等),并实现规则的动态推送和拉取 。下面我以最常用的 Nacos 为例,详细讲解实现步骤。
一、实现思路
- 规则写入:通过 Sentinel 控制台配置规则时,将规则同步写入 Nacos。
- 规则读取:应用启动时从 Nacos 拉取规则并加载到 Sentinel 内存中。
- 动态监听:监听 Nacos 配置变化,实时更新 Sentinel 内存中的规则。
二、具体实现步骤(基于 Spring Cloud Alibaba)
1. 引入依赖
在项目的 pom.xml 中添加 Sentinel 与 Nacos 集成的依赖:
XML
<!-- 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>
<!-- Nacos 客户端依赖 -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
2. 配置 Nacos 数据源(application.yml)
spring:
cloud:
sentinel:
# Sentinel 控制台地址
transport:
dashboard: localhost:8080
# 配置 Nacos 作为规则持久化数据源
datasource:
# 自定义数据源名称(如 flow 表示流控规则)
flow:
nacos:
server-addr: localhost:8848 # Nacos 服务地址
data-id: ${spring.application.name}-sentinel-flow # 配置文件ID
group-id: DEFAULT_GROUP # 分组
data-type: json # 数据格式
rule-type: flow # 规则类型(flow:流控 / degrade:降级 / authority:授权 / param-flow:热点参数)
# 可选:配置降级规则持久化
degrade:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}-sentinel-degrade
group-id: DEFAULT_GROUP
data-type: json
rule-type: degrade
3. 自定义 Sentinel 控制台规则同步(关键)
Sentinel 控制台默认不会将规则推送到 Nacos,需要修改控制台的代码,实现规则配置后同步到 Nacos:
注:需下载 Sentinel 控制台源码(官方源码),修改
sentinel-dashboard模块。
步骤 1:给控制台添加 Nacos 依赖
在 sentinel-dashboard/pom.xml 中添加:
XML
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
</dependency>
步骤 2:实现 Nacos 规则推送类
java
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
// 流控规则推送到 Nacos
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<FlowRuleEntity>, String> converter;
// Nacos 配置ID(需和应用端配置一致)
public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow";
public static final String GROUP_ID = "DEFAULT_GROUP";
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
if (app == null || app.isEmpty()) {
throw new IllegalArgumentException("应用名称不能为空");
}
// 转换规则为 JSON 字符串
String ruleJson = converter.convert(rules);
// 写入 Nacos
configService.publishConfig(app + FLOW_DATA_ID_POSTFIX, GROUP_ID, ruleJson);
}
}
步骤 3:修改控制台的规则控制器
找到 FlowControllerV2 类,注入上面的 FlowRuleNacosPublisher,并修改保存 / 删除规则的方法:
java
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
// 保存规则
@PostMapping("/rule")
public Result<FlowRuleEntity> addFlowRule(@RequestBody FlowRuleEntity entity) {
// 原有保存逻辑...
// 新增:推送到 Nacos
publishRules(entity.getApp());
return Result.success(entity);
}
// 推送规则到 Nacos
private void publishRules(String app) throws Exception {
List<FlowRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
4. 测试验证
- 启动 Nacos 服务(默认端口 8848)。
- 启动修改后的 Sentinel 控制台(端口 8080)。
- 启动你的应用,访问 Sentinel 控制台配置流控规则。
- 打开 Nacos 控制台(http://localhost:8848/nacos),查看配置列表,能看到生成的规则配置文件。
- 重启应用,检查 Sentinel 控制台中规则是否还存在(存在则持久化成功)。
