简介
Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级高可用流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度来帮助用户保护服务的稳定性。
本文主要讲限流、熔断降级、热点、系统保护、授权等方面,并持久化到Nacos中。
安装sentinel控制台
官方下载地址:https://github.com/alibaba/Sentinel/releases
提供1.7的版本:https://pan.baidu.com/s/1JS2tP_7T0Coh4lE5tEOX5Q 提取码:tffz
启动命令:
nohup java -server -Xms256m -Xmx256m -jar -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=sentinel -Dserver.port=9090 -Dserver.servlet.session.timeout=7200 sentinel-dashboard-1.7.0.jar > sentinel.log 2>&1 &
访问: http://localhost:9090/#/dashboard/home 账号密码都是: sentinel
默认用户名和密码都是 sentinel。也可指定用户名密码:
- Dsentinel.dashboard.auth.username=sentinel 用于指定控制台的登录用户名为 sentinel;
- Dsentinel.dashboard.auth.password=123456 用于指定控制台的登录密码为 123456;
- Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服务端 session 的过期时间,如 7200 表示 7200 秒;60m 表示 60 分钟,默认为 30 分钟;
增加相应依赖
除了sentinel依赖,还需要增加持久化依赖。如果不持久化,服务每次重启后,规则策略都需要重新配置。
sentinel提供的持久化配置中心有redis、nacos、zk、file等,我选用的是Nacos,前文也介绍了Nacos作为配置中心的搭建过程。
-
<!--sentinel-->
-
<dependency>
-
<groupId>com.alibaba.cloud</groupId>
-
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
-
</dependency>
-
<!--sentinel持久化到nacos-->
-
<dependency>
-
<groupId>com.alibaba.csp</groupId>
-
<artifactId>sentinel-datasource-nacos</artifactId>
-
</dependency>
增加项目配置项
-
spring:
-
application:
-
name: gourdhu-service
-
cloud:
-
# nacos-配置
-
nacos:
-
# 配置中心
-
config:
-
server-addr: 47.103.5.190:8848
-
file-extension: yaml
-
encode: UTF-8
-
group: GOURD
-
namespace: 0d1fc564-ffec-4670-a634-77b4c607d80f
-
# sentinel 流控
-
sentinel:
-
# 取消Sentinel控制台懒加载
-
eager: true
-
# 控制台地址
-
transport:
-
port: 8719
-
dashboard: 10.10.10.100:9090
-
# 持久化数据库-nacos
-
datasource:
-
# 限流
-
flow:
-
nacos:
-
dataId: ${spring.application.name}-sentinel-flow.json
-
groupId: GOURD
-
# 规则
-
ruleType: flow
-
server-addr: ${spring.cloud.nacos.config.server-addr}
-
# 熔断降级
-
degrade:
-
nacos:
-
dataId: ${spring.application.name}-sentinel-degrade.json
-
groupId: GOURD
-
# 规则
-
ruleType: degrade
-
server-addr: ${spring.cloud.nacos.config.server-addr}
-
# 系统保护
-
system:
-
nacos:
-
dataId: ${spring.application.name}-sentinel-system.json
-
groupId: GOURD
-
# 规则
-
ruleType: system
-
server-addr: ${spring.cloud.nacos.config.server-addr}
-
# 授权
-
authority:
-
nacos:
-
dataId: ${spring.application.name}-sentinel-authority.json
-
groupId: GOURD
-
# 规则
-
ruleType: authority
-
server-addr: ${spring.cloud.nacos.config.server-addr}
-
# 热点
-
hot:
-
nacos:
-
dataId: ${spring.application.name}-sentinel-hot.json
-
groupId: GOURD
-
# 规则
-
ruleType: param_flow
-
server-addr: ${spring.cloud.nacos.config.server-addr}
Nacos配置文件内容
限流规则配置:
-
[{
-
"resource": "resource",
-
"limitApp": "default",
-
"grade": 1,
-
"count": 2,
-
"strategy": 0,
-
"controlBehavior": 0,
-
"clusterMode": false
-
}]
-
# resource: 资源名
-
# limitApp-流控应用: default(所有)
-
# grade-阈值类型: qps(1),线程数(0)
-
# count-单机阈值: 每秒2次
-
# strategy-流控模式: 直接(0),关联(1),链路(2)
-
# controlBehavior-流控方式: 快速失败(0),Warm Up(1),排队等待(2)
Nacos中配置:
Sentinel控制台显示:
熔断降级规则配置:
-
[{
-
"resource": "resource",
-
"limitApp": "default",
-
"count": 60000,
-
"grade": 0,
-
"timeWindow": 20
-
}]
-
# grade-阈值类型: 异常比例(1),RT(0)
-
# timeWindow-时间窗口:降级时间间隔, 单位秒
热点规则配置:
-
[{
-
"resource": "hot-resource",
-
"limitApp": "default",
-
"grade": 1,
-
"paramIdx": 0,
-
"count": 1,
-
"controlBehavior": 0,
-
"maxQueueingTimeMs": 0,
-
"burstCount": 0,
-
"durationInSec": 1,
-
"paramFlowItemList": [],
-
"clusterMode": false
-
}]
-
# paramIdx: 参数索引,从0开始
-
# durationInSec:统计窗口时长,默认1s
-
# paramFlowItemList:参数例外项
系统保护规则配置:
-
[{
-
"highestSystemLoad": -1,
-
"qps": 200,
-
"avgRt": -1,
-
"maxThread": -1,
-
"highestCpuUsage": -1
-
}]
-
# -1表示失效
授权规则配置:
-
[{
-
"resource": "auth-resource",
-
"limitApp": "default",
-
"strategy": 0
-
}]
-
# strategy: 授权规则,0-白名单(默认),1-黑名单
授权规则限制可以用一句话就说明:如果配置的策略是黑名单且requester在配置在limitApp中,则请求拦截;如果配置的策略是白名单且requester在配置不在limitApp中,则请求拦截;否则请求不拦截。
至此,sentinel 的整合就好了,下面启动项目,开始测试
启动项目测试
启动成功后,在控制台看到以下输出,说明配置成功
或者直接去sentinel控制台查看流控、降级、系统规则中是否存在记录:
Jmeter测试
增加限流接口,并埋点@SentinelResource:
-
@GetMapping("/sentinel")
-
@SentinelResource(value="resource")
-
@ApiOperation(value = "测试sentinel限流")
-
public BaseResponse sentinelTest() {
-
return BaseResponse.ok("success!");
-
}
-
@GetMapping("/sentinel-hot")
-
@SentinelResource(value="hot-resource")
-
@ApiOperation(value = "测试sentinel热点")
-
public BaseResponse sentinelHot(String hotkey) {
-
return BaseResponse.ok("success! hotkey: "+hotkey);
-
}
增加异常处理器:
-
/**
-
* 异常处理器
-
* @author gourd
-
*/
-
@RestControllerAdvice
-
@Slf4j
-
public class GlobalExceptionHandler {
-
/**
-
* 处理Sentinel异常
-
* @param e
-
* @return
-
*/
-
@ExceptionHandler(value = UndeclaredThrowableException.class)
-
public BaseResponse badRequestException(UndeclaredThrowableException e) {
-
Throwable undeclaredThrowable = e.getUndeclaredThrowable();
-
// 打印堆栈信息
-
log.error("异常信息:",undeclaredThrowable);
-
if(undeclaredThrowable instanceof FlowException){
-
return BaseResponse.failure("限流啦!");
-
}else if(undeclaredThrowable instanceof DegradeException){
-
return BaseResponse.failure("熔断降级啦!");
-
}else if(undeclaredThrowable instanceof ParamFlowException){
-
return BaseResponse.failure("热点限流啦!");
-
}else if(undeclaredThrowable instanceof AuthorityException){
-
return BaseResponse.failure(HttpStatus.UNAUTHORIZED.value(),"授权限制了!");
-
}
-
return BaseResponse.failure("未知异常!");
-
}
-
}
测试限流:
我配置的策略类型是QPS。
我们配置的单机QPS是2,也就是说resource资源一秒内只会处理2个请求,其他请求会快速失败返回。Jmeter并发数为3,循环1次。
测试熔断降级:
为了方便测试,我们把熔断超时时间改为1s,并把限流qps改大为50,并在接口中设置线程睡眠 1.1s,模拟超时。Jmeter并发数为1,循环10次。
我配置的策略类型是RT。
平均响应时间 (DEGRADE_GRADE_RT):当资源的平均响应时间超过阈值(DegradeRule 中的 count,以 ms 为单位)之后,资源进入准降级状态。接下来如果持续进入 5 个请求,它们的 RT 都持续超过这个阈值,那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回(抛出 DegradeException)。
测试热点数据限流:
设置限流阙值为1,统计窗口时间为1s,参数索引为0,即以接口第一个参数为热点,一个热点参数一秒内只接受一个请求。
Jmeter增加两个http请求,传不同的参数,并发数为3。
测试系统保护:
我配置的策略类型是QPS,为了方便测试,设置QPS值为5,Jmeter并发数为10,循环1次。