1. 是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 的主要特性:
Sentinel 的开源生态:
Sentinel 分为两个部分:
- 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。
2. 安装、运行
<!-- alibaba Sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${spring-cloud-alibaba.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.0</version>
</dependency>
<!-- alibaba Sentinel 整合 Nacos 实现持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
<!-- 当 Sentinel 整合的微服务类型是 gateway -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.8.0</version>
</dependency>
3. 流控规则
3.1 简单说明
- 资源名:唯一名称,默认请求路径;
- 针对来源:Sentinel 可以针对调用者进行限流,填写微服务名,默认 default(不区分来源);
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量)︰当调用该 API 的 QPS 达到阈值的时候,进行限流;
- 线程数:当调用该 API 的线程数达到阈值的时候,进行限流。
- 是否集群:不需要集群。
- 流控模式:
- 直接:API 达到限流条件时,直接限流;
- 关联:当关联的资源达到阈值时,就限流自己;
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)// API 级别的针对来源。
- 流控效果:
- 快速失败:直接失败,抛异常;
- Warm up:根据 Code Factor(冷加载因子,默认 3)的值,从阈值/codeFactor,经过预热时长,才达到设置的 QPS 阈值;
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为 QPS,否则无效。
3.2 流控模式
a. 直接
直接调用默认报错信息,技术方面 OK,但是否应该有我们自己的后续处理?例如类似有一个 fallback 的兜底方法?
b. 关联
当关联的资源达到阈值时,就限流自己(e.g. 支付接口达到阈值后限流下订单的接口)。
【效果】当关联资源 /testB
的 QPS 阈值超过 1 时,就限流 /testA
的访问地址。
在 PostMan 跑的期间去访问 /testA,不出意外 Blocked by Sentinel (flow limiting):
c. 链路
// TODO
3.3 流控效果
a. 快速失败
界面显示:Blocked by Sentinel (flow limiting)
源码参见:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
b. Warm Up
默认 coldFactor 为 3,即请求 QPS 从 threshold/coldFactor 开始,经预热时长逐渐升至设定的 QPS 阈值。
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统搞崩,WarmUp 就是为了保护系统,慢慢的把流量放进来,慢慢的把阈值增长到最初设定的阈值。
c. 排队等待
匀速排队,让请求以均匀的速度通过,阈值类型必须是 QPS,否则无效。
![](_v_images/20220216191902826_6474.png =500x)
4. 降级规则
4.1 说明
除了流量控制之外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积。Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或者异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
4.2 策略
- 慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
- 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
- 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
【注】异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex)
记录业务异常。@SentinelResource
注解会自动统计业务异常,无需手动调用。
5. 热点规则
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制;
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制。
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
在 Controller#xxxHandle 方法上加了 @SentinelResource("testHotKey")
注解的资源做限制:当 QPS 超过 1次/s,立刻被限流。如若处理方法的第 1 个参数的值为 1101 则做限流 200次/s 的控制。
也即 param1 不是 "1101" 时,阈值是 1;但若值为 "1101",则阈值 200。
6. 系统规则
7. @SentinelResource
该注解处理的是 Sentinel 控制台配置的违规情况
- value
- 资源名称;
- 必需项,因为需要通过 resource name 找到对应的规则,这个是必须配置的。
- entryType
- entry 类型;
- 可选项,有 IN 和 OUT 两个选项,默认为 EntryType.OUT。
- blockHandler
- blockHandler 对应处理 BlockException 的函数名称,可选项;
- blockHandler 函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
- blockHandlerClass
- blockHandler 函数默认需要和原方法在同一个类中;
- 如果希望使用其他类的函数,则需要指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
- fallback
- fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑;
- fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
- fallbackClass
- fallbackClass 的应用和 blockHandlerClass 类似,fallback 函数默认需要和原方法在同一个类中;
- 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
- defaultFallback(since 1.6.0)
- 如果没有配置 defaultFallback 方法,默认都会走到这里来;
- 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理;
- 若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。
- exceptionsToIgnore(since 1.6.0)
- 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
8. 服务熔断
8.1 &Ribbon
@Bean
@LoadBalance
public RestTemplate restTemplate() {
return new RestTemplate();
}
8.2 &OpenFeign
# 对Feign的支持
feign:
sentinel:
enabled: true
9. 规则持久化
一旦我们重启应用,Sentinel 规则将消失,生产环境需要将配置规则进行持久化。
将限流配置规则持久化进 Nacos 保存,只要刷新 8401 某个 rest 地址,Sentinel 控制台的流控规则就能看到,只要 Nacos 里面的配置不删除,针对 8401 上 Sentinel 上的流控规则持续有效。
【避坑】升级 JDK 版本为 1.8.0_152 以上。
服务配置
spring:
application:
name: alibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 # 默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: alibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
Nacos 配置
[Data ID] alibaba-sentinel-service
[Group] DEFAULT_GROUP
---------------------------------------------------------------------------------
[
{
"resource": "/testC", # 资源名称
"limitApp": "default", # 来源类型
"grade": 1, # 阈值类型 (0:线程数;1:QPS)
"count": 1, # 单机阈值
"strategy": 0, # 流控模式 (0:直接;1:关联;2:链路)
"controlBehavior": 0, # 流控效果 (0:快速失败;1:WarmUp;2:排队等待)
"clusterMode": false # 是否集群
}
]