前言
講解spring boot中使用。spring cloud中使用(gateway、nacos中使用)株灸。
注意莱革,只做限流講解桐筏,同時spring boot為spring mvc框架除破。spring cloud使用spring webflux框架
基礎環(huán)境
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
文件配置
<!-- sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
-
xxx.yml
配置
spring:
cloud:
sentinel:
transport:
dashboard: localhost:30010 //控制包jar包地址托享。是否與控制臺連接開關碧查,不做測試建議注釋羊瘩,會產(chǎn)生本地文件
heartbeat-interval-ms: 5000 //心跳時間ms
enabled: true //Sentinel自動化配置是否生效
- 創(chuàng)建自定義規(guī)則配置。注意积仗,我這里spring boot項目是多模塊,為了解耦才這么寫
public abstract class CustomSentinelConfig {
@PostConstruct
private void config() {
List<FlowRule> flowRules = new ArrayList<>();
/**
* 添加限流方式
* 10次拒絕訪問
*/
FlowRule flowRule1 = new FlowRule();
//資源名,資源名是限流規(guī)則的作用對象
flowRule1.setResource("限流-10");
//限流閾值
flowRule1.setCount(10);
//調用關系限流策略:直接管搪、鏈路缀壤、關聯(lián)
flowRule1.setStrategy(0);
//限流閾值類型蛤织,QPS 或線程數(shù)模式
flowRule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒絕 / 慢啟動模式 / 排隊等待)免猾,不支持按調用關系限流蚓炬,不支持線程
flowRule1.setControlBehavior(0);
//組裝
flowRules.add(flowRule1);
/**
* 添加限流方式
* 5次等待排隊
*/
FlowRule flowRule2 = new FlowRule();
//資源名,資源名是限流規(guī)則的作用對象
flowRule2.setResource("限流等待-5");
//限流閾值
flowRule2.setCount(5);
//調用關系限流策略:直接李根、鏈路盔几、關聯(lián)
flowRule2.setStrategy(0);
//限流閾值類型顺献,QPS 或線程數(shù)模式
flowRule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒絕 / 慢啟動模式 / 排隊等待)椒袍,不支持按調用關系限流驹暑,不支持線程
flowRule2.setControlBehavior(2);
//超時時間設置
flowRule2.setMaxQueueingTimeMs(60000);
//組裝
flowRules.add(flowRule2);
/**
* 添加限流方式
* 2次拒絕訪問
*/
FlowRule flowRule3 = new FlowRule();
//資源名帆焕,資源名是限流規(guī)則的作用對象
flowRule3.setResource("限流-2");
//限流閾值
flowRule3.setCount(2);
//調用關系限流策略:直接、鏈路、關聯(lián)
flowRule3.setStrategy(0);
//限流閾值類型鲸沮,QPS 或線程數(shù)模式
flowRule3.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒絕 / 慢啟動模式 / 排隊等待)炫狱,不支持按調用關系限流,不支持線程
flowRule3.setControlBehavior(0);
//組裝
flowRules.add(flowRule3);
/**
* 添加限流方式
* 10次等待排隊
*/
FlowRule flowRule4 = new FlowRule();
//資源名剔猿,資源名是限流規(guī)則的作用對象
flowRule4.setResource("限流等待-10");
//限流閾值
flowRule4.setCount(10);
//調用關系限流策略:直接视译、鏈路、關聯(lián)
flowRule4.setStrategy(0);
//限流閾值類型归敬,QPS 或線程數(shù)模式
flowRule4.setGrade(RuleConstant.FLOW_GRADE_QPS);
//流控效果(直接拒絕 / 慢啟動模式 / 排隊等待)酷含,不支持按調用關系限流,不支持線程
flowRule4.setControlBehavior(2);
//超時時間設置
flowRule4.setMaxQueueingTimeMs(60000);
//組裝
flowRules.add(flowRule4);
/**
* 添加限流方式
* 線程最多五個
*/
FlowRule flowRule5 = new FlowRule();
//資源名弄慰,資源名是限流規(guī)則的作用對象
flowRule5.setResource("線程-5");
//限流閾值
flowRule5.setCount(5);
//調用關系限流策略:直接第美、鏈路、關聯(lián)
flowRule5.setStrategy(0);
//限流閾值類型陆爽,QPS 或線程數(shù)模式
flowRule5.setGrade(RuleConstant.FLOW_GRADE_THREAD);
//流控效果(直接拒絕 / 慢啟動模式 / 排隊等待)什往,不支持按調用關系限流,不支持線程
flowRule5.setControlBehavior(0);
//超時時間設置
flowRule5.setMaxQueueingTimeMs(60000);
//組裝
flowRules.add(flowRule5);
/**
* 組裝限流
*/
FlowRuleManager.loadRules(currentLimitRules(flowRules));
}
/**
* 限流規(guī)則配置
*
* @param rules
* @return
*/
protected abstract List<FlowRule> currentLimitRules(List<FlowRule> rules);
}
/**
* 自定義限流規(guī)則
*
* @date 2021-8-9
*/
@Configuration
public class SentinelConfig extends CustomSentinelConfig {
@Override
protected List<FlowRule> currentLimitRules(List<FlowRule> rules) {
return rules; //為了解耦慌闭,繼承默認配置别威,此處自定義增添配置
}
}
- 在接口上使用躯舔,
注意:限流可以在方法上使用,不僅僅只針對接口
/**
* 下載省古、文件
*
* @param url
* @param response
*/
@SentinelResource(value = "限流-10") //value為對應規(guī)則
@GetMapping("/download")
public void download(@RequestParam String url, HttpServletResponse response) throws Exception {
new RestBeanUtil<String, String>(null)
.build(new OnCallBeanListener<String, String>() {
@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;
}
});
}
- 返回規(guī)則
當限流時候粥庄,需要自定義一個規(guī)則配置
/**
* 自定義、外接哨兵異常
*
* @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) {
//熱點參數(shù)限流
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_BUSINESS));
} else if (e instanceof SystemBlockException) {
//系統(tǒng)規(guī)則
msg = JSON.toJSONString(new RestBean<>(RestCodeType.BUSY_UNREACHABLE));
} else if (e instanceof AuthorityException) {
//授權規(guī)則
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, "當前業(yè)務繁忙惜互,請稍后再試"),
BUSY_UNREACHABLE(70010, "當前業(yè)務暫停,請稍后再試"),
BUSY_TOO_MANY_PEOPLE(70020, "當前訪問人數(shù)過多琳拭,請稍后再試"),
BUSY_IP_BAN(70030, "超出接口訪問次數(shù)训堆,請稍后再試"),
spring cloud 限流注意:框架為webflux
- pom.xml文件配置
<!--gateway依賴,不能與web依賴放在一起-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.0.7</version>
</dependency>
<!--gateway與nacos獲取微服務-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.0.5</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
<scope>provided</scope>
</dependency>
<!-- 注冊中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>2021.1</version>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2021.1</version>
</dependency>
<!--sentinel-nacos-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.3</version>
</dependency>
<!--sentinel-gateway 暫時不用添加白嘁,后續(xù)講解-->
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>-->
<!-- <version>2021.1</version>-->
<!-- </dependency>-->
-
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: //網(wǎng)關的路由,測試使用絮缅,不成功去掉
- id: oss-service
uri: lb://oss
predicates:
- Path=/oss/**
- Method=GET,POST
-
打開nacos中心鲁沥,創(chuàng)建
sentinel-service
配置
image.png 文件配置
resource:資源名稱
limitApp:來源應用
grade:閥值類型,0---線程數(shù)耕魄,1---QPS
count:單機閥值
strategy:流控模式画恰,0---直接,1---關聯(lián)屎开,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\":\"當前業(yè)務繁忙蔼两,請稍后再試\"}}")
private String info;
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable throwable) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(info), String.class);
}
}
-
啟動項目
image.png
image.png
spring 網(wǎng)關限流基于spring-cloud-alibaba-sentinel-gateway
包
- 上面的spring cloud限流針對的是接口名稱,加上下包后逞度,將會是針對網(wǎng)關的限流
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
<version>2021.1</version>
</dependency>
-
根據(jù)項目業(yè)務需求额划,看是針對
單個接口限流
還是某類業(yè)務
限流。添加后档泽,接口限流將會失敗俊戳,二者應該是存一不兼容。
image.png 修改
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\":\"當前業(yè)務繁忙渐北,請稍后再試\"}}")
private String info;
@Override
public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable throwable) {
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(Mono.just(info), String.class);
}
}
注意
- 不必要的文件
不使用sentinel控制臺時阿逃,請注釋dashboard監(jiān)控,否則會產(chǎn)生大量警告日志
transport:
# dashboard: localhost:30010
heartbeat-interval-ms: 5000