sentinel 從1.6.0 版本開始,提供了Spring Cloud Gateway Adapter 模塊,支持兩種資源維度的限流。
- Route 維度
- 自定義API維度,可以利用提供的API來定義API分組,然后針對這些分組維度進行限流。需要引入如下的依賴。
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>1.7.1</version>
</dependency>
Route 維度限流
添加一個配置類 GatewayConfiguration
@Configuration
public class GatewayConfigurtion{
private final List<ViewResolver> viewResolvers;
private final ServerCodeConfigurer serverCodecConfigurer;
public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolvers, ServerCodecConfigurer serverCodecConfigurer){
this.viewResolvers=viewResolvers.getIfAvailable(Collections::emptyList)
this.serverCodecConfigurer = serverCodecConfigurer;
}
// 注入 SentinelGatewayFilter
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public GlobalFilter SentinelGatewayFilter(){
}
//注入限流異常處理器
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SentinelGatewayBlockExceptionHandler SentinelGatewayBlockExceptionHandler (){
return new SentinelGatewayBlockExceptionHandler (viewResolvers,serverCodecConfigurer);
}
@PostConstruct
public void doInit(){
initGatewayRules();
}
//初始化限流規則
private void iniGatewayRules(){
Set<GatewayFlowRule> rules= new HashSet<>();
GatewayFlowRule gatewayFlowRule=new GatewayFlowRule("nacos-gateway-provider").setCount(1).setIntervalSec(1);
rules.add(gatewayFlowRule);
GatewayRuleManager.loadRules(rules);
}
}
配置類的主要功能如下:
- 注入一個全局限流過濾器SentinelGatewayFilter.
- 注入限流異常處理器
- 初始化限流規則。在當前版本中,sentinel-spring-cloud-gateway-adapter 還只能支持手動配置。
其中,GatewayFlowRule 網關限流規則中提供了如下屬性。
- resource: 資源名稱,可以是網關中的route名稱或者用戶自定義的API分組名稱。
- resourceMode: 資源模型,限流規則則是針對API Gateway的 route(RESOURCE_MODE_ROUTE_ID)還是用戶在Sentinel 中定義的API分組(RESOURCE_MODE_CUSTOM_API_NAME),默認route.
- grade:限流指標維度,同限流規則的grade 字段。
- count:限流閾值。
- intervalSec: 統計時間窗口,單位是秒, 默認是1 秒。
- controlBehavior: 流量整形的控制效果,同限流規則的controlBehavior字段,目前支持快速失敗和勻速排隊兩種模式,默認快速失敗。
- burst: 應對突發請求時額外允許的請求數目。
- maxQueueingTimeoutMs:勻速排隊模式下的最長排隊時間,單位是毫秒,僅在勻速排隊模式下生效。
- paramItem: 參數限流配置。若不提供,則代表針對參數進行限流,該網關規則將會被轉換成普通流控規則;否則會轉換熱點規則。其中的字段如下。
parseStrategy: 從請求中提取參數的策略,目前支持提取來源IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意Header(PARAM_PARSE_STRATEGY_HEADER)和任意URL 參數(PARAM_PARSE_STRATEGY_URL_PARAM)四種模式。
fieldName:若提取策略選擇Header模式或者URL參數模式,則需要指定對應的Header名稱或URL參數名稱。
pattern和matchStrategy: 為后續參數匹配特性預留,目前末實現。
網關限流規則的加載可以通過GatewayRuleManager.loadRules(rules); 的方式手動加載,也可以通過GatewayRuleManager.register2Property(property)注冊動態限流規則(建議使用這種動態限流規則的方式)。
application.yml 文件中的配置如下,由於SentinelGatewayFilter是全局過濾器,網關配置不需要做任何調整。
spring:
application:
name: apring-cloud-nacos-gateway-consumer
cloud:
nacos:
discovery:
server-addr: 192.168.216.128:8848
gateway:
discovery:
locator:
enabled: false#開啟從注冊中心動態創建路由的功能,利用微服務名進行路由
lower-Case-Service-id: false
routes:
- id: nacos-gateway-provider
uri: lb://spring-cloud-nacos-gateway-provider
predicates:
- Path=/nacos/**
filters:
# 驗證碼處理
- StripPrefix=1
最后,通過測試工具訪問http://localhsot:8888/nacos/say, 當觸發限流之后,會獲得如下內容。
Blocked by Sentinel: ParamFlowException
自定義API分組限流
自定義API分組限流實際上就是讓多個Route公用一個限流規則。舉例來說,假設有如下兩個URI匹配規則。
spring:
cloud:
gateway:
routes:
id: foo_route
uri: http://www.foo.com
predicates:
- Path=/foo/**
- id: baz_route
uri:http://www.baz.com
predicates:
-Path=/baz/**
如果我們希望這兩個路由共用同一個限流規則,則可以采用自定義API分組限流的方式來實現。
private void initCustomizedApis(){
Set<ApiDefinition> definitions= new HashSet<>();
ApiDefinition apiDefinition=new ApiDefinition("first_customized_api")
apiDefinition.setPredicateItem(new HashSet<ApiPredicateItem>(){{
add(new ApiPathPredicateItem().setPattern("/foo/**"));
add(new ApiPathPredicateItem().setPattern("/baz/**").setMatchStrategy
(SentinelGatewayContants.URL_MATCH_STRATEGY_PREFIX));
}});
definitions.add(apiDefinition);
GatewayApiDefinitionManager.loadApiDefinitions(difinitions);
}
上述代碼主要是降/foo/** 和 /baz/**進行統一的分組,並提供一個name=first_sustomized_api, 然后再初始化網關限流規則時,針對該name設置限流規則。同時,我們可以通過setMatchStrategy 來設置不同path下的限流參數策略。
private void initGatewayRules(){
GatewayFlowRule customerFlowRule=new GatewayFlowRule("first_customized_api").
setResourceMode(SentinelGatewayContants.RESOURCE_MODE_CUSTOM_API_NAME).setCount(5).setIntervalSec(1);
}
需要注意的是,再上述代碼中,foo_route和 baz_route 這兩個路由ID 與 first_customized_api 都會標記為Sentinel 的資源(限流資源標記)。比如,當訪問網關的URI為http://localhsot:8888/foo/1時,Sentinel會統計foo_route、baz_route、first_customized_api 這些資源的流量情況。
