Sentinel 是由阿里巴巴开源的一个面向分布式、多语言异构化服务架构的流量治理组件,提供流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等功能
两大核心概念:
资源 (Resource) :可以是任何东西,比如一个 HTTP 接口、一段 Java 方法。只要通过Sentinel API或注解(
@SentinelResource)包裹起来,它就是被保护的资源规则 (Rule):定义如何保护资源。包含流控规则、熔断规则、热点规则、系统规则等
Sentinel使用
Sentinel由两部分组成,核心库(Java 客户端) : 不依赖任何框架/库, 能够运行于所有 Java 运行时环境, 同时对Spring Cloud 等框架也有较好的支持;控制台(Dashboard) 基于 Spring Boot 开发, 打包后可以直接运行
Sentinel Dashboard
-
下载
-
启动,将jar放在一个目录下,用cmd打开这个文件夹
java -jar .\文件名 -
默认用户名和密码都是sentinel
核心库
独立使用
-
引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.6</version> </dependency> -
定义资源
java//通过try-catch try(Entry entry= SphU.entry("资源名称")){ //被保护的逻辑 }catch (BlockException ex){ //请求被拒绝的逻辑 } -
定义规则
javaprivate static void initFlowRules(){ //新建规则集合 List<FlowRule> rules = new ArrayList<>(); //新建规则 FlowRule rule = new FlowRule(); //添加资源 rule.setResource("资源名称"); //设置限流维度为 QPS rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置每秒多少请求 rule.setCount(20); rules.add(rule); 添加规则 FlowRuleManager.loadRules(rules); }
Spring项目
-
添加依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> -
添加配置
yamlspring: cloud: sentinel: transport: dashboard: # sentinel控制台地址 client-ip: # 连接本地Sentinel可以不配置,连接服务器Sentinel需要配置client-ip -
Sentinel starter默认对Spring MVC的所有HTTP服务进行限流,如果想要对非HTTP服务进行限流或者降级, 则需要在方法上添加@SentinelResource("资源名")
流量控制
流控规则
QPS:控制每秒请求数
并发线程数:表示最多只给 /order/{orderId} 分配的线程个数,防止因为接口响应过慢导致线程池耗尽

流控效果
- 快速失败:丢弃超过阈值的请求,对应
RuleConstant.CONTROL_BEHAVIOR_DEFAULT,适用于通过压测确定系统的抗压能力。底层主要依赖滑动窗口算法 - Warm Up:也叫预热模式,单机阈值一般设置为一个微服务能够承受的最大QPS。一个服务器刚启动时,资源还没有初始化,处理请求的速度远不及正常情况下的最大QPS。此时如果之间将QPS跑到最大值,会直接导致服务器宕机。预热模式则利用冷启动算法,系统起始放行的 QPS 只是
单机阈值 / 冷启动因子(默认3)。在随后的预热时长 内,逐步将QPS上限拉升到填写的标准阈值。对应RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER。 - 排队等待:同一时间的请求会放到一个队列中,按照阈值允许的时间间隔依次执行。比如当QPS=5时,系统会每隔200ms(
1000ms/5)从队列中取出并处理一个请求。如果在队列里等待请求超过了 超时时间,就会被丢弃
流控模式
-
直接模式:根据自身收到的流量判断,不区分流量的来源

-
链路模式:针对同一个底层公共方法或者接口,只拦截特定上游来源的流量

链路模式中,是对不同来源的两个链路做监,但是sentinel会默认给所有进入SpringMVC的请求设置同 一个root资源, 会导致链路模式失效. 所以需要关闭这种对SpringMVC的资源聚合
yamlspring: cloud: sentinel: web-context-unify: false -
关联模式:
关联资源:两个资源之间具有资源争抢或者依赖关系的时,比如读请求和写请求都依赖于数据库,则称这两个资源为关联资源
关联模式:两个资源存在资源抢占时,关联资源超过单机阈值,就会对当前资源进行拦截(关联资源正常提供服务)。当关联资源低于阈值时,再对当前资源进行放行

热点参数限流
热点参数限流表示以资源参数值为维度进行限流,对于/product/{productId}接口,如果大家都在访问id为1的商品,这时可以对productId=1这个参数进行单独的流量控制,比如将单点阈值适当增加
对相同参数进行统一限流

- 定义资源,热点参数限流对默认的Spring MVC 资源无效, 需要在资源上加 @SentinelResource("资源名")注解
- 表示对于第一个参数的相同参数值每秒请求数不能超过5
对相同参数进行额外限流

表示对参数为1的请求限制阈值为10,其余参数值的阈值不变
限流算法
计数器算法
将时间划分为一个个固定大小的时间窗口,每个窗口单独维护一个计数器。当计数器超过阈值时,拒绝请求,时间进入下一个窗口时,计数器重置为0
缺点:假设QPS=100,在0.8s ~ 1.0s和0.8s ~ 1.2s两个时间段内各放行100个请求,那是在0.4s内服务器就会收到200个请求,大量请求会被拒绝
滑动窗口算法
将时间划分为更高的精细度,假设将1s划分为5块,每块为200ms。那么窗口每200ms会往前移一格,每次需要保证当前窗口内的请求数不超过QPS

Sentinel 底层就是通过滑动窗口算法实现的
漏桶限流算法
进水:用户的请求会放入一个队列中
漏水:服务器以固定速度从队列中取出数据并处理请求
溢出:队列满时,超过队列容量的请求会触发限流

适用于数据库操作,防止高并发情况造成的数据库服务器宕机
令牌桶限流算法
发放令牌:服务器以固定速率往桶内放入令牌,桶内令牌数达到上限,后续的令牌直接丢弃
消耗令牌:每个到达的请求都需要从桶中拿取固定数目的令牌,只有拿到足够令牌的请求才被允许通过,如果拿到的令牌数不够则触发限流。可以处理突发请求,Spring Cloud Gateway的RequestRateLimiter底层就是使用令牌桶算法实现限流功能
熔断降级
为了保证系统的高可用而做出的额外逻辑
熔断:当上游服务器A访问下游服务器B时,发现服务器B频繁超时或者报错,那么服务器A就不会真正调用服务器B,而是直接返回
降级:当下游服务器宕机,为了避免返回空数据,系统自动降级,返回默认数据

熔断策略
决定什么时候触发熔断
-
慢调用比例
超过最大响应的时间(RT)的调用称为慢调用,当请求数量 > 设定的最小数量, 且慢调用比例 > 设定的阈值时触发熔断
-
异常比例
统计时长内, 当请求数量 > 设置的最小数量, 且异常比例大于阈值时触发熔断
-
异常数
统计时长内,当异常数目超过阈值时触发熔断
状态机

- 关闭状态:请求正常通过,Sentinel在后台收集慢响应和异常数据
- 熔断状态:触发熔断条件,在休眠时间窗口内,所有的新请求都会走降级逻辑
- 半开状态:休眠时间结束后,先放行少量请求,根据失败率来判断是否恢复正常
FallbackFactory
FallbackFactory是微服务架构中用于实现服务降级调用的接口,当远程调用失败或者超时时,FallbackFactory会根据异常信息创建一个降级处理实例,代替原服务调用。对于熔断和限流都有效
-
开启配置
feign: sentinel: enabled: true -
编写FallbackFactory实现类
javapublic class ProductFallBackFactory implements FallbackFactory<productAPI> { @Override public productAPI create(Throwable cause) { return new productAPI() {}; } } -
在接口上配置FallbackFactory实现类
java@FeignClient(value = "product-service",path = "/product",fallbackFactory = ProductFallBackFactory.class) public interface productAPI { } -
定义DefaultFeignConfiguration类,并在类中添加ProductFallBackFactory的Bean,最后将DefaultFeignConfiguration交给Spring进行管理
java//Public-API public class DefaultFeignConfiguration { @Bean public ProductFallBackFactory productFallBackFactory(){ return new ProductFallBackFactory(); } } // 启动类 @EnableFeignClients(clients ={productAPI.class} ,defaultConfiguration = DefaultFeignConfiguration.class)
授权规则
一种黑白名单机制,根据调用方的身份,决定是否允许其访问指定的受保护的资源
Sentinel提供了两种授权模式:白名单和黑名单
白名单模式:只有在白名单内才允许访问
黑名单模式:黑名单内不允许访问,并抛出AuthorityException异常,其余请求允许访问
配置
-
实现RequestOriginParser接口,从请求中提取出带有调用方身份的字符串(一般放到Header中),并交给Spring进行管理
java@Configuration public class HeaderOriginParser implements RequestOriginParser { @Override public String parseOrigin(HttpServletRequest request) { String origin=request.getHeader("origin"); ... return origin; } } -
配置请求头
gateway:
yamlspring: cloud: gateway: default-filters: - AddRequestHeader=origin,gateway #AddRequestHeader是gateway自带的请求头过滤器 -
配置授权规则

定义异常返回结果
实现BlockExceptionHandler接口
java
@Component
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
//设置编码
response.setContentType("text/html;charset=utf-8");
String msg="Blocked by Sentinel (flow limiting)";
int status=429;
if (e instanceof AuthorityException){
status=401;
msg="授权失败";
}else if (e instanceof DegradeException){
msg="触发降级";
}else if (e instanceof FlowException){
System.out.println("触发限流");
}else if (e instanceof ParamFlowException){
msg="触发热点限流";
}
response.setStatus(status);
PrintWriter printWriter=response.getWriter();
printWriter.print(msg);
printWriter.flush();
printWriter.close();
}
}
规则管理及推送
| 特性 | 原始模式 (In-Memory) | 拉模式 (Pull) | 推模式 (Push) |
|---|---|---|---|
| 规则持久化 | 不持久化 (重启即失) | 持久化 (文件/数据库) | 持久化 (Nacos/Apollo 等) |
| 规则生效实时性 | 实时 | 有延迟 (取决于轮询周期) | 毫秒级实时 (配置中心推送) |
| 对配置中心依赖 | 无依赖 | 无或弱依赖 | 强依赖 (需要 Nacos/Apollo) |
| 多实例同步/集群扩展 | 无法自动同步 | 自动同步 (轮询) | 自动同步 (订阅通知) |
| 适用场景 | 本地开发、测试验证 | 简单单机/小规模环境 | 生产环境标准方案 |
Pull模式
Sentinel控制台通过API将规则推送给客户端,由客户端负责在内存中更新规则并将规则写入本地文件

实现
java
public class FileDataSourceInit implements InitFunc {
@Override
public void init() throws Exception {
//定义文件路径
String ruleDir = System.getProperty("user.home") +
"/sentinel/rules/orderService";
//定义文件名,不同规则要定义不同的文件,这里以流控规则为例
String flowRulePath = ruleDir + "/flow-rule.json";
//创建文件夹
mkdirIfNotExist(ruleDir);
//创建文件
createFileIfNotExist(flowRulePath);
// 注册一个可读数据源,用来定时读取本地的json文件,更新到规则缓存中
// 流控规则
ReadableDataSource<String, List<FlowRule>> ds = new
FileRefreshableDataSource<>(
flowRulePath, source -> JSON.parseObject(source, new
TypeReference<List<FlowRule>>() {})
);
// 将可读数据源注册至FlowRuleManager
// 这样当规则文件发生变化时,就会更新规则到内存
FlowRuleManager.register2Property(ds.getProperty());
WritableDataSource<List<FlowRule>> flowRuleWDS = new
FileWritableDataSource<>(
flowRulePath,
this::encodeJson
);
// 将可写数据源注册至transport模块的WritableDataSourceRegistry中
// 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
}
private <T> String encodeJson(T t) {
return JSON.toJSONString(t);
}
private void mkdirIfNotExist(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
}
private void createFileIfNotExist(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
file.createNewFile();
}
}
}
在resources下创建META-INF/services目录,并创建文件: com.alibaba.csp.sentinel.init.InitFunc, 文件内填写本地数据源的路径
com.object.FileDataSourceInit
Push模式
由控制台负责将配置推送到远程配置中心,数据源负责获取远程配置中心的配置并更新到本地

不修改源码
控制台对规则的修改无法同步到配置中心,只能接收配置中心的数据
-
添加依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> -
注册数据源
javapublic class NacosDataSourceInit implements InitFunc { // nacos server ip private static final String remoteAddress = ""; // nacos group private static final String groupId = ""; // nacos dataId private static final String dataId = ""; @Override public void init() throws Exception { ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() { })); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); } } -
配置数据源路径,在resources下创建META-INF/services目录,并创建文件: com.alibaba.csp.sentinel.init.InitFunc, 文件内填写本地数据源的路径
com.object.NacosDataSourceInit
-
配置nacos
json[ { "clusterMode": false, "controlBehavior": 0, "count": 88.0, "grade": 1, "limitApp": "default", "maxQueueingTimeMs": 500, "resource": "/order/{orderId}", "strategy": 0, "warmUpPeriodSec": 10 } ]
源码改造
可以和配置中心双向通信
https://github.com/alibaba/Sentinel/releases
以下修改全部基于sentinel-dashboard源码
-
修改pom文件

-
将test下的com.alibaba.csp.sentinel.dashboard.rule.nacos复制到src/main/java/com.alibaba.csp.sentinel.dashboard.rule

-
修改com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfig,将默认地址修改为自己的Nacos地址
-
修改com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2为

-
修改前端页面
-
修改src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html,将以下注释取消

-
修改src/main/webapp/resources/app/scripts/controllers/identity.js,将第4行左右的FlowServiceV1 修改为 FlowServiceV2
-
修改第98行左右的/dashboard/flow/ -> /dashboard/v2/flow/
-
-
将sentinel-dashboard重新打包,然后启动,需要清理浏览器缓存
-
配置nacos
-
引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> -
配置nacos地址
yamlspring: cloud: sentinel: datasource: flow-rules: #流控规则 nacos: server-addr: 192.168.109.130:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow
-