一、前言

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。本节将详细记录何如通过Sentinel控制台控制Sentinel客户端的各种行为。Sentinel控制台的功能主要包括:流量控制、降级控制、热点配置、系统规则和授权规则等。

二、安装控制台

Sentinel控制台下载地址: https://github.com/alibaba/Sentinel/releases ,本节我们下载sentinel-dashboard-1.8.0.jar版本,下载好后使用java -jar sentinel-dashboard-1.8.0.jar命令启动即可,默认的端口号为8080:

账号密码都是sentinel。

更多可用的启动参数配置:

  • Dsentinel.dashboard.auth.username=sentinel用于指定控制台的登录用户名为 sentinel;
  • Dsentinel.dashboard.auth.password=123456用于指定控制台的登录密码为 123456,如果省略这两个参数,默认用户和密码均为 sentinel;
  • Dserver.servlet.session.timeout=7200用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
  • -Dcsp.sentinel.dashboard.server=consoleIp:port指定控制台地址和端口。

三、搭建客户端

3.1 项目搭建

新建一个Spring Boot项目,artifactId为spring-cloud-alibaba-sentinel-dashboard-guide,项目pom内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wno704</groupId>
<artifactId>spring-cloud-alibaba-sentinel-dashboard-guide</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Alibaba-Sentinel-Dashboard-Guide</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

引入了spring-cloud-starter-alibaba-sentinel和spring-boot-starter-web依赖。

3.2 编写controller

接着在com.wno704.alibaba目录下新建controller包,然后在该包下新建TestController:

1
2
3
4
5
6
7
8
@RestController
public class TestController {

@GetMapping("test1")
public String test1() {
return "test1";
}
}

3.3 配置application.yml

1
2
3
4
5
6
7
8
9
10
server:
port: 8081
spring:
application:
name: sentinel-dashboard
cloud:
sentinel:
transport:
dashboard: localhost:8080
port: 8719
  • spring.cloud.sentinel.transport.dashboard,指定了sentinel控制台的ip和端口地址;
  • spring.cloud.sentinel.transport.port,sentinel客户端和控制台通信的端口,默认为8719,如果这个端口已经被占用,那么sentinel会自动从8719开始依次+1扫描,直到找到未被占用的端口。

3.4 测试

启动项目,使用http工具访问: http://localhost:8081/test1 ,然后登录sentinel控制台:

在簇点链路中可以看到刚刚那笔请求,我们可以对它进行流控、降级、授权、热点等配置(控制台是懒加载的,如果没有任何请求,那么控制台也不会有任何内容)。

四、流控规则

在簇点链路列表中,点击/test1后面的【流控】按钮:

  • 资源名:标识资源的唯一名称,默认为请求路径,也可以在客户端中使用SentinelResource配置;
  • 针对来源:Sentinel可以针对服务调用者进行限流,填写微服务名称即spring.application.name,默认为default,不区分来源;
  • **阈值类型、单机阈值:
    • QPS:(Queries-per-second,每秒钟的请求数量),当调用该api的QPS达到阈值的时候,进行限流;
    • 线程数:当调用该api的线程数达到阈值的时候,进行限流。
  • 是否集群:默认不集群;
  • 流控模式
    • 直接:当api调用达到限流条件的时,直接限流;
    • 关联:当关联的资源请求达到阈值的时候,限流自己;
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,则进行限流)。
  • 流控效果
    • 快速失败:直接失败;
    • Warm Up:根据codeFactor(冷加载因子,默认值为3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值;
    • 排队等待:匀速排队,让请求匀速通过,阈值类型必须设置为QPS,否则无效。

4.1 QPS直接失败

演示下QPS直接失败设置及效果。点击簇点链路列表中/test1请求后面的流控按钮:

上面设置的效果是,1秒钟内请求/test1资源的次数达到2次以上的时候,进行限流。
点击新增按钮后,列表会跳转到”流控规则”菜单下,所以我们也可以在这里设置流控规则,不过一般还是习惯直接在簇点链路列表中直接选中资源添加流控规则。新增后,我们访问 http://localhost:8081/test1 ,看看效果:

当手速快点的时候(1秒超过2次),页面返回 Blocked by Sentinel (flow limiting)。

4.2 线程数直接失败

改造下TestController:

1
2
3
4
5
6
7
8
9
@RestController
public class TestController {

@GetMapping("test1")
public String test1() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
return "test1";
}
}

让方法休眠1秒,更容易出现效果。重启项目,然后在sentinel控制台中添加如下流控规则:

多次访问 http://localhost:8081/test1 ,效果:

4.3 关联

改造TestController,添加一个新的api接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
@RestController
public class TestController {

@GetMapping("test1")
public String test1() {
return "test1";
}

@GetMapping("test2")
public String test2() {
return "test2";
}
}

重启项目,浏览器中访问下这两个请求,然后在sentinel控制台簇点链路列表中,点击test1后的流控按钮:

上述流控规则表示:当1秒内访问/test2的次数大于2的时候,限流/test1。
我们使用postman来密集访问/test2,然后我们手动浏览器请求/test1,看看效果。postman设置如下规则:

然后点击Run按钮,我们回到HTTP工具,访问: http://localhost:8081/test1

4.4 链路

在演示链路限流之前,我们先改造改造sentinel客户端代码。在项目的com.wno704.alibaba目录下新建service包,然后在该包下新建HelloService:

1
2
3
4
5
6
7
@Service
public class HelloService {
@SentinelResource("hello")
public String hello() {
return "hello";
}
}

@SentinelResource("hello")将该方法标识为一个sentinel资源,名称为hello。

接着在TestController中使用该资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class TestController {

@Autowired
private HelloService helloService;

@GetMapping("test1")
public String test1() {
return "test1 " + helloService.hello();
}

@GetMapping("test2")
public String test2() {
return "test2 " + helloService.hello();
}
}

在配置文件中新增收敛设置为无效

1
2
3
4
spring:
cloud:
sentinel:
web-context-unify: false

注意:在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,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class FilterContextConfig {

@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;
}

}

重启项目,在浏览器中多次访问这两个api,然后查看sentinel控制台簇点链路:

然后点击hello资源后面的流控按钮:

上述配置的意思是,当通过/test1访问hello的时候,QPS大于1则进行限流;言外之意就是/test2访问hello请求并不受影响。
我们回到HTTP工具,访问: http://localhost:8081/test1

4.5 预热Warm Up

流控效果除了直接失败外,我们也可以选择预热Warm Up。Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

sentinel客户端的默认冷加载因子coldFactor为3,即请求QPS从 threshold / 3 开始,经预热时长逐渐升至设定的QPS阈值。

比如:

上面的配置意思是:对于/test1资源,一开始的QPS阈值为3(10/3),经过10秒后,QPS阈值达到10,效果我就不演示了,大概效果就是使用浏览器访问 http://localhost:8081/test1 ,以最快的手速点刷新,一开始会常看到Blocked by Sentinel (flow limiting)的提示,10秒后几乎不再出现(因为你的手速很难达到1秒10下)。

4.6 排队等待

排队等待方式不会拒绝请求,而是严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过。

修改TestController的代码:

1
2
3
4
5
6
7
8
9
10
11
@RestController
@Slf4j
public class TestController {

@GetMapping("test1")
public String test1() {
log.info("test1");
return "test1";
}

}

重启项目,浏览器访问 http://localhost:8081/test1 ,然后点击sentinel控制台簇点链路列表的/test1流控按钮:

上述配置的含义是,访问/test1请求每秒钟最多只能1次,超过的请求排队等待,等待超过1000毫秒则超时。新增该规则后,多次快速访问 http://localhost:8081/test1 ,sentinel客户端控制台日志打印如下:

每笔请求时间间隔1秒。

五、降级规则

降级配置页面:

5.1 基础介绍

降级策略分为3种:

  • 慢调用比例(SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

熔断降级规则(DegradeRule)包含下面几个重要的属性:

Field说明默认值
resource资源名,即规则的作用对象
grade熔断策略,支持慢调用比例/异常比例/异常数策略慢调用比例
count慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow熔断时长,单位为 s
minRequestAmount熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)5
statIntervalMs统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)1000 ms
slowRatioThreshold慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

5.2 慢调用比例

5.3 异常比例

修改TestController的代码:

1
2
3
4
5
6
7
8
9
@RestController
public class TestController {

@GetMapping("test1")
public String test1() {
// 每次请求都抛出异常
throw new RuntimeException("服务异常");
}
}

重启项目,浏览器访问 http://localhost:8081/test1 ,然后点击sentinel控制台簇点链路列表的/test1降级按钮:

上面的配置含义是:如果/test1的QPS大于5,并且每秒钟的请求异常比例大于0.5的话,那么在未来的1秒钟(时间窗口)内,sentinel断路器打开,该api接口不可用。

也就是说,如果一秒内有10个请求进来,超过5个以上都出错,那么会触发熔断,1秒钟内这个接口不可用。

还是使用上面的JMeter测试,开启JMeter后,使用http访问: http://localhost:8081/test1

关掉JMeter后,再次访问 http://localhost:8081/test1

5.4 异常数

该策略为异常数时表示:当指定时间窗口内,请求异常数大于等于某个值时,触发降级。比如有如下规则:

上面的规则表示:在1秒内,访问/test1请求异常的次数大于等于5,则触发降级。测试一波:

六、热点规则

热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的数据,并对其访问进行限制。

比如在TestController中有如下方法:

1
2
3
4
5
    @GetMapping("buy")
@SentinelResource(value = "buy")
public String buy(String goodName, Integer count) {
return "买" + count + "份" + goodName;
}

对这个资源添加热点规则:

上面的配置含义是:对buy资源添加热点规则,当第0个参数的值为wno704的时候QPS阈值为10,否则为1。此外,如果第0个参数不传,那么这笔请求不受该热点规则限制。效果如下:

七、系统规则

系统规则则是针对整个系统设置限流规则,并不针对某个资源,设置页面如下:

阈值类型包含以下五种:

  • 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 达到阈值即触发系统保护。

比较直观就不演示了。

八、授权规则

授权规则用于配置资源的黑白名单:


上述配置表示:只有appA和appB才能访问hello资源。