Spring Cloud Gateway 整合 Sentinel 閘道器限流(1)
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 這些資源的流量情況。