Sentinel 实现服务降级、熔断与限流(1.8.+ 版)
Sentinel 概念
1、Sentinel
是什么?
Sentinel: 分布式系统的流量防卫兵
。随着微服务的流行,服务与服务之间的稳定性变得越来越重要,Sentinel 以流量为切入点,从流量控制
、熔断降级
、系统负载保护
等多个维度保护服务的稳定性。
概念:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
配置:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
2、解决的问题:
(1)服务雪崩
(2)服务降级
(3)服务熔断
(4)服务限流
安装 Sentinel 控制台
一、Sentinel 的组件分成两部分【后台、前台(8080)】
1、核心库(Java 客户端)
:不依赖与任何框架/库,能够运行于所以的 Java 8
运行时环境,同时对 Dubbo、Spring Cloud 等框架也有较好的支持。
2、控制台(Dashboard)
:基于 Spring Boot 开发,打包后就可以直接运行,不需要额外的 Tomcat 等应用容器。
二、安装步骤
1、下载:https://github.com/alibaba/Sentinel/releases/download/1.8.2/sentinel-dashboard-1.8.2.jar
2、前提准备好 Java 8 运行环境,命令如下:
java -jar sentinel-dashboard-1.8.2.jar
3、访问 Sentinel 的管理界面:http://localhost:8080,密码账号都是:sentinel
初始化工程
一、启动 nacos8848
成功,访问:http://localhost:8848/nacos
二、创建 cloud-alibaba-sentinel-service8401
模块
1、引入 pom 依赖
<!--持久化支持依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<!--Alibaba Sentinel依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- Alibaba Nacos discovery依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2、写 yml 配置文件
server:
port: 8401
spring:
application:
name: cloud-alibaba-sentinel-service
cloud:
nacos:
# 服务注册
discovery:
# server-addr: localhost:8848 # 服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
# 服务监控端口
dashboard: localhost:8080
# 默认 8719,假如被占用了会自动从 8719 开始依次 +1 扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: "*"
3、启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelServiceMain8401 {
public static void main(String[] args) {
SpringApplication.run(SentinelServiceMain8401.class, args);
}
}
4、controller
@RestController
@Slf4j
public class FlowLimitController {
@GetMapping(value = "/testA")
public String testA(){
return "--------testA";
}
@GetMapping(value = "/testB")
public String testB(){
return "--------testB";
}
}
5、测试,启动 nacos 、sentinel、cloud-alibaba-sentinel-service8401服务后,打开sentinel后刷新没有任何变化,只有当被监控的服务发起请求调用后就会被监控,便能够被 sentinel 监控到,sentinel 是懒加载机制。
流控规则
基本介绍
名词解释及说明:
1、资源名:唯一名称,默认请求路径。
2、针对来源:Sentinel 可以针对调用这进行限流,填写微服务名,默认 default(不区分来源)。
3、阈值类型/单击阈值:
(1)QPS(每秒钟的请求数量):当调用该 API 的 QPS 达到阈值的时候,进行限流。
(2)线程数:当调用该 API 的线程数达到阈值的时候,进行限流。
4、是否集群:不需要集群(指 Sentinel)。
5、流控模式:
(1)直接:API 达到限流条件时,直接限流。
(2)关联:当关联的资源达到阈值时,就限流自己。
(3)链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【 API 级别的针对来源】。
6、流控效果:
(1)快速失败:直接失败,抛异常。
(2)Warn Up:根据 coldFactor (冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的 QPS 阈值。
(3)排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为 QPS,否则无效。
流控模式
1、直接(默认)模式
(1)直接
==> 快速失败(系统默认)
(2)配置及说明
(2.1)阈值类型:QPS
结论:表示 1秒钟 向/testA API 发送 1次请求
就是 OK,若超过设定次数 1 ,就直接-快速失败,报默认错误。报错:Blocked by Sentinel (flow limiting)
。
(2.2)阈值类型:并发线程数
表示 1 秒内访问该 API 接口的线程数,当排队的线程数达到设定的阈值的时候,则进行限流操作,通常出现在接口访问响应慢的时候。如果操作很快,也不会出现限流。
问题: 不难看出来,直接调用默认报错信息,但是通常这种情况并不适用于实际的业务开发,是否有一个我们后续处理的办法,类似有一个 hystrix 的 fallback
的兜底方法?见 @SentinelResource 注解
2、关联模式
(1)关联模式
:当关联的资源达到阈值时,就限流自己,当与 A 关联的资源 B 大道与之后,就限流 A(通俗理解:B 惹事 ,A 坐牢) 。
(2)配置及说明:当关联资源 /testB
的 QPS 阈值超过 1 时,就限流 /testA
的REST访问地址,当关联资源达到阈值后闲置配置好的资源名。
(3)测试:密集请求 /testB
,然后访问 /testA
,结果,/testA 出现了流控报错:Blocked by Sentinel (flow limiting)
,应用场景:下单接口(/testA)、支付支付(/testB)
。
3、链路模式
(1)链路模式:访问 /testA
资源名时,对入口资源设定限流阈值,当入口资源达到限流阈值时,/testA 出现流控报错。
(2)解决 Sentinel 流控规则-链路模式 失效(坑),原因(查看官网说明),配置如下:
(2.1)新增 pom 依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.2</version>
</dependency>
(2.2)修改 yml 配置
# spring.cloud.sentinel.filter.enabled=false
spring:
cloud:
sentinel:
# 配置文件中关闭sentinel官方的CommonFilter实例化
filter:
enabled: false
(2.3)添加配置类,自定义构建CommonFilter实例
@Configuration
public class FilterContextConfig {
/**
* @NOTE 在spring-cloud-alibaba v2.1.1.RELEASE及前,sentinel1.7.0及后,关闭URL PATH聚合需要通过该方式,spring-cloud-alibaba v2.1.1.RELEASE后,可以通过配置关闭:spring.cloud.sentinel.web-context-unify=false
* 手动注入Sentinel的过滤器,关闭Sentinel注入CommonFilter实例,修改配置文件中的 spring.cloud.sentinel.filter.enabled=false
* 入口资源聚合问题:https://github.com/alibaba/Sentinel/issues/1024 或 https://github.com/alibaba/Sentinel/issues/1213
* 入口资源聚合问题解决:https://github.com/alibaba/Sentinel/pull/1111
*/
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
// 入口资源关闭聚合
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
}
(2.4)测试
测试结果:刷新/testA
达到设置的阈值时,出现报错。而刷新/testB
是达到阈值并没有报错,是因为没有配置资源名为 message, 入口资源 为 /testB的流控规则。
流控效果
1、快速失败
默认的流控处理。直接失败,抛出异常
2、Warm up(预热)
(1)公式:阈值除以codeFactor(默认值为3)
,经过预热时长后达到阈值。
(2)默认 coldFactor
为 3,即请求 QPS 从 threshold / 3
开始,经预热时长逐渐升至设定的 QPS 阈值。官网说明。
(3)Warm up 配置
例:阈值设置为 10 ,预热时长设置为 5 秒。系统初始化的阈值为 10/3,经过经过了 5 秒后阈值慢慢升高至 10。
测试结果:疯狂刷新/testA
,刚开始,QPS超过3时,直接失败,后续访问直到 QPS 慢慢达到10 的时候才失败。
(4)应用场景:
如:秒杀系统在开启的瞬间,会有很多流量上来,可能导致系统崩溃,预热的方式就是为了保护系统,可以慢慢的把请求的流量放进来,慢慢的把初始化阈值 QPS/3
增长到指定设置的阈值
。
3、排队等待
(1)匀速排队,让请求一均匀的速度通过,阈值类型必须设置为 QPS,否则无效。
(2)设置含义:/testA
接口每秒 1 次
请求,超过的话就排队等待,等待超时时间为 20000 毫秒
,超过 20000 毫秒 没有响应就报错。
熔断降级规则
一、基本介绍(1.8.2):官网:https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
二、熔断降级规则说明
熔断降级规则(DegradeRule)包含下面几个重要的属性:
三、降级策略
1、慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
2、异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。
经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
3、异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断
。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
自定义熔断降级、限流方法友好提示参数配置及其注意事项:https://blog.csdn.net/qq_36763419/article/details/121508632
配置原理可参考 Hystrix 的熔断降级配置(配置原理相同):https://blog.csdn.net/qq_36763419/article/details/120119872
热点 key 规则
1、第一部分(基本配置): 热点 key 规则目前仅支持 QPS 限流模式,当访问指定资源名
的时,携带有指定参数索引
(指资源方法的第几个参数,从 0 开始计数),并且在指定时间窗内 QPS 达到阈值
时进行限流。自定义限流兜底方法如下:
@RestController
@Slf4j
public class HotKeyRuleController {
/*热点key规则限流*/
//对 p1 参数进行热点限流
@GetMapping(value = "/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "------testHotKey";
}
public String deal_testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2,BlockException e) {
return "------deal_testHotKey";
}
}
2、第二部分参数例外项: 表示在指定参数索引
,正常情况下(符合第一部分描述)参数值等于非指定参数值时,指定时间窗内 QPS 达到阈值则限流。特殊情况下,指定参数值等于 x ,限流阈值是 y ,也就是说参数值是 x 时候,指定时间窗内 QPS 达到指定阈值 y ,才进行限流。值得注意的是,参数必须是基本类型或者String。
系统规则
名词解释及说明:
系统规则(限流总控)是从应用级别的入口流量进行控制,从单台机器的 load
、CPU使用率
、平均 RT
、入口 QPS
和并发线程数
等几个维度监控应用指标,让系统尽可能泡在最大吞吐量的同时保证系统整体稳定性。系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。系统规则支持以下几种模式:
1、Load 自适应(仅对 Linux/Unix-like 机器生效)
:系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量才会触发系统保护(BBR 阶段)。系统容量有系统的 maxQps * minRt
估算得出。设定参考值一般是 CPU cores (CPU核数) * 2.5
。
2、平均 RT
:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
3、并发线程数:
当单台机器上所有入口流量的并发线程数达到阈值基础法系统保护。
4、入口 QPS:
当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
5、CPU usage(1.5.+ 版)
:当系统的 CPU 使用率超过阈值即触发系统保护(取值范围:0.0-1.0),比较灵敏。
服务调用熔断
Sentinel 整合 OpenFeign(参考):https://blog.csdn.net/qq_36763419/article/details/120119872
yml配置如下:
# 开启基于 sentinel 的 OpenFeign 调用熔断降级支持
feign:
sentinel:
enabled: true
Sentinel 规则持久化
Sentinel(1.8.0+版本) 整合 Nacos 实现持久化配置详解:https://blog.csdn.net/qq_36763419/article/details/121560105