一、Sentinel 简介
Sentinel 是分布式系统的流量防卫兵,从流量控制、熔断降级、负载保护等多个维度保护系统的稳定性。
它不再需要配置很多东西,在其图形化界面进行设置即可。是 Hystrix
加量不加价的升级版
特征包括:
- 应用场景丰富:消息削峰填谷、集群流量控制、实时熔断
- 实时监控
- 引入依赖简单配置即可使用
- 定制规则管理、适配动态数据源
Sentinel 主要分为两部分:
- 核心库(Java客户端):不依赖任何框架/库,能运行与所有 Java 运行时环境,同时对 Doubbo / Spring Cloud 等框架也有较好的支持
- 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器
二、下载安装
可以看到目前最新版是 1.8.2
往下滑,下载 jar 包
下载完成后放到没有中文和空格的目录下,该目录下启动 cmd 窗口
前提:
- 配置好 JDK
- 8080 端口没被占用
cmd 窗口执行 java -jar sentinel-dashboard-1.8.2.jar
启动成功后进行访问 http://localhost:8080
账号密码同为 sentinel
三、 当前项目结构介绍
当前项目中包含十二个模块:
- 公有API:cloud-api-commons
- 服务提供者: cloud-provider-payment8001(增加 Sleuth)/8002 (端口号8001 和 8002 )
- 服务消费者(restTemplate): cloud-consumer-order80 (端口号80 ,增加 Sleuth)
- 服务消费者(OpenFeign): cloud-consumer-feign-order80(端口号80 )
- 注册中心 Eureka: cloud-eureka-server7001(端口号7001 )
- 使用断路器实现的服务提供者 (Hystrix):cloud-provider-hystrix-payment8001(端口号8001)
- 使用断路器实现的服务消费者(Hystrix):cloud-consumer-feign-hystrix-order80(端口号80)
- 服务监控(hystrixDashboard):cloud-consumer-hystrix-dashboard9001(端口号9001)
- 网关(Gateway):cloud-gateway-gateway9527(端口号9527)
- 服务提供者(基于Nacos):cloudalibaba-provider-payment9001(端口号9001)
- 服务消费者(基于Nacos):cloudalibaba-consumer-nacos-order83(端口号83)
- Nacos服务配置中心:cloudalibaba-config-nacos-client3377(端口号3377)
前文链接: https://blog.youkuaiyun.com/weixin_42547014/article/details/120334570
项目源码: https://gitee.com/zhangchouchou/spring-cloud-demo
四、项目中添加 Sentinel
1. 添加 Module,修改 POM
以 Maven 方式创建新的模块 cloudalibaba-sentinel-service8401
,在 POM 中添加引用
<dependencies>
<dependency>
<groupId>org.zjh.springclouddemo</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.11</version>
</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>
</dependency>
</dependencies>
2. 新增 YML 配置文件
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719 #默认8719,应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用HttpServer
management:
endpoints:
web:
exposure:
include: '*'
3. 添加启动类
@EnableDiscoveryClient
@SpringBootApplication
public class SentinelApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelApplication.class, args);
}
}
4. 添加 controller
@RestController
@Slf4j
public class SentinelController {
@GetMapping("/testA")
public String testA() {
return "------testA";
}
@GetMapping("/testB")
public String testB() {
return "------testB";
}
}
5. 测试
启动 Nacos
启动成功后访问 http://192.168.44.1:8848/nacos/index.html
进行检验
启动 Sentinel
Sentinel 的 jar 包目录下 cmd 窗口执行 java -jar sentinel-dashboard-1.8.2.jar
启动刚刚编写的服务
访问 Sentinel 界面
因为 Sentinel 采用的懒加载,所以界面应该为空
访问测试接口
访问 http://localhost:8401/testA
和 http://localhost:8401/testB
刷新 Sentinel 界面
五、操作介绍
1、流控规则
QPS
控制每秒的访问次数和处理请求的线程数
对 testA 接口进行流控,设置每秒访问一次,超过直接降级处理
设置完以后访问 http://localhost:8401/testA
进行测试,连续刷新后返回降级处理内容
线程
对规则进行修改
修改接口代码,让他新建线程
重启服务后多次刷新访问 http://localhost:8401/testA
注:Sentinel没有持久化,监控的服务重启后对应的监控规则就没有了
关联
当与A关联的资源B达到阈值后,就限流自己
修改流控规则:当关联资源/testB的QPS阀值超过1时,就限流/testA的REST访问。
使用 Postman 模拟并发密集访问 testB
postman 里新建多线程集合组,将请求保存到集合组
此时访问 testA
预热
用5秒钟的时间达到最大访问值10
快速刷新 testA ,刚开始会出现降级结果,慢慢就不会出现了。
比如秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。
排队等待
匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效。
设置 /testB 每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。
修改 testB ,增加打印语句
@GetMapping("/testB")
public String testB() {
log.info(Thread.currentThread().getName()+"\t ...testB");
return "------testB";
}
2、熔断降级
RT(平均响应时间,秒级)
- 平均响应时间 (DEGRADE_GRADE_RT):超过阈值 且 时间窗口内的请求>=5,两个条件同时满足后触发降级,窗口期过后关闭断路器
- RT 最大4900 ms,更大的需要通过启动配置项
-Dcsp.sentinel.statistic.max.rt=xxx
来配置。异常比例(秒级)
- QPS>=5且异常比例(秒级统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
异常数(分钟级)
- 异常数(分钟统计)超过阈值时,触发降级;时间窗口结束后,关闭降级
Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如:调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其他的资源而导致级联错误。
当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException)。
Sentinel的断路器是没有半开状态的
半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix
测试
添加测试接口
@GetMapping("/testD")
public String testD(){
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
log.info("testD 测试RT");
return "------testD";
}
使用 Jmeter 压测
添加线程组
添加 HTTP 请求
启动压测后访问 testD
永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务,
如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
后续停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK
异常比例
修改 testD 接口
新增规则
调整压测
正常访问报错,by zero
熔断处理后:
异常数
时间窗口一定要大于等于60秒
刷新5次后降级处理
3、热点规则
添加新的接口
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2) {
//int age = 10/0;
return "------testHotKey";
}
//兜底方法
public String deal_testHotKey (String p1, String p2, BlockException exception){
return "------testHotKey 兜底方法";
}
添加完接口后重启服务,先刷新 Sentinel 界面,然后访问 http://localhost:8401/testHotKey?p1=abc
添加规则
添加完成后快速刷新访问
测试
若使用 http://localhost:8401/testHotKey?p1=abc&p2=33
访问,可返回兜底方法
若仅带参数 p2 访问 http://localhost:8401/testHotKey?p2=abc
,不会返回兜底方法
其他规则
4、系统规则
六、全局兜底方法设置
启动类加上注解
1. 创建 customerBlockHandler 类用于自定义限流处理逻辑
方法必须是public static修饰的
package org.zjh.springcloud.helper;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.zjh.springcloud.entities.CommonResult;
public class CustomerBlockHandler {
public static CommonResult handleException(BlockException exception){
return new CommonResult(2020,"自定义限流处理信息.... CustomerBlockHandler --- 1");
}
public static CommonResult handleException2(BlockException exception){
return new CommonResult(2020,"自定义限流处理信息.... CustomerBlockHandler --- 2");
}
}
2. 创建新的测试接口
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
public CommonResult customerBlockHandler(){
return new CommonResult(200,"按客戶自定义",new User(11,"姓名","18320988374","男"));
}
3. 测试
访问 http://localhost:8401/rateLimit/customerBlockHandler