一、安裝sentinel
1.下載地址:sentinel v1.8.6
2.啟動sentinel dashboard,執(zhí)行以下命令:
java -Dcsp.sentinel.log.dir=D:\xxx\sentinel\logs -Dserver.port=9217 -Dcsp.sentinel.dashboard.server=localhost:9217 -Dcsp.sentinel.heartbeat.client.ip=localhost -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=sentinel -jar sentinel-dashboard-1.8.6.jar
參數(shù)解釋:
-Dcsp.sentinel.log.dir:日志保存路徑,默認(rèn):${user.home}/logs/csp/
-Dserver.port=9217:控制臺服務(wù)端口,默認(rèn):8080
-Dcsp.sentinel.dashboard.server=localhost:9217:控制臺訪問端口,默認(rèn):8080
-Dcsp.sentinel.heartbeat.client.ip=localhost:客戶端心跳ip,多網(wǎng)卡需要指定這個ip,否則啟動后報(bào)錯,可忽略
-Dproject.name=sentinel-dashboard:控制臺顯示名稱
-Dsentinel.dashboard.auth.username=sentinel:控制臺登錄賬號,默認(rèn):sentinel
-Dsentinel.dashboard.auth.password=sentinel:控制臺登錄密碼,默認(rèn):sentinel
-jar sentinel-dashboard-1.8.6.jar:運(yùn)行sentinel1.8.6 jar包
3.啟動成功界面

4.登錄控制臺,登錄賬號和密碼默認(rèn)為sentinel,啟動命令可自定義登錄賬號和密碼。

二、Gateway網(wǎng)關(guān)pom.xml引入sentinel組件
<!-- spring cloud gateway 核心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
? ? <version>3.1.4</version>
</dependency>
<!-- spring cloud gateway sentinel 適配器-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
? ? <version>1.8.6</version>
</dependency>
<!-- spring cloud gateway sentinel連接控制臺,發(fā)現(xiàn)服務(wù) -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
? ? <version>1.8.6</version>
</dependency>
三、注入對應(yīng)的 SentinelGatewayFilter 實(shí)例以及 SentinelGatewayBlockExceptionHandler即可,參考官方文檔:https://sentinelguard.io/zh-cn/docs/api-gateway-flow-control.html。
@Configuration
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit() {
initCustomizedApis();
}
private void initCustomizedApis() {
? ? Set<ApiDefinition> definitions = new HashSet<>();
? ? ApiDefinition api1 = new ApiDefinition("some_customized_api")
? ? .setPredicateItems(new HashSet<ApiPredicateItem>() {{
? ? add(new ApiPathPredicateItem().setPattern("/animal/**")
? ? .setMatchStrategy(SentinelGatewayConstants.PARAM_MATCH_STRATEGY_PREFIX));
? ? }});
? ? ApiDefinition api2 = new ApiDefinition("another_customized_api")
? ? .setPredicateItems(new HashSet<ApiPredicateItem>() {{
? ? add(new ApiPathPredicateItem().setPattern("/system/**"));
? ? }});
? ? definitions.add(api1);
? ? definitions.add(api2);
? ? GatewayApiDefinitionManager.loadApiDefinitions(definitions);
? ? }
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
rules.add(new GatewayFlowRule("system-route")
.setCount(1) // 限流閾值
.setIntervalSec(1)); // 統(tǒng)計(jì)時間窗口,單位是秒,默認(rèn)是 1 秒
rules.add(new GatewayFlowRule("animal-route")
.setCount(1) // 限流閾值
.setIntervalSec(1)); // 統(tǒng)計(jì)時間窗口,單位是秒,默認(rèn)是 1 秒
GatewayRuleManager.loadRules(rules);
}
}
四、application.yaml配置路由
server:
port: 9211
spring:
application:
name: spring-cloud-gateway
cloud:
gateway:
routes:
# Add your routes here.
- id: system_route
uri: lb://system
predicates:
- Path=/system/**
- id: animal_route
uri: lb://animal
predicates:
- Path=/animal/**
五、啟動網(wǎng)關(guān)Gateway、服務(wù),觸發(fā)限流

正常訪問

觸發(fā)限流
六、嗯哼?sentinel dashboard沒有顯示嘛,怎么回事?

按官方文檔說明,啟動配置VM參數(shù)增加:
# 注:通過 Spring Cloud Alibaba Sentinel 自動接入的 API Gateway 整合則無需此參數(shù)
-Dcsp.sentinel.app.type=1

但是?。。『孟褚膊恍校。?/span>還必須增加一個參數(shù),指向控制臺地址:
-Dcsp.sentinel.dashboard.server=localhost:9001
注意:對網(wǎng)關(guān)發(fā)起請求后,需要等待大概10秒左右,才會在sentinel dashboard看到網(wǎng)關(guān)流控控制面板。
七、小小完善
1.第六節(jié)說到,需要增加啟動配置,這里有4種解決方案。
方案一,啟動類Application增加以下參數(shù):
System.setProperty(SentinelConfig.APP_TYPE_PROP_KEY, "1");
System.setProperty("csp.sentinel.dashboard.server","localhost:9001");
System.setProperty(SentinelConfig.PROJECT_NAME_PROP_KEY,"gateway-dashboard");
方案二,啟動配置VM增加如下參數(shù):
-Dcsp.sentinel.app.type=1 -Dcsp.sentinel.dashboard.server=localhost:9001 -Dproject.name=gateway-dashboard
方案三,新增sentinel.properties配置文件,詳情參閱com.alibaba.csp.sentinel.config.SentinelConfigLoader加載配置邏輯,配置內(nèi)容如下:
project.name=gateway-dashboard # 控制臺顯示名稱
csp.sentinel.app.type=1 # 指定類型為gateway網(wǎng)關(guān)類型
csp.sentinel.dashboard.server=localhost:9211 # 指定sentinel dashboard控制臺地址
方案四,application.yaml增加自定義配置參數(shù),再參照方案一
1.自定義限流全局異常
新增異?;卣{(diào):
package com.akim.cloud.gateway.common.sentinel.handler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
public class SentinelFallbackHandler implements WebExceptionHandler {
private Mono<Void> writeResponse(ServerResponse response, ServerWebExchange exchange) {
ServerHttpResponse serverHttpResponse = exchange.getResponse();
serverHttpResponse.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
byte[] datas = "{'code':429, 'msg':'系統(tǒng)繁忙,請稍后再試!'}".getBytes(StandardCharsets.UTF_8);
DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(datas);
return serverHttpResponse.writeWith(Mono.just(buffer));
}
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
if (!BlockException.isBlockException(ex)) {
return Mono.error(ex);
}
return handleBlockedRequest(exchange, ex).flatMap(response -> writeResponse(response, exchange));
}
private Mono<ServerResponse> handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
}
}
2.改造GatewayConfiguration
可以看出上面配置api限流和服務(wù)分組時,很不友好,直接讀取application.yaml gateway配置的routes。
新增application.yaml自定義配置:
akim:
# gateway網(wǎng)關(guān)限流
sentinel:
enabled: true # 是否開啟網(wǎng)關(guān)限流,默認(rèn)true
count: 10 # 限流閾值,Double類型
intervalSec: 1 # 統(tǒng)計(jì)時間窗口,單位:秒,Long類型,默認(rèn)1秒
新增配置文件對象類SentinelProperties.java:
package com.akim.cloud.gateway.common.sentinel.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import javax.validation.constraints.NotNull;
@Data
@ConfigurationProperties("akim.sentinel")
public class SentinelProperties {
@NotNull(message = "限流閾值")
private Double count;
@NotNull(message = "統(tǒng)計(jì)時間窗口,單位:秒")
private Long intervalSec;
}
b.注入全局異常攔截
c.直接上代碼文章來源:http://www.zghlxwxcb.cn/news/detail-505753.html
package com.akim.cloud.gateway.common.sentinel.handler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.akim.cloud.gateway.common.sentinel.config.SentinelProperties;
import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import javax.annotation.PostConstruct;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@EnableConfigurationProperties(SentinelProperties.class)
@ConditionalOnProperty(prefix = "akim.sentinel", name = "enabled", matchIfMissing = true) // 如果配置文件屬性值為false,則不注入
@Configuration
@Slf4j
public class GatewayConfiguration {
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
protected final RouteDefinitionLocator routeDefinitionLocator;
private final SentinelProperties sentinelProperties;
public SentinelBlockHandler(ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
RouteDefinitionLocator routeDefinitionLocator, SentinelProperties sentinelProperties) {
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
this.routeDefinitionLocator = routeDefinitionLocator;
this.sentinelProperties = sentinelProperties;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelFallbackHandler sentinelGatewayExceptionHandler() {
return new SentinelFallbackHandler();
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
// Register the block exception handler for Spring Cloud Gateway.
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
}
@Bean
@Order(-1)
public GlobalFilter sentinelGatewayFilter() {
return new SentinelGatewayFilter();
}
@PostConstruct
public void doInit() {
// 限流api
initCustomizedApis();
// 服務(wù)分組流控
initGatewayRules();
}
private void initCustomizedApis() {
Set<ApiDefinition> definitions = new HashSet<>();
List<RouteDefinition> routeDefinitions = routeDefinitionLocator.getRouteDefinitions().collectList().block();
routeDefinitions.stream().forEach(route -> {
PredicateDefinition pathDefinition = CollUtil.findOne(route.getPredicates(),
predicateDefinition -> "Path".equals(predicateDefinition.getName()));
if (pathDefinition == null) {
log.info("[sentinel][Route({}) 沒有 Path 條件,忽略接口限流]", route.getId());
return;
}
String path = pathDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0");
if (StrUtil.isEmpty(path)) {
log.info("[sentinel][Route({}) Path 的值為空,忽略接口限流]", route.getId());
return;
}
definitions.add(new ApiDefinition(route.getId() + "-api")
.setPredicateItems(new HashSet<ApiPredicateItem>() {
{
// 匹配 Path 前綴以及其子路徑的所有請求
add(new ApiPathPredicateItem().setPattern(path)
.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); // 匹配前綴,不設(shè)置則認(rèn)為完全匹配
}
}));
});
GatewayApiDefinitionManager.loadApiDefinitions(definitions);
}
/**
* 網(wǎng)關(guān)限流規(guī)則
* GatewayFlowRule參數(shù):
* resource: 資源名稱,可以是網(wǎng)關(guān)中的route名稱或者用戶自定義的API分組名稱。
* resourceMode: 資源模型,限流規(guī)則則是針對API Gateway的 route(RESOURCE_MODE_ROUTE_ID)還是用戶在 Sentinel 中定義的API分組(RESOURCE_MODE_CUSTOM_API_NAME),默認(rèn)route。
* grade:限流指標(biāo)維度,同限流規(guī)則的 grade 字段。
* count:限流閾值。
* intervalSec: 統(tǒng)計(jì)時間窗口,單位是秒, 默認(rèn)是1秒。
* controlBehavior: 流量整形的控制效果,同限流規(guī)則的 controlBehavior字段,目前支持快速失敗和勻速排隊(duì)兩種模式,默認(rèn)快速失敗。
* burst: 應(yīng)對突發(fā)請求時額外允許的請求數(shù)目。
* maxQueueingTimeoutMs:勻速排隊(duì)模式下的最長排隊(duì)時間,單位是毫秒,僅在勻速排隊(duì)模式下生效。
* paramItem: 參數(shù)限流配置。若不提供,則代表針對參數(shù)進(jìn)行限流,該網(wǎng)關(guān)規(guī)則將會被轉(zhuǎn)換成普通流控規(guī)則;否則會轉(zhuǎn)換熱點(diǎn)規(guī)則。其中的字段如下:
* parseStrategy: 從請求中提取參數(shù)的策略,目前支持提取來源IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意Header(PARAM_PARSE_STRATEGY_HEADER)和任意URL 參數(shù)(PARAM_PARSE_STRATEGY_URL_PARAM)四種模式。
* fieldName:若提取策略選擇Header模式或者URL參數(shù)模式,則需要指定對應(yīng)的Header名稱或URL參數(shù)名稱。
* pattern和matchStrategy: 為后續(xù)參數(shù)匹配特性預(yù)留,目前末實(shí)現(xiàn)。
*/
private void initGatewayRules() {
Set<GatewayFlowRule> rules = new HashSet<>();
List<RouteDefinition> definitions = routeDefinitionLocator.getRouteDefinitions().collectList().block();
definitions.stream().forEach(route -> {
if (StrUtil.isEmpty(route.getId())) {
log.info("[sentinel][Route 沒有 Id 條件,忽略接口限流]");
return;
}
rules.add(new GatewayFlowRule(route.getId())
.setCount(sentinelProperties.getCount()) // 限流閾值
.setIntervalSec(sentinelProperties.getIntervalSec())); // 統(tǒng)計(jì)時間窗口,單位是秒,默認(rèn)是 1 秒
});
// 加載網(wǎng)關(guān)限流規(guī)則
GatewayRuleManager.loadRules(rules);
}
}
搞定!文章來源地址http://www.zghlxwxcb.cn/news/detail-505753.html
到了這里,關(guān)于Spring Cloud Gateway集成Sentinel 1.8.6及Sentinel Dashboard的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!