前言
讲解spring boot中使用。spring cloud中使用(gateway、nacos中使用)。
注意,只做限流讲解,同时spring boot为spring mvc框架。spring cloud使用spring webflux框架
基础环境
spring boot 2.4.13
,sentinel 2021.1
,nacos 2021.1
,gateway 3.0.7
不提供sentinel控制台jar包,版本
1.8.2
。不提供nacos中心jar包,版本2.0.3
。
spring boot项目限流(需要gateway等的往下翻)
在单独的spring boot整体项目中限流,此处我做的是代码持久化,注意是
注解式
。pom.xml
文件配置
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2021.1
-
xxx.yml
配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:30010 //控制包jar包地址。是否与控制台连接开关,不做测试建议注释,会产生本地文件
heartbeat-interval-ms: 5000 //心跳时间ms
enabled: true //Sentinel自动化配置是否生效
- 创建自定义规则配置。注意,我这里spring boot项目是多模块,为了解耦才这么写
public abstract class CustomSentinelConfig {
@PostConstruct
private void config() {
List 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);
//组装
flowRules.add(flowRule1);
/**
* 添加限流方式
* 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);
//组装
flowRules.add(flowRule2);
/**
* 添加限流方式
* 2次拒绝访问
*/
FlowRule flowRule3 = new FlowRule();
//资源名,资源名是限流规则的作用对象
flowRule3.setResource("限流-2");
//限流阈值
flowRule3.setCount(2);
//调用关系限流策略:直接、链路、关联
flowRule3.setStrategy(0);
//限流阈值类型,QPS 或线程数模式
flowRule3.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒绝 / 慢启动模式 / 排队等待),不支持按调用关系限流,不支持线程
flowRule3.setControlBehavior(0);
//组装
flowRules.add(flowRule3);
/**
* 添加限流方式
* 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);
//组装
flowRules.add(flowRule4);
/**
* 添加限流方式
* 线程最多五个
*/
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(flowRule5);
/**
* 组装限流
*/
FlowRuleManager.loadRules(currentLimitRules(flowRules));
}
/**
* 限流规则配置
*
* @param rules
* @return
*/
protected abstract List currentLimitRules(List rules);
}
/**
* 自定义限流规则
*
* @date 2021-8-9
*/
@Configuration
public class SentinelConfig extends CustomSentinelConfig {
@Override
protected List currentLimitRules(List rules) {
return rules; //为了解耦,继承默认配置,此处自定义增添配置
}
}
- 在接口上使用,
注意:限流可以在方法上使用,不仅仅只针对接口
/**
* 下载、文件
*
* @param url
* @param response
*/
@SentinelResource(value = "限流-10") //value为对应规则
@GetMapping("/download")
public void download(@RequestParam String url, HttpServletResponse response) throws Exception {
new RestBeanUtil(null)
.build(new OnCallBeanListener() {
@Override
public String run(String value) throws Exception {
try {
log.info("文件下载:" + url);
ossService.handlerDownload(url, response);
} catch (Exception e) {
e.printStackTrace();
MinioUtil.downLoadFail(response, e);
}
return null;
}
});
}
- 返回规则
当限流时候,需要自定义一个规则配置
/**
* 自定义、外接哨兵异常
*
* @date 2021/8/9
*/
@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(HttpStatus.NOT_ACCEPTABLE.value());
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/json;charset=utf-8");
response.getWriter().write(msg);
response.getWriter().close();
}
}
-
RestBean
是自定义的restful风格实体,RestCodeType为枚举类
/**
* 流量限制类
*/
BUSY_BUSINESS(70000, "当前业务繁忙,请稍后再试"),
BUSY_UNREACHABLE(70010, "当前业务暂停,请稍后再试"),
BUSY_TOO_MANY_PEOPLE(70020, "当前访问人数过多,请稍后再试"),
BUSY_IP_BAN(70030, "超出接口访问次数,请稍后再试"),
spring cloud 限流注意:框架为webflux
- pom.xml文件配置
org.springframework.cloud
spring-cloud-starter-gateway
3.0.7
org.springframework.cloud
spring-cloud-loadbalancer
3.0.5
org.projectlombok
lombok
1.18.18
provided
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2021.1
com.alibaba
fastjson
1.2.75
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2021.1
com.alibaba.csp
sentinel-datasource-nacos
1.8.3
-
xxx.yml
配置
---
spring:
application:
name: gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
group: remote
namespace: b14470b8-2099-41c1-8652-8cad015b0b53
---
#限流配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:30010
heartbeat-interval-ms: 5000
datasource:
ds1:
nacos:
server-addr: 127.0.0.1:8848
dataId: sentinel-service
groupId: sentinel
data-type: json
rule_type: flow
namespace: b14470b8-2099-41c1-8652-8cad015b0b53 //看是否为个人空间,否则去掉
enabled: true //此处必须打开
---
spring:
cloud:
gateway:
discovery:
locator:
enabled: false
lower-case-service-id: true
routes: //网关的路由,测试使用,不成功去掉
- id: oss-service
uri: lb://oss
predicates:
- Path=/oss/**
- Method=GET,POST
-
打开nacos中心,创建
sentinel-service
配置
文件配置
resource:资源名称
limitApp:来源应用
grade:阀值类型,0---线程数,1---QPS
count:单机阀值
strategy:流控模式,0---直接,1---关联,2---链路
controlBehavior:流控效果,0---快速失败,1---warmUp,2---排队等待
clusterMode:是否集群
[
{
"resource": "/authentication/queryUserList",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
},
{
"resource": "/main/s",
"limitApp":"default",
"grade":1,
"count":1,
"strategy":0,
"controlBehavior":0,
"clusterMode":false
}
]
- 配置限流返回信息
@Configuration
public class SentinelHandler implements BlockRequestHandler {
@Value("${customGateWay.sentinel.info:{\"result\":7000,\"message\":\"当前业务繁忙,请稍后再试\"}}")
private String info;
@Override
public Mono handleRequest(ServerWebExchange exchange, Throwable throwable) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(info), String.class);
}
}
-
启动项目
spring 网关限流基于spring-cloud-alibaba-sentinel-gateway
包
- 上面的spring cloud限流针对的是接口名称,加上下包后,将会是针对网关的限流
com.alibaba.cloud
spring-cloud-alibaba-sentinel-gateway
2021.1
-
根据项目业务需求,看是针对
单个接口限流
还是某类业务
限流。添加后,接口限流将会失败,二者应该是存一不兼容。
修改
SentinelHandler
的继承类,否则无法正常回调
//import com.alibaba.csp.sentinel.adapter.spring.webflux.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 限流、处理器
*
* @date 2022/4/6
*/
@Configuration
public class SentinelHandler implements BlockRequestHandler {
@Value("${customGateWay.sentinel.info:{\"result\":7000,\"message\":\"当前业务繁忙,请稍后再试\"}}")
private String info;
@Override
public Mono handleRequest(ServerWebExchange exchange, Throwable throwable) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(info), String.class);
}
}
注意
- 不必要的文件
不使用sentinel控制台时,请注释dashboard监控,否则会产生大量警告日志
transport:
# dashboard: localhost:30010
heartbeat-interval-ms: 5000