以前分享過 一篇 《Spring Cloud Gateway 原生的接口限流該怎麼玩》, 核心是依賴Spring Cloud Gateway 默認提供的限流過濾器來實現git
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
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(); }); }); }; }
在實際生產過程當中,一定不能知足咱們的需求redis
生產中路由信息是保存數據庫持久化或者配置中心,RequestRateLimiterGatewayFilterFactory
並不能隨着持久化數據的改變而動態改變限流參數,不能作到實時根據流量來改變流量閾值spring
隨着微服務的流行,服務和服務之間的穩定性變得愈來愈重要。Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性,分佈式系統的流量防衛兵。
從 1.6.0 版本開始,Sentinel 提供了 Spring Cloud Gateway 的適配模塊,能夠提供兩種資源維度的限流:
route 維度:即在 Spring 配置文件中配置的路由條目,資源名爲對應的 routeId
自定義 API 維度:用戶能夠利用 Sentinel 提供的 API 來自定義一些 API 分組數據庫
<!--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>
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
以客戶端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;
sentinel經過擴展Gateway的過濾器,經過選擇的不一樣GatewayParamParser
過處理請求限流因子和數據源中的配置進行比較
源碼以下:api
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限流確實有效app
sentinel-datasource-nacos
做爲sentinel的數據源,能夠從如上 nacos 管理臺實時刷新限流參數及其閾值1.7.0
會增長此功能歡迎關注咱們得到更多的好玩JavaEE 實踐async
項目推薦: Spring Cloud 、Spring Security OAuth2的RBAC權限管理系統 歡迎關注分佈式