Spring Cloud Gateway 擴展支持動態限流

以前分享過 一篇 《Spring Cloud Gateway 原生的接口限流該怎麼玩》, 核心是依賴Spring Cloud Gateway 默認提供的限流過濾器來實現redis

原生RequestRateLimiter 的不足

  • 配置方式spring

spring:
 cloud:
   gateway:
     routes:
     - id: requestratelimiter_route
       uri: lb://pigx-upms
       order: 10000
       predicates:
       - Path=/admin/**
       filters:
       - name: RequestRateLimiter
         args:
           redis-rate-limiter.replenishRate: 1  
           redis-rate-limiter.burstCapacity: 3
           key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表達式去的對應的bean
       - StripPrefix=1
  • RequestRateLimiterGatewayFilterFactory數據庫

public GatewayFilter apply(Config config) {
KeyResolver resolver = getOrDefault(config.keyResolver, defaultKeyResolver);
RateLimiter<Object> limiter = getOrDefault(config.rateLimiter,
defaultRateLimiter);
boolean denyEmpty = getOrDefault(config.denyEmptyKey, this.denyEmptyKey);
HttpStatusHolder emptyKeyStatus = HttpStatusHolder
.parse(getOrDefault(config.emptyKeyStatus, this.emptyKeyStatusCode));

return (exchange, chain) -> {
return exchange.getResponse().setComplete();
});
});
};
}
  • 在實際生產過程當中,一定不能知足咱們的需求api

    生產中路由信息是保存數據庫持久化或者配置中心,RequestRateLimiterGatewayFilterFactory 並不能隨着持久化數據的改變而動態改變限流參數,不能作到實時根據流量來改變流量閾值併發

Sentinel 流控

       隨着微服務的流行,服務和服務之間的穩定性變得愈來愈重要。Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性,分佈式系統的流量防衛兵。
從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模塊,能夠提供兩種資源維度的限流:route 維度:即在 Spring 配置文件中配置的路由條目,資源名爲對應的 routeId 自定義 API 維度:用戶能夠利用 Sentinel 提供的 API 來自定義一些 API 分組app

pom 依賴

<!--Spring Cloud Alibaba 封裝的 sentinel 模塊-->
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

<!--使用nacos 保存限流規則-->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

配置本地路由規則及其sentinel數據源

spring:
 application:
   name: sentinel-spring-cloud-gateway
 cloud:
   gateway:
     enabled: true
     discovery:
       locator:
         lower-case-service-id: true
     routes:
     - id: pigx_route
       uri: https://api.readhub.cn
       predicates:
       - Path=/topic/**
   sentinel:
     datasource.ds1.nacos:
       server-addr: 127.0.0.1:8848
       data-id: gw-flow
       group-id: DEFAULT_GROUP
       ruleType: gw-api-group
     filter:
       enabled: true

配置nacos數據源中的限流策略

圖片

  • 經常使用限流策略 常量async

以客戶端IP做爲限流因子
public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;
以客戶端HOST做爲限流因子
public static final int PARAM_PARSE_STRATEGY_HOST = 1;
以客戶端HEADER參數做爲限流因子
public static final int PARAM_PARSE_STRATEGY_HEADER = 2;
以客戶端請求參數做爲限流因子
public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;
以客戶端請求Cookie做爲限流因子
public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;
  • 核心源碼解析 SentinelGatewayFilter分佈式

sentinel經過擴展Gateway的過濾器,經過選擇的不一樣GatewayParamParser 過處理請求限流因子和數據源中的配置進行比較 源碼以下:ide

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
   Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);

   Mono<Void> asyncResult = chain.filter(exchange);
   if (route != null) {
       String routeId = route.getId();
       Object[] params = paramParser.parseParameterFor(routeId, exchange,
           r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_ROUTE_ID);
       String origin = Optional.ofNullable(GatewayCallbackManager.getRequestOriginParser())
           .map(f -> f.apply(exchange))
           .orElse("");
       asyncResult = asyncResult.transform(
           new SentinelReactorTransformer<>(new EntryConfig(routeId, EntryType.IN,
               1, params, new ContextConfig(contextName(routeId), origin)))
       );
   }

   Set<String> matchingApis = pickMatchingApiDefinitions(exchange);
   for (String apiName : matchingApis) {
       Object[] params = paramParser.parseParameterFor(apiName, exchange,
           r -> r.getResourceMode() == SentinelGatewayConstants.RESOURCE_MODE_CUSTOM_API_NAME);
       asyncResult = asyncResult.transform(
           new SentinelReactorTransformer<>(new EntryConfig(apiName, EntryType.IN, 1, params))
       );
   }

   return asyncResult;
}

效果演示

  • 以上nacos 配置爲 每秒只能經過5個請求,咱們使用jmeter 4.0 來併發10個線程測試一下 圖片微服務

  • 經過上圖能夠結果證實sentinel限流確實有效

動態修改限流參數

  • sentinel-datasource-nacos 做爲sentinel的數據源,能夠從如上 nacos 管理臺實時刷新限流參數及其閾值

  • 目前sentinel dashboard 1.6.2 暫未實現gateway 流控圖形化控制  1.7.0會增長此功能

相關文章
相關標籤/搜索