官方文档:https://github.com/alibaba/Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
服务端启动
下载地址:https://github.com/alibaba/Sentinel/releases
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
客户端配置
默认需要依赖 spring-cloud-alibaba-dependencies
父 pom 依赖
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>客户端依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>客户端配置
spring: cloud: sentinel: transport: port: 8719 dashboard: localhost:8080 # 服务端地址限流规则

阈值类型
- QPS
- 每秒访问的次数
- 线程数
- 可以支持多少线程提供资源访问
流控模式
- 直接
- 就是直接针对当前访问的资源
- 关联
- 当配置了关联资源的时候,如果当前访问资源超过了配置的阈值,那么被关联的资源将被限流
- 如:根据库存的服务关联订单的服务,当库存达到阈值的时候,会限制订单,这样用户就不能访问订单了,从而从源头控制了流量
- 链路
- 当多个资源都需要访问一个资源的时候,可以根据链路设置流量控制
流控效果
- 快速失败
- 默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出
FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时
- 默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出
- Warm Up
- Warm Up(
RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档 - 阈值:有两个含义,正常情况下,阈值为所设置的
阈值 / 3,所设置的阈值为最大阈值 - 预热时常:当超过正常阈值后,多少秒内,阈值会达到最大阈值数量
- Warm Up(
- 排队等待(**匀速排队)**
- 匀速排队(
RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式 - 超时事件:指超过等待多久没有得到执行的请求,将会移除队列,直接报错
- 匀速排队(
降级规则
我们通常用以下几种方式来衡量资源是否处于稳定的状态:
平均响应时间 (
DEGRADE_GRADE_RT):当 1s 内持续进入 N 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule中的timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限,可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=xxx来配置。- RT:一秒内 5 个请求的平均响应时间
- 时间窗口:熔断后多少秒内恢复
异常比例 (
DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= N(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule中的timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0, 1.0],代表 0% - 100%。- 异常比例:小数,
[0.0, 1.0] - 时间窗口:熔断后多少秒内恢复
- 异常比例:小数,
异常数 (
DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow小于 60s,则结束熔断状态后仍可能再进入熔断状态。- 异常数:1 分钟之内异常的数量
- 时间窗口:熔断后多少秒内恢复
注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。示例:
Entry entry = null;
try {
entry = SphU.entry(key, EntryType.IN, key);
// Write your biz code here.
// <<BIZ CODE>>
} catch (Throwable t) {
if (!BlockException.isBlockException(t)) {
Tracer.trace(t);
}
} finally {
if (entry != null) {
entry.exit();
}
}
热点规则
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
- 参数索引:从 0 开始,表示第一个参数
- 单机阈值:QPS
- 窗口时长:表示流量控制时间
要是用流控,必须使用 @SentinelResource 注解
@GetMapping("/backend")
@SentinelResource(value = "/backend", blockHandler = "blockBackend", blockHandlerClass = BlockHandler.class)
public String backend(String name) {
System.out.println("name = " + name);
return testService.test();
}
如果需要定义具体值进行热点限流的话,需要将普通限流数调大

系统规则
针对全局资源的控制,配置的时候系统默认规则要大于自定义的规则

- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的
maxQps * minRt估算得出。设定参考值一般是CPU cores * 2.5。 - CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
自定义异常信息
异常方法要和资源的方法参数签名一致,否则不生效
- blockHandler:是针对流控
- blockHandlerClass:流控处理类
- fallback:正对内部异常
- fallbackClass:内部异常处理累
单独配置
@GetMapping("/echo")
@SentinelResource(value = "/echo", blockHandler = "blockEcho", fallback = "fallbackEcho")
public String echo(String name) {
System.out.println("echo = " + new Date());
if (RandomUtils.nextBoolean()) {
throw new RuntimeException("xxxxxxxxxxx");
}
return "echo " + name;
}
public String blockEcho(String name, BlockException ex) {
return "进行了流量控制";
}
public String fallbackEcho(String name) {
return "发生了内部异常";
}
全局配置(注意函数必须是 static 函数)
@GetMapping("/frontend")
@SentinelResource(value = "/frontend", blockHandler = "blockFrontend", blockHandlerClass = {BlockHandler.class})
public String frontend() {
return testService.test();
}
public static class BlockHandler {
public static String blockFrontend(BlockException ex) {
return "进行了流量控制";
}
}
配置持久化
使用 Nacos 持久化
推模式:使用 Nacos 配置规则
Nacos 是阿里中间件团队开源的服务发现和动态配置中心。Sentinel 针对 Nacos 作了适配,底层可以采用 Nacos 作为规则配置数据源。使用时只需添加以下依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
NacosWritableDataSource 的实现
public class NacosWritableDataSource<T> implements WritableDataSource<T> { private String serverAddr, groupId, dataId; public NacosWritableDataSource(String serverAddr, String groupId, String dataId) { this.serverAddr = serverAddr; this.groupId = groupId; this.dataId = dataId; } @Override public void write(T t) throws Exception { String jsonConfigInfo = encodeJson(t); ConfigService configService = NacosFactory.createConfigService(serverAddr); boolean isPublishOk = configService.publishConfig(dataId, groupId, jsonConfigInfo); System.out.println("write to nacos is " + isPublishOk); } private String encodeJson(T t) { return JSON.toJSONString(t); } @Override public void close() throws Exception { } }实现:当系统启动时,会调用 init 方法实现配置的读取,然后将
NacosWritableDataSource实例注册到 Sentinel 的监控系统中,当配置发生变化,会调用NacosWritableDataSource的write方法@Component public class DataSourceInitFunc { @Value("${spring.cloud.nacos.config.server-addr}") private String remoteAddress; @Value("${spring.cloud.nacos.config.group}") private String groupId; @Value("${spring.application.name}") private String dataId; @PostConstruct public void init() { ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(remoteAddress, groupId, dataId, source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})); FlowRuleManager.register2Property(flowRuleDataSource.getProperty()); WritableDataSource<List<FlowRule>> wds = new NacosWritableDataSource<>(remoteAddress, groupId, dataId); WritableDataSourceRegistry.registerFlowDataSource(wds); } }
使用 Redis 持久化
推模式:使用 Redis 配置规则
Sentinel 针对 Redis 作了相应适配,底层可以采用 Redis 作为规则配置数据源。使用时只需添加以下依赖:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-redis</artifactId>
</dependency>
Redis 动态配置源采用 Redis PUB-SUB 机制实现
整合 Feign
application.yml
feign:
sentinel:
enabled: true
关于降级
如果 sentinel 和 feign 都做了降级处理,默认会先走 sentinel 的降级逻辑,因为先走了 sentinel 的降级,请求变为正常,所以走不到 feign 的降级逻辑

