首頁>技術>

Gateway在微服務架構系統中,為系統內部服務提供一道安全屏障,提高系統可用性、安全性等問題。使用Gateway可幫助開發人員快速開發應用,而不需要關心安全控制、流量控制、審計日誌、版本控制等問題。

為什麼需要限流

簡單的說限流就是讓控制流量讓它們合理、平滑、有效的傳遞到內部服務,而不是隨意想進就進,影響系統執行。比如以下一些情況就會使系統流量在短時間內增加從而導致一些意想不到的問題:

使用者增長速度快業務高峰時間段保證業務可用性應對網路爬蟲防止惡意刷單、非法訪問系統...

上面列出的這些情況是很難預知的,如果某個事件導致服務的流量在很短時間內突然增長太快,在沒有限流的情況下會導致服務不可用、系統壓力大最終可能會使伺服器自動重啟(古時候是要殺頭的~~)。相反如果有了限流就會好很多流量會得到有效控制,超過閾值的訪問直接在閘道器層就會被拒絕,這樣就可以減少服務壓力,達到保護內部服務的目的。

限流策略

限制流量也不是隨意限制的,限制的不好會適得其反,下面列舉幾種常見的限流策略:

按remote地址限流按user限流按Api限流按remote地址 + api按remote地址 + user...

策略有很多,選擇最合適的才是最好的,就拿remote ip來限制來說,比如有幾百個人在區域網內共享一個公網IP,系統每秒限制10個請求那這幾百人在使用你們應用的時候經常會被拒絕,那體驗也太差了,這種情況如果按user來限制每個使用者都能每秒發10個請求,再給api加個總的限制也許就會比remote策略好很多。所以在限制流量的時候也要考慮策略方面的因素,選擇最適合業務場景的策略。

Spring Cloud Gateway限流原理

使用Spring Cloud Gateway後,如果進行流量管理呢?下面我們就來探討下如何使用Spring Cloud Gateway進行流量管理,先簡單了解下Spring Cloud Gateway的工作原理:

經過上面圖不難發現,流量會依次進入:

Gateway Handler MappingGateway Web HandlerFilter最後達到內部服務(Proxied Service)

到達Proxied Service後的請求如何處理Gateway就不管了,處理完成之後請求又回到Gateway做後處理。搞清楚請求的走向,我們就可以在請求處理之前和之後對請求做一些不可描述的事了!!。

RequestRateLimiterGatewayFilterFactory 過濾器

Spring Cloud Gateway很多內建的Filter,如:AddRequestHeader、AddRequestParameter等等,這些都可以直接拿來使用,只需要簡單配置引數即可。本文只關注RequestRateLimiter內建的過濾器來完成限流。首先寫一個測試介面:

package com.example.gateway;@RestController@RequestMapping("/traffic")public class TrafficController { @GetMapping public ResponseEntity<String> testTrafficLimit(){ return ResponseEntity.ok("Success"); }}

然後再配置下路由:

 spring: cloud: gateway: routes: - id: traffic_litmit uri: http://localhost:8080 predicates: - Path=/traffic_route filters: - RewritePath=/traffic_route, /traffic - name: RequestRateLimiter args: rate-limiter: "#{@defaultRateLimiter}" key-resolver: "#{@hostAddKeyResolver}"

上面的配置新增一個名稱為RequestRateLimiter的濾器的,RequestRateLimiter可以理解為一個過濾器工廠的名稱,Spring Cloud Gateway是通過GatewayFilter Factories去實現過濾器的,RequestRateLimiter與之對應的工廠類為RequestRateLimiterGatewayFilterFactory,那RequestRateLimiterGatewayFilterFactory是如何工作呢?

結合上面的圖,簡單的說差不多就二步:

獲取key判斷是否允許訪問

key是通過呼叫KeyResolver例項來獲取的,判斷是否允許訪問是通過呼叫RateLimiter來決定的。分工還是很明確的,所以要使用Spring Cloud Gateway限流只需要實現這兩個介面再加上過濾器配置就可以啦。

使用Spring Cloud Gateway限流

上面已經大致介紹過Spring Cloud Gateway限流的一些知識,再結合Guava來做個簡單的RateLimiter來演示下限流的使用,話不多說上程式碼:

public class DefaultRateLimiter extends AbstractRateLimiter<DefaultRateLimiter.Config> { Logger logger = LoggerFactory.getLogger(DefaultRateLimiter.class.getName()); /** * 預設一秒一個請求,多了不收了~~ */ private final RateLimiter limiter = RateLimiter.create(1); public DefaultRateLimiter() { super(Config.class, "default-rate-limit", null); } @Override public Mono<Response> isAllowed(String routeId, String id) { Config config = getConfig().get(routeId); limiter.setRate(Objects.isNull(config.getPermitsPerSecond()) ? 1 : config.getPermitsPerSecond()); logger.info("Rate: {}", limiter.getRate()); boolean isAllow = limiter.tryAcquire(); logger.info("isAllow: {} , time: {}",isAllow, System.currentTimeMillis()); return Mono.just(new Response(isAllow, new HashMap<>())); } @Validated public static class Config { @DecimalMin("0.1") private Double permitsPerSecond; public Double getPermitsPerSecond() { return permitsPerSecond; } public Config setPermitsPerSecond(Double permitsPerSecond) { this.permitsPerSecond = permitsPerSecond; return this; } }}

再修改一下過濾器的配置即可完成限流功能:

filters: - RewritePath=/traffic_route, /traffic - name: RequestRateLimiter args: rate-limiter: "#{@defaultRateLimiter}" key-resolver: "#{@hostAddKeyResolver}" default-rate-limit.permitsPerSecond: 0.5

這樣就完成一個自定義的RateLimiter了, 如果沒有什麼特殊要求的話可以直接使用RedisRateLimiter來實現限流,這個是內建限流器只需要簡單配置兩個引數就能使用:

 filters: - StripPrefix=1 - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 1 redis-rate-limiter.burstCapacity: 2

引數說明:

redis-rate-limiter.replenishRate:允許使用者每秒處理多少個請求redis-rate-limiter.burstCapacity:令牌桶的容量,允許在一秒鐘內完成的最大請求數

總結

本文簡單的介紹了閘道器的一些知識和Spring Cloud Gateway限流的實現,希望對大家有所幫助。

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 最近學到的Git知識,大廠的Git機制還是很方便的