前言
- 当前在spring boot 是不spring cloud上运行sentinel
- 环境: spring boot
2.4.9
, sentinel2021.1
- 主要配置运行,只讲限流方式,且不讲解控制台操作(不需要使用),不配置
nacos
持久化 - 只用注解式
- 官方
解决方案
- 引入sentinel
<!-- sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
- 还是贴出所有pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
- 提一下跑时出现的一个坑,引入了一个以下包,导致跑时出现异常无法启动
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
- 修改为,
hibernate-validator
包含validation-api
,但是sentinel缺少其他配置所以无法启动
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>7.0.1.Final</version>
</dependency>
- 还是贴以下外部配置,外部jar包控制台
spring:
cloud:
sentinel:
transport:
dashboard: localhost:30010
heartbeat-interval-ms: 1000
enabled: true
- 创建一个
CustomBlockHandler
外部控制异常捕获(只针对控制台操作),new RestBean<>(RestCodeType.BUSY_BUSINESS)
这些变更为自己的异常代码
@Configuration
public class CustomBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
String msg = null;
if (e instanceof FlowException) {
//限流
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_BUSINESS));
} else if (e instanceof DegradeException) {
//BUSY_TOO_MANY_PEOPLE
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_UNREACHABLE));
} else if (e instanceof ParamFlowException) {
//热点参数限流
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_BUSINESS));
} else if (e instanceof SystemBlockException) {
//系统规则
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_UNREACHABLE));
} else if (e instanceof AuthorityException) {
//授权规则
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_UNREACHABLE));
}
response.setStatus(400);
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().write(msg);
response.getWriter().close();
}
}
- 创建一个持久化配置
CustomSentinelConfig
public abstract class CustomSentinelConfig {
@PostConstruct
private void config() {
List<FlowRule> flowRules = new ArrayList<>();
/**
* 添加限流方式
* 10次拒绝访问
*/
FlowRule flowRule1 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule1.setResource("限流-10");
//限流阈值
flowRule1.setCount(10);
//调用关系限流策略:直接、链路、关联
flowRule1.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流
flowRule1.setControlBehavior(0);
/**
* 添加限流方式
* 5次等待排队
*/
FlowRule flowRule2 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule2.setResource("限流等待-5");
//限流阈值
flowRule2.setCount(5);
//调用关系限流策略:直接、链路、关联
flowRule2.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流
flowRule2.setControlBehavior(2);
//超时时间设置
flowRule2.setMaxQueueingTimeMs(60000);
/**
* 添加限流方式
* 2次拒绝访问
*/
FlowRule flowRule3 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule3.setResource("限流-2");
//限流阈值
flowRule3.setCount(2);
//调用关系限流策略:直接、链路、关联
flowRule3.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule3.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流
flowRule3.setControlBehavior(0);
/**
* 添加限流方式
* 10次等待排队
*/
FlowRule flowRule4 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule4.setResource("限流等待-10");
//限流阈值
flowRule4.setCount(10);
//调用关系限流策略:直接、链路、关联
flowRule4.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule4.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流
flowRule4.setControlBehavior(2);
//超时时间设置
flowRule4.setMaxQueueingTimeMs(60000);
/**
* 添加限流方式
* 线程最多五个
*/
FlowRule flowRule5 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule5.setResource("线程-5");
//限流阈值
flowRule5.setCount(5);
//调用关系限流策略:直接、链路、关联
flowRule5.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule5.setGrade(RuleConstant.FLOW_GRADE_THREAD);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流
flowRule5.setControlBehavior(0);
//超时时间设置
flowRule5.setMaxQueueingTimeMs(60000);
/**
* 组装限流
*/
flowRules.add(flowRule1);
flowRules.add(flowRule2);
flowRules.add(flowRule3);
flowRules.add(flowRule4);
flowRules.add(flowRule5);
FlowRuleManager.loadRules(currentLimitRules(flowRules));
}
/**
* 限流规则配置
*
* @param rules
* @return
*/
protected abstract List<FlowRule> currentLimitRules(List<FlowRule> rules);
}
- 以上是一个abstract类,继承类为
SentinelConfig
,这里看个人配置,我这里是为了方便配置
@Configuration
public class SentinelConfig extends CustomSentinelConfig {
@Override
protected List<FlowRule> currentLimitRules(List<FlowRule> rules) {
return rules;
}
}
- 以下开始有点特殊,创建一个测试类
@RestController
public class SentinelController {
@SentinelResource(value = "线程-5")
@RequestMapping(value = "/ss")
public String ss(String id, HttpServletResponse response) throws Exception {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
return "访问结果";
}
}
- 按照官方写法应为
@RestController
public class SentinelController {
@SentinelResource(value = "线程-5",blockHandler = "ssHandler")
@RequestMapping(value = "/ss")
public String ss(String id, HttpServletResponse response) throws Exception {
try {
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
return "访问结果";
}
public String ssHandler(String id, HttpServletResponse response, BlockException b) throws Exception {
return "错误代码";
}
}
-
不好意思,个人代码风格有点接受不了,很恶心感觉,emmm没别的意思,注意:
CustomBlockHandler
只针对外部配置,内部的不生效,不要再问为什么 -
那就把
ssHandler
剔掉,blockHandler = "ssHandler"
也踢掉,变成了一个注释搞的
@SentinelResource(value = "线程-5")
- 当然还要加入其它配置,业务入口必须加入
throws Exception
,否则会报其它异常
public String ss(String id, HttpServletResponse response) throws Exception {
- 全局捕获异常加入,我这里使用文本比对的,你们可以替换为类比较
...
else if (msg.contains("FlowException")) {
logger.error("全局异常捕获,限流开始", "FlowException");
restBean.setType(RestCodeType.BUSY_BUSINESS, e);
}
...
-
基本就配置完成了,来一次测试,我这里是限制同时五个线程
image.png
-
比对限流响应时间
全局异常捕获
- 置于响应时间为什么那么久,我这边请求软件高并发的问题。但是同样,全局捕获肯定比自定义要慢这是当然的,全局捕获还有其他判断。。这是当然的,以下去除休眠网页访问时间。
image.png
- 其它限流方式就不贴出了
结尾
- 有不对的地方请您指正
- 一定要加
throws Exception
不然就是另一个异常
网友评论