Sentinel 流量控制

2023-04-20,

一、Sentinel 介绍


Sentinel 是阿里巴巴出品的面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流,流量整形、熔断降级、系统负载保护等多个维度来保障微服务的稳定性。主页地址

  Sentinel Hystrix resilience4j
隔离策略 信号量隔离(并发线程隔离)链接 线程池隔离/信号量隔离 信号量隔离
熔断降级策略 基于响应时间、异常比率、异常数 基于异常比率 基于异常比率、响应时间
实时统计实现 滑动窗口 滑动窗口 Ring Bit Buffer
动态规则配置 支持多种数据源 支持多种数据源 有限支持
扩展性 多个扩展点 插件的形式 接口的形式
基于注解的支持 支持 支持 支持
限流 基于 QPS,支持基于调用关系的限流,线程数限流等 有限的支持 Rate Limiter
流量整形 基于预热模式、匀速器模式、预热排队模式 不支持 简单的 Rate Limiter模式
系统自适应保护 支持 不支持 不支持
控制台 提供开箱即用的控制台,可配置规则,查看秒级监控,机器发现等 简单的监控查看 不提供控制台,可对接其它监控系统。

1、Sentinel 组成


Sentinel 的使用主要分为两个部分:
【1】核心库:主要指 Java客户端,不依赖任何框架/库,能够运行在 Java7及以上版本的运行时环境,同时对 Dubbo/SpringCloud 等框架也有较好的支持。
【2】控制台:控制台主要负责管理推送规则、监控、集群限流分配管理、机器发现等。

2、Sentinel 的特性


【1】丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
【2】完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
【3】广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
【4】完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

3、Sentinel 的相关概念


【1】资源:资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来表示资源。
【2】规则:围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。

二、Sentinel 流控降级入门


Sentinel 本地应用流控降级实现分为三步:
【创建本地应用】【1】pom.xml 中引入 sentinel-core 依赖

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel-core</artifactId>
4 <version>1.7.2</version>
5 </dependency>

【2】创建 Sentinel 限流规则方案一 [建议使用](在 Sentinel控制台设置流控规则)

创建 Sentinel 限流规则方案二 [不建议使用](在应用中使用代码编写流控规则)

 1 package com.zzx.sentinelquickstart.controller;
2
3 import com.alibaba.csp.sentinel.Entry;
4 import com.alibaba.csp.sentinel.SphU;
5 import com.alibaba.csp.sentinel.slots.block.RuleConstant;
6 import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
7 import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
8 import org.springframework.web.bind.annotation.GetMapping;
9 import org.springframework.web.bind.annotation.RestController;
10
11 import javax.annotation.PostConstruct;
12 import java.util.ArrayList;
13 import java.util.List;
14
15 /**
16 * @description::sentinel 测试类
17 * @author: zzx
18 * @createDate: 2020/9/26
19 * @version: 1.0
20 */
21 @RestController
22 public class TestController {
23
24 @GetMapping("/hello")
25 public String hello(){
26 //使用限流规则
27 try(Entry entry = SphU.entry("Hello")) {//限流入口
28 //被保护的规则
29 return "hello Sentinel";
30 }catch (Exception e){
31 e.printStackTrace();
32 return "系统繁忙,请稍等";
33 }
34 }
35
36 /**
37 * @Description 定义限流规则
38 * @Author zhengzhaoxiang
39 * @Date 2020/9/26 8:58
40 * @Param
41 * @Return
42 */
43 @PostConstruct //当前类的构造函数执行之后执行
44 public void initFlowRules(){
45 //1、创建存放限流规则的集合,存放 FlowRule
46 List<FlowRule> flowRules = new ArrayList<>();
47 //2、创建限流规则
48 FlowRule flowRule = new FlowRule();
49 flowRule.setResource("Hello");//定义资源,表示 sentinel 会对哪个资源生效
50 flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);//定义限流规则的类型 = QPS
51 flowRule.setCount(2);// 定义 QPS 秒能通过的请求个数
52 //3、将限流规则放到集合中
53 flowRules.add(flowRule);
54 //4、加载限流规则
55 FlowRuleManager.loadRules(flowRules);
56 }
57 }

【3】测试:当 1秒内点击两次以内,正常返回,超过2次,则返回 “系统繁忙,请稍等“

搭建本地 Sentinel 控制台:Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、实时监控(单机和集群),规则管理和推送的功能。本地控制台搭建步骤:
【1】下载 Sentinel 控制台 jar包:链接
【2】启动 Sentinel 控制台:jdk1.8及以上,使用如下命令启动控制台:9000是端口;

java -Dserver.port=9000 -jar sentinel-dashboard-1.7.2.jar

【3】访问 Sentinel 控制台:通过浏览器打开 http:localhost:9000/ 即可访问 Sentinel控制台,默认用户名和密码都是 sentinel;

本地应用接入本地 Sentinel控制台:本地应用是以客户端的身份来接入控制台,具体步骤如下:
【1】在本地应用的 pom.xml文件中引入依赖:

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel-transport-simple-http</artifactId>
4 <version>1.7.2</version>
5 </dependency>

【2】在本地应用的 JVM中添加如下启动参数:

1 # dashboard 设置 Sentinel控制台的主机地址和端口。 project.name设置本地在 Sentinel 控制台中的名称
2 -Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=SentinelQuickStart

【3】运行测试: 重启本地应用并重新通过浏览器访问本地请求,快速刷新几次,查看控制台中的实时监控情况。

1、Sentinel 定义资源的方式


抛出异常的方式定义资源 [了解]Sentinel中的 SphU包含了 try-catch风格的 API。用这种方式,当资源发生了限流会抛出 BlockException。这个时候可以捕获异常,进行限流之后的逻辑处理。关键代码如下:

1 //使用限流规则
2 try(Entry entry = SphU.entry("Hello")) {//限流入口
3 //被保护的规则
4 return "hello Sentinel";
5 }catch (Exception e){
6 e.printStackTrace();
7 return "系统繁忙,请稍等";
8 }

返回布尔值方式定义资源 [了解]Sentinel中的 SphO 提供 if-else风格的API。用这种方式,当资源发生了限流之后就返回 false,这个时候可以根据返回值,进行限流之后的逻辑处理。
【1】在 Sentinel_quick_start 项目中创建 TestBooleanController使用返回布尔值的方式定义资源。需要注意的是 SphO.entry(x)需要与 SphO.exit()方法成对出现,否则会导致调用链记录异常,抛出 ErrorEntryFreeException 异常。

 1 package com.zzx.sentinelquickstart.controller;
2
3 import com.alibaba.csp.sentinel.SphO;
4 import org.springframework.web.bind.annotation.GetMapping;
5 import org.springframework.web.bind.annotation.RestController;
6
7 /**
8 * @description::sentinel 测试类
9 * @author: zzx
10 * @createDate: 2020/9/26
11 * @version: 1.0
12 */
13 @RestController
14 public class TestBooleanController {
15
16 @GetMapping("/boolean")
17 public Boolean hello(){
18 //使用限流规则
19 if(SphO.entry("Sentinel_Boolean")) {//限流入口
20 try {
21 //被保护的资源
22 System.out.println("被保护的资源");
23 return true;
24 } finally {
25 SphO.exit();
26 }
27 }else{
28 //被限流或降级的处理
29 System.out.println("被限流或降级的处理");
30 return false;
31 }
32 }
33 }

【2】测试:添加限流规则,随后访问请求,当超过 QPS=2的时候,就会返回 flase,正常返回 true。

异步调用支持 [了解]Sentinel 支持异步调用链路的统计。在异步调用中,需要通过 SphU.asyncEntry(x)方法定义资源,并通常需要在异步的回调函数中调用 exit方法。
【1】在本地应用的引导类中添加 @EnableAsync,表示 springboot项目开始异步调用支持;

1 @SpringBootApplication
2 @EnableAsync//开启异步调用的支持
3 public class SentinelQuickStartApplication {
4 public static void main(String[] args) {
5 SpringApplication.run(SentinelQuickStartApplication.class, args);
6 }
7 }

【2】创建 AsyncService 编写异步调用方法;

 1 import org.springframework.scheduling.annotation.Async;
2 import org.springframework.stereotype.Service;
3
4 /**
5 * @description: 异步方法服务类
6 * @author: zzx
7 * @createDate: 2020/9/27
8 * @version: 1.0
9 */
10 @Service
11 public class AsyncService {
12
13 @Async //表示方法是异步调用方法
14 public void hello() throws InterruptedException {
15 System.out.println("异步的开始");
16 Thread.sleep(5000);
17 System.out.println("异步的结束");
18 }
19 }

【3】创建 TestAsyncController,实现异步调用限流控制;

 1 import com.alibaba.csp.sentinel.AsyncEntry;
2 import com.alibaba.csp.sentinel.SphO;
3 import com.alibaba.csp.sentinel.SphU;
4 import com.alibaba.csp.sentinel.slots.block.BlockException;
5 import com.zzx.sentinelquickstart.server.AsyncService;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.web.bind.annotation.GetMapping;
8 import org.springframework.web.bind.annotation.RestController;
9
10 /**
11 * @description::sentinel 测试类
12 * @author: zzx
13 * @createDate: 2020/9/26
14 * @version: 1.0
15 */
16 @RestController
17 public class TestAsyncController {
18
19 @Autowired
20 private AsyncService asyncService;
21
22 @GetMapping("/async")
23 public void hello(){
24 //使用限流规则
25 AsyncEntry asyncEntry = null;
26 try {
27 //被保护的资源
28 asyncEntry = SphU.asyncEntry("Sentinel_AsyncEntry");//限流入口
29 asyncService.hello();//调用异步的方法,被保护的资源
30 } catch (BlockException | InterruptedException e) {
31 System.out.println("限流后逻辑处理");
32 } finally {
33 if(asyncEntry != null){
34 asyncEntry.exit(); //限流的出口
35 }
36 }
37 }
38 }

【4】测试:当设置限流规则后,QPS>2时就会出现异常中捕获的信息,当QPS<=2时,则执行异常方法hello中的内容;

注解方式定义资源 [重点]Sentinel支持通过注解 @SentinelResource 定义资源并配置 blockHandler函数来进行限流之后的处理。
【1】在本地应用的 pom.xml中引入依赖:因为 Sentinel中使用 AspectJ的扩展用于自动定义资源、处理 BlockException等,所以需要在项目引入 sentinel-annotation-aspectj依赖;

1 <dependency>
2 <groupId>com.alibaba.csp</groupId>
3 <artifactId>sentinel-annotation-aspectj</artifactId>
4 <version>1.7.2</version>
5 </dependency>

【2】创建 AspectJ 的配置类;

 1 import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
2 import org.springframework.context.annotation.Bean;
3 import org.springframework.context.annotation.Configuration;
4
5 /**
6 * @description: 配置文件,创建引入jar中的实例
7 * @author: zzx
8 * @createDate: 2020/9/27
9 * @version: 1.0
10 */
11 @Configuration
12 public class SentinelAspectConfiguration {
13
14 @Bean
15 public SentinelResourceAspect sentinelResourceAspect(){
16 return new SentinelResourceAspect();
17 }
18 }

【3】创建 TestAnnController,实现限流控制;@SentinelResource注解用来标识资源是否限流、降级。例子中该注解的属性‘Sentinel_Ann’表示资源名。@SentinelResource 还提供了其他额外的属性如 blockHandler来指定被限流后的操作。

 1 import com.alibaba.csp.sentinel.AsyncEntry;
2 import com.alibaba.csp.sentinel.SphU;
3 import com.alibaba.csp.sentinel.annotation.SentinelResource;
4 import com.alibaba.csp.sentinel.slots.block.BlockException;
5 import com.zzx.sentinelquickstart.server.AsyncService;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.web.bind.annotation.GetMapping;
8 import org.springframework.web.bind.annotation.RestController;
9
10 /**
11 * @description::sentinel 测试类
12 * @author: zzx
13 * @createDate: 2020/9/26
14 * @version: 1.0
15 */
16 @RestController
17 public class TestAnnController {
18
19 @Autowired
20 private AsyncService asyncService;
21
22 //设置资源名称 和 限流降级的处理函数
23 @SentinelResource(value = "Sentinel_Ann", blockHandler = "execeptionHandler")
24 @GetMapping("/ann")
25 public String hello(){
26 //使用限流规则
27 return "Hello Sentinel";
28 }
29
30 public String execeptionHandler(BlockException e){
31 e.printStackTrace();
32 return "系统繁忙,请稍等";
33 }
34 }

【4】运行测试:在 Sentinel控制台中设置关于 “Sentinel_Ann”资源的流控规则后。当访问请求的 QPS超过2时就会调用 blockHandler 定义的方法。

三、Sentinel 高级


1、Sentinel 和 SpringCloud整合


为了减少开发的复杂程度,我们对大部分的主流框架,例如 Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor 等都做了适配。你只需要引入对应的依赖即可方便地整合 Sentinel。如果要实现 SpringCloud和 Sentinel的整合,可以通过引入 Spring Cloud Alibaba Sentinel来方便地整合 Sentinel。Spring Cloud Alibaba 是阿里巴巴提供的,致力于提供微服务开发的一站式解决方案。Spring Cloud Alibaba 默认为 Sentinel整合Servlet、RestTemplate、FeignClient和 Spring WebFlux。Sentinel 在 Spring Cloud生态中,不仅补全了 Hystrix 在 Servlet和 RestTemplate 这一块的空白,而且还完全兼容了 Hystrix在 FeignClient中限流降级和用法,并且支持运行时灵活地配置和调整限流降级规则。

需求:使用 SpringCloud+Sentinel实现访问 http://localhost:8080/ann 路径的流量控制,引用上面的案例。
具体步骤:【1】创建 springboot 项目,在项目中引入 spring-cloud-start-alibaba-sentinel依赖

1 <dependency>
2 <groupId>com.alibaba.cloud</groupId>
3 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
4 <version>2.1.0.RELEASE</version>
5 </dependency>

【2】在 application.properties中配置本地项目接入本地控制台。

1 # 设置应用名称
2 spring.application.name=SpringCloudSentinel
3 # 设置 Sentinel连接控制台的主机地址和端口
4 spring.cloud.sentinel.transport.dashboard=localhost:9000

2、Sentinel 对 Feign的支持


Sentinel 适配了 Feign组件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel的依赖外,还需要如下配置:
【1】配置文件打开 Sentinel对 Feign的支持:feign.sentinel.enabled=true;

1 # 设置 Sentinel连接控制台的主机地址和端口
2 spring.cloud.sentinel.transport.dashboard=localhost:9000
3 #开启 sentinel 对 Feign的支持
4 feign.sentinel.enabled=true

【2】在 Sentinel控制台中增加关于资源的流控规则,Sentinel和 Feign整合时,流控规则编写形式为:http请求方式:协议://服务名/请求路径跟参数,例如:GET:http://sentinel-feign-provider/hello

3、Sentinel 对 Spring Cloud Gateway的支持


从 1.6.0版本开始,Sentinel 提供了 SpringCloud Gateway的适配模块,可以提供两种资源维度的限流:
【1】route 维度:即在 Spring配置文件中配置的路由条目,资源名对应的 routeId;
【2】自定义 API维度:用户可以利用 Sentinel 提供的API 来自定义一些 API分组;

整合 sentinel:网关微服务配置好之后,就可以开始整合 Spring Cloud GateWay 和 Sentinel 了。
【1】在 sentinel_gateway的 pom.xml中引入依赖:

 1 <dependency>
2 <groupId>com.alibaba.cloud</groupId>
3 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
4 <version>2.1.0.RELEASE</version>
5 </dependency>
6 <dependency>
7 <groupId>com.alibaba.cloud</groupId>
8 <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
9 <version>2.1.0.RELEASE</version>
10 </dependency>

【2】创建 GatewayConfiguration配置类,配置流控降级回调操作。

 1 @Component
2 public class GatewayConfiguration {
3 @PostConstruct
4 public void doInit(){
5 //限流回调函数
6 GatewayCallbackManager.setBlockHandler(new BlockRequestHandler(){
7 //当请求被限流时调用的方法
8 @Override
9 public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
10 return ServerResponse.status(200).syncBody("系统繁忙,请稍等");
11 }
12 });
13 }
14 }

【3】在 application.yml中配置 Sentinel控制台的访问地址,同上;
【4】运行测试:启动项目,在 Sentinel控制台中增加关于资源的流控规则,Sentinel在适配 Spring Cloud Gateway时提供了两种配置资料的规则:
 route 维度规则定义:在 sentinel控制台中增加流控规则,API类型选择 “Route ID”,API名称为网关配置的路由Id,QPS阈值设置为2
自定义 API维度:先配置 API管理,匹配串设置为路由规则中匹配的 “断言”信息。
然后点击流控规则,新增网关流控规则。选择 API分组:

四、Sentinel 规则


Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel也提供相关 API,供开发者定制自己的规则策略。Sentinel 主要支持以下几种规则:

1、流量控制规则


流量控制(flow control),其原理是监控应用流量的 QPS或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

流量控制主要有两种方式:
【1】并发线程数:并发线程数限流用于保护业务线程数不被耗尽;
【2】QPS:当 QPS超过某个阈值的时候,则采取措施进行流量控制;

一条限流规则主要由以下几个因素组成,我们可以组合元素来实现不同的限流效果:
 ① resource:资源名,即限流规则的作用对象;
 ② count:限流阈值;
 ③ grade:限流阈值类型(QPS或并发线程数);
 ④ limitApp:流控针对的调用来源,若为 default 则不区分调用来源;
 ⑤ strategy:调用关系限流策略;
 ⑥ controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
    ● 直接拒绝(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是默认的流量控制方式,当 QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
    ● Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过 “冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热时间,避免冷系统被压垮。
    ●排队等待(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,让请求以匀速的速度通过,对应的是漏桶算法。

同一个资源可以同时有多个限流规则,检查规则时会依次检查。

2、熔断降级规则


熔断降级会在链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认的行为是抛出 DegradeException)
重要的属性:

Field 说明 默认值
resource 资源名,即限流规则的作用对象  
count 阈值  
grade 熔断策略,支持秒级RT/秒级异常比例/分钟级异常数 秒级平均RT
rtSlowRequestAmount RT模式下1s内连续多个请求的平均 RT超出阈值方可触发熔断 5
timeWindow 降级的时间,单位为 s  
minRequestAmount 异常熔断的触发最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断 5

同一个资源可以同时有多个降级规则。熔断策略详解:
【1】平均响应时间(DEGRADE_GRADE_RT)当1s内持续进入 N个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以ms为单位),那么在接下的时间(DegradeRule中的 timeWindow,以 s为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。
【2】异常比例(DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量>=N(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,在接下来的时间(DegradeRule中的timeWindow,以 s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围0-1。
【3】异常数(DEGRADE_GRADE_EXCEPTION_COUNT):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间是分钟级别的,若 timeWindow小于 60s,则结束熔断状态后仍可能再进入熔断状态。

【通过代码定义熔断规则】:每次熔断时间为设置的TimeWindow的时长。

 1 package com.zzx.sentinelquickstart.controller;
2
3 import com.alibaba.csp.sentinel.annotation.SentinelResource;
4 import com.alibaba.csp.sentinel.slots.block.BlockException;
5 import com.alibaba.csp.sentinel.slots.block.RuleConstant;
6 import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
7 import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
8 import com.zzx.sentinelquickstart.server.AsyncService;
9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.web.bind.annotation.GetMapping;
11 import org.springframework.web.bind.annotation.RestController;
12 import javax.annotation.PostConstruct;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 /**
17 * @description::sentinel 测试类
18 * @author: zzx
19 * @createDate: 2020/9/26
20 * @version: 1.0
21 */
22 @RestController
23 public class TestAnnController {
24
25 @Autowired
26 private AsyncService asyncService;
27
28 //设置资源名称 和 限流降级的处理函数
29 @SentinelResource(value = "Sentinel_Rule", blockHandler = "execeptionHandler")
30 @GetMapping("/ann")
31 public String hello(){
32 //使用限流规则
33 return "Hello Sentinel";
34 }
35
36 /**
37 * @Description 定义熔断降级规则
38 * @Author zhengzhaoxiang
39 * @Date 2020/10/1 8:16
40 * @Param []
41 * @Return void
42 */
43 @PostConstruct
44 public void initDegradeRule(){
45 //1、创建存放规则的集合
46 List<DegradeRule> rules = new ArrayList<>();
47 //2、创建熔断降级规则
48 DegradeRule degradeRule = new DegradeRule();
49 //定义资源名称
50 degradeRule.setResource("Sentinel_Rule");
51 //定义规则类型:平局响应时间类型
52 degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
53 //定义阈值
54 degradeRule.setCount(0.01);
55 //降级时间
56 degradeRule.setTimeWindow(10);
57 //3、讲规则保存到集合中
58 rules.add(degradeRule);
59 //4、加载规则
60 DegradeRuleManager.loadRules(rules);
61 }
62
63 //被限流或降级的处理函数
64 public String execeptionHandler(BlockException e){
65 e.printStackTrace();
66 return "系统繁忙,请稍等";
67 }
68 }

【在 Sentinel控制台动态设置】:

3、系统保护规则


Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU使用率、总体平均RT、入口 QPS和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能保持最大吞吐量的同时保证系统整体的稳定性。系统保护规则是整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web服务或 Dubbo服务端接收的请求,都属于入口流量。

系统规则支持以下模式:
【1】CPU使用率:当系统 CPU使用率超过阈值即触发系统保护,阈值设置范围为0~1,表示0%~100%。
【2】Load(仅对 Linux/Unix-like机器生效):当系统的 Load1超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的maxQps * minRt计算得出。
【3】并发线程数:当单节点上所有入口流量的并发线程数达到阈值即触发系统保护。
【4】入口平均RT:当单节点上所有入口流量的平均响应时间达到阈值即触发系统保护。单位是毫秒。
【5】入口总QPS:当单节点上所有入口流量的 QPS达到阈值即触发系统保护。

重要的属性:

Field 说明 默认值
highestSystemLoad load1 触发值,用于触发自适应控制阶段 -1不生效
avgRt 所有入口流量的平均响应时间 -1不生效
maxThread 入口流量的最大并发数 -1不生效
qps 所有入口资源的 QPS -1不生效
highestCpuUsage 当前系统的 CPU使用率 -1不生效

注意系统规则只针对入口资源(EntryType=IN)生效。

实现方案两种如下:【1】 本地代码设置

 1 package com.zzx.sentinelquickstart.controller;
2
3 import com.alibaba.csp.sentinel.EntryType;
4 import com.alibaba.csp.sentinel.annotation.SentinelResource;
5 import com.alibaba.csp.sentinel.slots.system.SystemRule;
6 import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
7 import org.springframework.web.bind.annotation.GetMapping;
8 import org.springframework.web.bind.annotation.RestController;
9 import javax.annotation.PostConstruct;
10 import java.util.ArrayList;
11 import java.util.List;
12
13 /**
14 * @description::sentinel 测试类
15 * @author: zzx
16 * @createDate: 2020/9/26
17 * @version: 1.0
18 */
19 @RestController
20 public class SysController {
21
22 //定义资源 设置为入口资源
23 @SentinelResource(entryType = EntryType.IN)
24 @GetMapping("/ann")
25 public String hello(){
26 //使用限流规则
27 return "Hello Sentinel";
28 }
29
30 /**
31 * @Description 定义系统自适应保护规则
32 * @Author zhengzhaoxiang
33 * @Date 2020/10/1 8:16
34 * @Param []
35 * @Return void
36 */
37 @PostConstruct
38 public void initDegradeRule(){
39 //1、创建存放规则的集合
40 List<SystemRule> rules = new ArrayList<>();
41 //2、创建系统自适应保护规则
42 SystemRule degradeRule = new SystemRule();
43 //定义资入口资源的 QPS,参数表示允许的最大请求数(最大)
44 degradeRule.setQps(2);
45 //3、讲规则保存到集合中
46 rules.add(degradeRule);
47 //4、加载规则
48 SystemRuleManager.loadRules(rules);
49 }
50 }

【2】Sentinel 控制台动态设置

4、来源访问控制规则(IP黑白名单)


很多时候,我们需要根据调用来源判断该次请求是否运行放行,这时候可以使用 Sentinel的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)判断资源访问是否通过,其余的请求通过。

重要属性:来源访问控制规则(AuthorityRule)非常简单,主要有以下配置:
【1】resource:资源名,即限流规则的作用对象;
【2】limitApp:请求来源,对应的黑名单/白名单,多个用逗号分隔;
【3】strategy:限制模式,AUTHORITY_WHITE为白名单模式,AUTHORITY_BLACK为黑名单模式,默认为白名单模式;

实现方案两种如下:【1】本地代码设置,设置黑白名单规则

 1 package com.zzx.sentinelquickstart.controller;
2
3 import com.alibaba.csp.sentinel.annotation.SentinelResource;
4 import com.alibaba.csp.sentinel.slots.block.BlockException;
5 import com.alibaba.csp.sentinel.slots.block.RuleConstant;
6 import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
7 import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
8 import com.zzx.sentinelquickstart.server.AsyncService;
9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.web.bind.annotation.GetMapping;
11 import org.springframework.web.bind.annotation.RestController;
12 import javax.annotation.PostConstruct;
13 import java.util.ArrayList;
14 import java.util.List;
15
16 /**
17 * @description::sentinel 测试类
18 * @author: zzx
19 * @createDate: 2020/9/26
20 * @version: 1.0
21 */
22 @RestController
23 public class WhiteBlackController {
24
25 @Autowired
26 private AsyncService asyncService;
27
28 //设置资源名称 和 限流降级的处理函数
29 @SentinelResource(value = "Sentinel_Rule", blockHandler = "execeptionHandler")
30 @GetMapping("/origin")
31 public String hello(){
32 //使用限流规则
33 return "Hello Sentinel";
34 }
35
36 /**
37 * @Description 定义白名单授权定义规则
38 * @Author zhengzhaoxiang
39 * @Date 2020/10/1 8:16
40 * @Param []
41 * @Return void
42 */
43 @PostConstruct
44 public void initWhiteRule(){
45 //1、创建存放规则的集合
46 List<AuthorityRule> rules = new ArrayList<>();
47 //2、创建授权控制规则
48 AuthorityRule rule = new AuthorityRule();
49 //定义资源名称
50 rule.setResource("Sentinel_Rule");
51 //定义限制模式 白名单
52 rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
53 //请求来源
54 rule.setLimitApp("192.168.52.1");
55 //3、讲规则保存到集合中
56 rules.add(rule);
57 //4、加载规则
58 AuthorityRuleManager.loadRules(rules);
59 }
60
61 /**
62 * @Description 定义黑名单授权定义规则
63 * @Author zhengzhaoxiang
64 * @Date 2020/10/1 8:16
65 * @Param []
66 * @Return void
67 */
68 @PostConstruct
69 public void initBlackRule(){
70 //1、创建存放规则的集合
71 List<AuthorityRule> rules = new ArrayList<>();
72 //2、创建授权控制规则
73 AuthorityRule rule = new AuthorityRule();
74 //定义资源名称
75 rule.setResource("Sentinel_Rule");
76 //定义限制模式 白名单
77 rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
78 //请求来源
79 rule.setLimitApp("127.0.0.1");
80 //3、讲规则保存到集合中
81 rules.add(rule);
82 //4、加载规则
83 AuthorityRuleManager.loadRules(rules);
84 }
85 //被限流或降级的处理函数
86 public String execeptionHandler(BlockException e){
87 e.printStackTrace();
88 return "系统繁忙,请稍等";
89 }
90 }

设置获取 IP地址的配置类

 1 package com.zzx.sentinelquickstart.config;
2
3 import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
4 import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
5 import org.springframework.stereotype.Component;
6 import javax.annotation.PostConstruct;
7 import javax.servlet.http.HttpServletRequest;
8
9 /**
10 * @description: 获取请求来源的 API
11 * @author: zzx
12 * @createDate: 2020/9/29
13 * @version: 1.0
14 */
15 @Component
16 public class SentinelConfiguration {
17 @PostConstruct
18 public void doInit(){
19 //获取请求来源的 IP地址
20 WebCallbackManager.setRequestOriginParser(new RequestOriginParser() {
21 @Override
22 public String parseOrigin(HttpServletRequest httpServletRequest) {
23 return httpServletRequest.getRemoteAddr();
24 }
25 });
26 }
27 }

【2】Sentinel控制台动态设置

5、动态规则扩展


前面不管是通过 Java代码还是通过 Sentinel控制台的方式去设置限流规则,都属于手动方式,不够灵活。这种方式一般仅用于测试和演示,生产环境一般通过动态规则的方式来动态管理限流规则。也就是说,很多时候限流规则会被存储在文件、数据库或者配置中心中。Sentinel的 DataSorce 接口给我们提供了对接任意配置源的能力。官方推荐通过控制台设置规则后将规则推送到统一的规则管理中心,客户端实现 ReadableDataSource接口端监听规则中心实时获取变更,流程如下:
常见的实现方式有:
【1】拉取式:
客户端主动向某个规则管理中心定期轮询拉取规则,这个规则管理中心可以是文件,甚至是 VCS等。这样做的方式是简单,缺点是无法及时获取变更;实现拉模式的数据源最简单的方式是继承 AutoRefreshDataSource抽象类,然后实现 readSource() 方法,在该方法里从指定数据源读取字符串格式的配置数据。
【2】推送式:规则管理中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 zk、Apollo等作为规则管理中心。这种方式有更好的实时性和一致性保证。实现推模式的数据源最简单的方式是继承 AbstractDataSource 抽象类,在其结构方法中添加监听器,并实现 readSource() 从指定数据源读取字符串格式的配置数据。

这里演示如何使用 zk配置规则:【1】Sentinel针对 zk做了相应适配,底层可以采用 zk作为规则配置数据源。使用时只需要添加 sentinel-datasource-zookeeper 依赖,如下 pom.xml:

 1 <dependency>
2 <groupId>com.alibaba.cloud</groupId>
3 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
4 <version>2.1.0.RELEASE</version>
5 </dependency>
6 <dependency>
7 <groupId>com.alibaba.csp</groupId>
8 <artifactId>sentinel-datasource-zookeeper</artifactId>
9 <version>1.7.2</version>
10 </dependency>

【2】在 application.properties中配置连接 sentinel控制台:

1 # 设置应用名称
2 spring.application.name=SentinelZookeeper
3 # 设置 Sentinel连接控制台的主机地址和端口
4 spring.cloud.sentinel.transport.dashboard=localhost:9000

【3】创建 zkSentinelConfig,设置客户端修改获取规则的地方为从 zk获取规则。

五、Sentinel 主要功能设计理念


流量控制:流量控制在网络传输中是一个常用概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:
流量控制设计理念:流量控制有以下几个角度:
【1】资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
【2】运行指标,例如 QPS、线程池、系统负载等;
【3】控制的效果,例如直接限流、冷启动、排队等;
Sentinel 的设计理念是让你自由选择控制的角度,并进行灵活组合,从而达到想要的效果;

熔断降级:除了流量控制以外,及时对调用链路中的不稳定因素进行熔断也是 Sentinel的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,可能会导致请求发生堆积,进而导致级联错误。
Sentinel 和 Hystrix 的原则是一致的: 当检测到调用链路中某个资源出现不稳定的表现,例如请求响应时间长或异常比例升高的时候,则对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。Hystrix 通过线程池隔离的方式,来对依赖(在 Sentinel 的概念中对应 资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本(过多的线程池导致线程数目过多),还需要预先给各个资源做线程池大小的分配。 如下图:

Sentinel 对这个问题采取了两种手段:
【1】通过并发线程数进行限制:和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。
【2】通过响应时间对资源进行降级:除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

系统负载保护:Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。

针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

1、Sentinel 的工作机制


Sentinel 的工作机制如下:
【1】对主流框架提供适配或者显示的 API,来定义需要保护的资源,并提供设施对资源进行实时统计和调用链路分析。
【2】根据预设的规则,结合对资源的实时统计信息,对流量进行控制。同时,Sentinel提供开放的接口,方便你定义及改变规则。
【3】Sentinel 提供实时的监控系统,方便你快速了解目前系统的状态;

Sentinel 流量控制的相关教程结束。

《Sentinel 流量控制.doc》

下载本文的Word格式文档,以方便收藏与打印。