Sentinel用于服务降级,熔断,限流,类似Hsytrix
1 Sentinel介绍
1.1 简介
- Sentinel(哨兵):功能类似我们之前学习的hystrix
1.2 下载和安装
- 下载地址:https://github.com/alibaba/Sentinel/tags ,下载
sentinel-dashboard-1.8.1.jar
- 下载的是一个jar包,直接通过
java -jar jar包名
即可- 但默认启动的端口是8080,要保证该端口没有被占用
- 也可以通过
java -Dserver.port=端口号 -jar jar包名
,来修改sentinel的启动端口
- 访问:http://localhost:8080 ,进入后台界面,登录名密码都为sentinel
1.3 使用
- spring官网使用教程:https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_spring_cloud_alibaba_sentinel
2 初始化演示工程
- (1)创建项目
cloudalibaba-sentinel-service8401
,此项目注册到nacos,并被sentinel保护
- (2)依赖引入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web监控 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- nacos 服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- sentinel 服务降级 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
- (3)修改配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos服务地址
sentinel:
transport:
dashboard: localhost:8080 # sentinel服务地址
port: 8719 # 假如端口被占用,自动从8719开始,依次+1,直至未被占用
# 暴露服务信息
management:
endpoints:
web:
exposure:
include: "*"
- (4)主启动类
1
2
3
4
5
6
7
//注册到nacos
public class SentinelServiceMain8401 {
public static void main(String[] args) {
SpringApplication.run(SentinelServiceMain8401.class, args);
}
}
- (5)Controller层
1
2
3
4
5
6
7
8
9
10
11
12
13
public class FlowLimitController {
public String testA() {
return "---- testA";
}
public String testB() {
return "---- testB";
}
}
- (6)测试
- 项目启动,因为sentinel使用懒加载,需要访问接口后,才会显示监控对象
3 流控规则
3.1 基本介绍
- (1)资源名:唯一名称,默认请求路径
- (2)针对来源:针对调用者进行限流,填写服务名(默认default,不区分来源)
- (3)阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该api的QPS达到阈值时,进行服务限流
- 线程数:当调用该api达到阈值的时候,进行限流
- (4)是否集群
- (5)流控模式:
- 直接:api达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)
- (6)流控效果
- 快速失败:直接失败,抛出异常
- Warm Up:根据codeFactor(冷加载因子,默认13)值,从阈值/codeFactory,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
3.2 流控模式
- (1)QPS-直接-快速失败(默认)
- (2)线程数-直接-快速失败
- 当请求的线程数超过阈值,则会进行报错
- (3)关联
- 当关联的资源达到阈值是,就限流自己
- 同一个服务,不同请求路径,其中B路径请求达到阈值,但是A进行限流
- 即B惹事,A挂了
- (4)链路
- https://blog.csdn.net/qq_31155349/article/details/108478190
- 注意spring-cloud-alibaba版本,2.1.1之前和之后
3.3 流控效果
- (1)直接失败
- 前面出现过不多赘述
- 有兴趣可查看源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
- (2)warm up(预热)
- 平时网址访问量很少,突然一瞬间访问量激增,为了不让服务器崩溃,需要逐步提升访问量,然后再达到最大值,形成循环渐进的效果
- 公式:初始阈值:阈值/冷加载因子(默认3),一旦访问量达到预热启动值,在达到设置的预热时间后,阈值达到最大值
- 效果:刚开始阈值为初始阈值,比较低,会出现报错。但系统也因此提高阈值,慢慢的阈值边到最大,就不会报错
- (3)匀速排队
- 阈值类型只能选择QPS
- 控制请求通过的是渐渐间隔,避免突然一秒有大量请求,达到了阈值,只能直接报错。但排队不会直接报错,而是限定了当前秒内只能通过多少个请求,其余线程在后面稍等,当请求等待时间超过我们设置的时间,则返回限流信息
4 降级规则
4.1 基本介绍
- 慢调用比例:
- 慢调用,请求的响应时间大于最大响应时间。
- 当单位时长内,请求数大于设置的最小请求数,且慢调用比例大于阈值,则进行熔断。经过熔断时长后进入半开放状态。下一个请求响应时间小于阈值,结束熔断,否则继续熔断
- 异常比例(秒级):
- QPS >= 5 且异常比例(秒级统计)超过阈值,触发降级(熔断);时间窗口(熔断时长)结束后,进入半开放阶段,若请求成功,关闭降级(熔断),否则继续
- 异常数(分钟级):
- 异常数(分钟统计)超过阈值,触发降级(熔断);时间窗口(熔断时长)结束后,进入半开放阶段,若请求成功,关闭降级(熔断),否则继续
4.2 慢调用比例
4.3 异常比例
4.4 异常数
5 热点规则
5.1 基本介绍
- 热点参数限流,会统计请求中传入的参数,若此参数为热点参数,则对此请求进行限流
5.2 代码演示
- (1)Controller层
1
2
3
4
5
6
7
8
9
10
11
//value: 唯一标识,一般与路径相同,blockHandler:服务降级方法
public String hotKetTest( String p1,
String p2){
return "--- hot-key-test";
}
public String deal_hotKey(String p1, String p2, BlockException blockException) { //参数要一致,并且需要BlockException参数
return "你正在访问的是热点资源,请稍后访问!";
}
- (2)配置热点
- (3)测试:访问http://localhost:8401/htoKey?p1=a ,当请求超过每秒一次,会返回我们自定义的fallback方法
5.3 参数例外项
- 有时候,我们希望热点参数的特定值,可以有不同的阈值,来进行分配
5.4 问题提出
@SentinelResource
的服务降级方法,仅对于sentinel-web界面配置的内容进行服务降级,例如QPS是否达到阈值之类;但不会对Java运行异常进行服务降级,后面会教如何解决
6 系统规则
- Sentinel系统自适应限流从整体维度对应用入口流量进行控制
阈值类型 | 说明 |
---|---|
LOAD | 仅对Linux/Unix-like机器生效,当系统的load超过启发值,且系统当前的并发线程超过估算的系统容量才会触发系统保护 |
RT | 当单台机器上所有入口流浪的平均RT达到阈值触发保护机制 |
线程数 | 所有入口流量的并发线程数达到阈值触发保护机制 |
入口QPS | 当所有入口流量的QPS达到阈值触发保护机制 |
CPU使用率 | 当系统CPU使用率超过阈值触发系统保护机制 |
7 @SentinelResource注解
7.1 资源名限流 和 url限流
- (1)按资源名限流
@SentinelResource
能给限流方法起一个资源名,如果以资源名来限流,系统不会调用默认的限流返回方法,会直接页面报错,所以在使用的时候要配置限流返回方法@SentinelResource(value = "资源名", blockHandler = "限流返回方法名")
- 限流返回方法的参数要与原方法参数一样,并额外多出BlockException类型的参数
- (2)按url限流
- 按url地址进行限流,系统会调用默认的限流返回方法,就算配置了@SentinelResource也是调用默认的限流返回方法,但是默认的限流返回方法,没有任何重要的消息,不太实用
7.2 限流返回方法与业务逻辑代码分离
- (1)创建一个自定义的处理类
1
2
3
4
5
6public class CustomerBlockHandler {
public static String blockHandler1(BlockException blockException) { //必须为静态方法
return "customerHandler:这是服务降级返回的信息!";
}
}
- (2)Controller层引入服务降级方法
1
2
3
4
5
6
7
8
9
10
11
public class RateLimitController {
//处理类中的处理方法
public String handler() {
return "业务与降级处理分离测试!";
}
}
7.3 fallback
- fallback 与 blockHandler的区别
- fallback处理的是Java运行的异常,而blockHandler是处理限流规则出现的异常
使用例子:
1
2
3
4
5
6
7
8
9
10
11
12
public String getPayment( String p1){
if(p1 != null) {
throw new RuntimeException("Java业务出现异常!,非限流问题!");
}
return "调用成功!";
}
public String fallbackHandler(String p1, Throwable e) {
return e.getMessage();
}- 正常不带参访问,没出现异常。但带p1参数进行方法,异常触发fallback处理方法,页面不会报错
7.4 其他参数
exceptionToIgnore
,忽略异常- 例子:
@SentinelResource(value = "fallback", fallback = "fallbackHandler", exceptionsToIgnore = {RuntimeException.class})
- 当发生RuntimeException时,Sentinel会忽略此异常,不会为此异常寻找其服务降级方法,而是直接页面报错
8 Sentinel与OpenFeign整合
- 除了使用Sentinel的
@SentinelResource
来实现服务降级,还可以使用OpenFeign来实现服务降级
- (1)引入OpenFegin依赖
1
2
3
4
5<!-- openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- (2)修改yaml配置
1
2
3feign:
sentinel:
enabled: true #开启sentinel对feign的支持
(3)主启动类
1
2
3
4
5
6
7
8
//使用Feign
public class OrderMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderMain84.class, args);
}
}(3)Service层
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//fallback为自定义服务降级类,会自动根据同一方法名来寻找服务降级方法
public interface FeignPaymentService {
public String getPayment();
}
public class FeignPaymentFallback implements FeignPaymentService{
public String getPayment() {
return "这是Feign的服务降级方法!";
}
}(4)Controller层
1
2
3
4
5
6
7
8
9
10
11
12
public class OrderController {
//----------------Feign----------------
private FeignPaymentService feignPaymentService;
public String getFeignPayment() {
return feignPaymentService.getPayment();
}
}
- (5)测试:
- 访问:http://localhost:84/consumer/getFeignPayment
- 测试服务降级:将服务端关闭,重新访问上面链接,出现服务降级信息
9 Sentinel持久化
- (2)持久化到nacos:https://zhuanlan.zhihu.com/p/283114605