Sentinel功能详解
上一篇文章《Sentinel实战与原理剖析》我们没有对Sentinel的功能进行讲解,本篇文件将对它们进行详细的解析。
Sentinel控制台
首先要下载Sentinel控制台的jar包,或者下载sentinel-dashboard的源码自行编译也可以。
然后启动控制台:
引入maven依赖:
xml
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.2</version>
</dependency>
</dependencies>
- spring-cloud-starter-alibaba-sentinel:Sentinel的starter,里面包含了sentinel-transport-simple-http、sentinel-annotation-aspectj、sentinel-spring-webmvc-adapter等依赖,并且自带自动配置,比起单独引入sentinel-core、sentinel-transport-simple-http等方便许多
- spring-boot-starter-actuator:Sentinel控制台依赖需要通过actuator暴露的端点收集服务监控信息,以在"实时监控"中进行展示。
- spring-cloud-starter-bootstrap:启动时加载bootstrap配置文件。
bootstrap.yml文件:
yml
server:
port: 8888
spring:
application:
name: demo
cloud:
sentinel:
transport:
# sentinel控制台的地址
dashboard: 127.0.0.1:8080
# 本服务以sentinel控制台交互的端口
port: 8719
# 暴露actuator的/actuator/sentinel端点
management:
endpoints:
web:
exposure:
include: '*'
编写一个简单的Controller:
java
/**
* @author huangjunyi
* @date 2024年4月13日 上午8:19:32
* @desc
*/
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello world";
}
}
启动服务,测试/actuator/sentinel端点是否正常暴露:
调一遍/hello接口,这样Sentinel才会有信息。
进入控制台查看,默认账号密码是sentinel/sentinel。
在【簇点链路】可以查看接口信息:
配置流控规则:
调用/hello接口测试流控规则:
【实时监控】可以查看不同时间点的通过QPS、拒绝QPS、响应时间(ms):
流控规则
流控规则可以设置【阈值类型】、【流控模式】、【流控效果】,其中【流控效果】只有当【阈值类型】是QPS是,才能设置。
阈值类型
【阈值类型】可以设置QPS或并发线程数,QPS是每秒请求数,如果设置为QPS的话,那么当接口的每秒请求数达到指定阈值时,则触发限流,设置为并发线程数时也是类似的规则。
流控模式
【流控模式】有"直接"、"关联"、"链路"三种。
直接
以【阈值类型】为QPS为例:"直接"就是当QPS指定资源名对应的接口QPS达到单机阈值设置的值时,该接口后续的请求将被限流。比如以下例子,当/hello接口的QPS达到2时,则后续的请求将会被限流。
关联
"关联"是指关联资源达到阈值后,当前资源则被限流。
我们改造一下接口:
java
/**
* @author huangjunyi
* @date 2024年4月13日 上午8:19:32
* @desc
*/
@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/hello")
public String hello() {
return "hello " + restTemplate.getForObject("http://localhost:8888/world", String.class);
}
@GetMapping("/world")
public String world() {
return "world";
}
@GetMapping("/my")
public String my() {
return "my " + restTemplate.getForObject("http://localhost:8888/world", String.class);
}
}
现在/hello接口和/my接口,都会调用到/world接口。
控制台配置:
那么此时关联资源(/world接口)的QPS达到2时,后续对当前资源(/hello接口)的请求都会被限流。
链路
"链路"是指当前资源的QPS达到阈值时,入口资源会被限流。
由于"链路"模式的当前资源必须是被@SentinelResource注解修饰的,并且入口资源只能通过方法调用的方式调用当前资源,不能通过http请求的方式进行调用,否则会不生效。因此改造一下工程:
把/world接口抽成Service接口,/hello和/my两个接口调用world():
java
/**
* @author huangjunyi
* @date 2024年4月13日 上午8:19:32
* @desc
*/
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello() {
return "hello " + helloService.world();
}
@GetMapping("/my")
public String my() {
return "my " + helloService.world();
}
}
Service添加@SentinelResource注解:
java
/**
* @author huangjunyi
* @date 2024年4月13日 下午2:24:56
* @desc
*/
@Service
public class HelloService {
@SentinelResource("world")
public String world() {
return "world";
}
}
此时接口调用情况变成如下这样:
然后进行规则配置:/hello接口和/my接口都调用了wolrd接口,那么像下面这样配置之后,当world接口的QPS达到限流阈值时,入口资源对应的/hello接口就会被限流。
注意,为了要让链路模式流控规则生效,还要配置入口资源关闭聚合。
可以添加配置spring.cloud.sentinel.web‐context‐unify: false。
yaml
server:
port: 8888
spring:
application:
name: demo
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
port: 8719
# 入口资源关闭聚合
web-context-unify: false
management:
endpoints:
web:
exposure:
include: '*'
或者引入sentinel-web-servlet依赖,并添加一个CommonFilter过滤器,给CommonFilter添加初始化属性CommonFilter.WEB_CONTEXT_UNIFY为false。
xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
<version>1.8.5</version>
</dependency>
java
@Bean
public FilterRegistrationBean<CommonFilter> sentinelFilterRegistration() {
FilterRegistrationBean<CommonFilter> registration = new FilterRegistrationBean();
registration.setFilter(new CommonFilter());
registration.addUrlPatterns("/*");
// 入口资源关闭聚合
registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
registration.setName("sentinelFilter");
registration.setOrder(1);
return registration;
}
流控效果
【流控效果】指的是底层的限流算法,配置不同的流控效果,那么Sentinel底层使用的限流算法就不一样,自然就有不同的流控效果。
快速失败
使用的是滑动时间窗算法,统计每秒的QPS数,达到阈值则限流。
比如下面配置的单机阈值为2,流控效果为快速失败,那么Sentinel底层使用滑动时间窗算法统计每秒的QPS,当前资源的QPS达到2时,后续对当前资源的请求都会被限流。
Warm Up
使用的是令牌桶算法,需要配置【预热时长】,在【预热时长】内限流阈值会均衡增长,直到达到了【预热时长】后,限流阈值增加到【单机阈值】指定的值。
比如下面配置【流控效果】为"Warm Up",指定【预热时长】为5,【单机阈值】为10。那么服务起订之后,当前资源("/hello"接口)的限流阈值将会在5秒内匀速增长达到10。
排队等待
当配置的【流控效果】为"排队等待"时,【单机阈值】指的是每秒匀速处理的请求个数,然后还有配置【超时时间】表示当请求被限流时,等待的超时时长。
比如下面配置【流控效果】为"排队等待",【单机阈值】为10,【超时时间】为200,那么表示当前资源("/hello"接口)每秒处理10个请求,当请求被限流时,等待200毫秒。
熔断降级规则
熔断规则里面需要配置【熔断策略】,包含熔断策略:"慢调用比例"、"异常比例"、"异常数"。
然后最下面三个配置项是固定配置项。
- 熔断时长:当触发熔断时,断路器打开的时长。
- 最小请求数:当指定【统计时长】内请求数达到最小请求数时,熔断规则才生效。
- 统计时长:熔断规则的统计时长。
慢调用比例
当【熔断策略】配置为"慢调用比例时",需要设置【最大 RT】和【比例阈值】两个配置项。【最大 RT】是指最大响应时间,当一次请求的响应时长超过了这个时间限制时,就会被记为一次慢调用;【比例阈值】是指触发熔断的慢调用比例,当【统计时长】内的慢调用比例阈值达到了【比例阈值】指定的比例值时,触发熔断。
异常比例
当【熔断策略】配置为"异常比例"时,需要配置【比例阈值】配置项,该配置项指的是当前资源在【统计时长】指定的时长内异常比例达到了【比例阈值】指定的比例值时,触发熔断。
异常数
当【熔断策略】配置为"异常数"时,需要配置【异常数】配置项,当前资源在【统计时长】的时长内异常数达到【异常数】指定的数值时,触发熔断。
热点参数规则
热点参数限流需要指定参数,因此我们改造一下/hello接口,添加一个接口参数。
java
@GetMapping("/hello")
public String hello(@RequestParam int num) {
return "hello " + helloService.world();
}
【热点规则】中的配置项包含:参数索引、统计窗口时长、单机阈值、参数类型、参数值、限流阈值。
比如像下面这样配置后,当我们请求/hello?num=1在5秒内超过2次是则被限流,而num参数是其他值时则在5秒内超过3次时被限流。
系统自适应保护
【系统保护规则】是用于保护整个服务的,而不是针对一个服务中的某个资源进行保护。
【系统保护规则】需要配置"阈值类型"以及与之对应的阈值,当系统的对应指标达到了阈值时,后续对该系统的所有请求都将被限流。
阈值类型包括:
- LOAD:系统负载,就是Linux的top命令里load average的第一个值
- RT:系统所有入口流量的平均响应时长
- 线程数:系统所有入口流量的并发线程数
- 入口QPS:系统所有入口流量的QPS
- CPU使用率:系统CPU使用率
黑白名单
黑白名单在【授权规则】中配置,需要配置【资源名】和【流控应用】两个配置项,【资源名】就是当前授权规则保护的当前资源,【流控应用】指的是调用方,黑白名单限制的就是调用方法。
集群流控
【集群流控】分两种角色:"Token Client"和"Token Server"。服务作为"Token Client"请求"Token Server"获取token,当获取不到时则进行限流。
我们添加"Token Server"时需要指定【机器类型】:
- 应用内机器:选择注册到Sentinel上的某个应用所在的机器作为"Token Server"。
- 外部指定机器:指定一台外部的机器作为"Token Server"。
然后我们可以在【流控规则】中勾选【是否集群】开启集群流控,需要配置【集群阈值模式】:
单机均摊:集群总阈值 = 连接到"Token Server"的"Token Client"数量 * 均摊阈值。
总体阈值:指定的阈值就是集群的总阈值。