Gateway實現(xiàn)限流的一些常見方式
Gateway怎么實現(xiàn)限流的
在API網(wǎng)關(guān)(如Spring Cloud Gateway、Kong、Nginx等)中實現(xiàn)限流是為了控制服務(wù)請求的頻率,從而避免系統(tǒng)過載,確保穩(wěn)定性和可用性。限流可以通過多種策略實現(xiàn),常見的方法包括基于請求次數(shù)、時間窗口、IP地址等方式進行限制。下面是 Spring Cloud Gateway 實現(xiàn)限流的一些常見方式:
1.基于請求次數(shù)的限流
這種方法通過限制單位時間內(nèi)的請求次數(shù)來防止過多的請求訪問服務(wù)。例如,限制每秒鐘只能處理最多100個請求。
- Spring Cloud Gateway實現(xiàn):Spring Cloud Gateway提供了內(nèi)置的限流功能,可以通過
RequestRateLimiter
過濾器來實現(xiàn)基于請求次數(shù)的限流。 示例配置:
spring: cloud: gateway: routes: - id: rate_limiter_route uri: http://example.com predicates: - Path=/api/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒鐘請求的數(shù)量 redis-rate-limiter.burstCapacity: 20 # 突發(fā)容量,即短時間內(nèi)允許的最大請求數(shù)
replenishRate
: 每秒鐘允許的請求數(shù)。burstCapacity
: 突發(fā)容量,表示短時間內(nèi)可以處理的最大請求數(shù),超過該數(shù)的請求會被丟棄或拒絕。
2.基于令牌桶算法(Token Bucket)限流
令牌桶算法是一種平滑請求流量的算法,它通過固定的速率生成令牌并將其存放在桶中,請求到達時需要獲取令牌才能處理,如果令牌桶為空,則請求被拒絕。
Spring Cloud Gateway實現(xiàn):使用RequestRateLimiter
實現(xiàn)基于令牌桶的限流。
示例配置:
spring: cloud: gateway: routes: - id: token_bucket_route uri: http://example.com predicates: - Path=/api/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 # 每秒生成的令牌數(shù) redis-rate-limiter.burstCapacity: 20 # 令牌桶的容量
這里的配置和上面的請求次數(shù)限制類似,但背后實現(xiàn)的是令牌桶算法。
3.基于IP限流
可以根據(jù)客戶端IP地址來限制每個IP的請求頻率,避免某個客戶端過度訪問服務(wù)。通常使用Redis來實現(xiàn)基于IP的限流。
示例配置(使用Redis):
spring: cloud: gateway: routes: - id: ip_rate_limiter_route uri: http://example.com predicates: - Path=/api/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 10 redis-rate-limiter.burstCapacity: 20 redis-rate-limiter.requestedTokens: 1 redis-rate-limiter.keyResolver: "#{@ipKeyResolver}"
在這個例子中,keyResolver
指定了如何基于客戶端 IP 地址來限流,可以自定義一個IP解析器ipKeyResolver
,這樣每個IP的請求次數(shù)會被限制。
4.基于時間窗口的限流
時間窗口限流是按照固定的時間窗口(如每分鐘、每小時等)來限制請求的數(shù)量。通過時間窗口來控制單位時間內(nèi)的最大請求數(shù)。
示例配置:
spring: cloud: gateway: routes: - id: time_window_route uri: http://example.com predicates: - Path=/api/** filters: - name: RequestRateLimiter args: redis-rate-limiter.replenishRate: 5 # 每秒鐘請求的數(shù)量 redis-rate-limiter.burstCapacity: 10 # 突發(fā)容量 redis-rate-limiter.requestedTokens: 1 # 每次請求消耗的令牌數(shù)
這種方式將請求限制在一定的時間窗口內(nèi),如果在窗口內(nèi)的請求數(shù)量超過限制,將拒絕額外的請求。
5.自定義限流策略
Spring Cloud Gateway 還允許通過自定義KeyResolver
、RateLimiter
等來實現(xiàn)更靈活的限流策略。例如,基于用戶的ID、API路徑等來做不同的限流策略。
自定義KeyResolver
示例:
@Bean public KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostString()); }
這個例子通過客戶端IP地址進行限流。
6.其他網(wǎng)關(guān)限流工具
除了Spring Cloud Gateway,其他網(wǎng)關(guān)如 Kong、Nginx 等也提供了豐富的限流功能:
- Kong使用插件機制實現(xiàn)限流,支持基于請求次數(shù)、IP、API Key等的限流。
- Nginx可以通過
limit_req
和limit_conn
模塊來進行限流控制。
總結(jié)
在 Spring Cloud Gateway 中,常見的限流方式包括:
- 基于請求次數(shù)的限流(Rate Limiting)
- 基于令牌桶算法的限流(Token Bucket)
- 基于IP的限流
- 基于時間窗口的限流
可以通過RequestRateLimiter
過濾器實現(xiàn)這些策略,結(jié)合 Redis 等存儲技術(shù)來共享和持久化限流狀態(tài)。在選擇限流策略時,需要根據(jù)業(yè)務(wù)需求、流量模式、以及系統(tǒng)的負載能力來決定。
分析Gateway 限流代碼
@Component public class RateLimitConfig { @Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("token")); } @Bean KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); } @Bean KeyResolver apiKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getPath().value()); } @Primary @Bean KeyResolver appIpKeyResolver() { return exchange -> { Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); return Mono.just(exchange.getRequest().getRemoteAddress().getHostName().concat(route.getUri().getHost())); }; } }
這段代碼實現(xiàn)了Spring Cloud Gateway的限流配置,具體的實現(xiàn)通過不同的KeyResolver
來為請求提供唯一的標識,用于區(qū)分不同的請求來源或策略。KeyResolver
是限流的核心組成部分,它決定了限流的“鍵”(即每個請求的唯一標識),從而確保不同的請求按照不同的規(guī)則被限流。
以下是對代碼的詳細分析:
1.KeyResolver
的作用
KeyResolver
是 Spring Cloud Gateway 中限流機制的一部分,用來生成與請求相關(guān)的唯一“鍵”。在限流時,基于這些“鍵”來計算每個限流單元(例如每個用戶、每個IP、每個API等)的請求次數(shù)。限流規(guī)則會依據(jù)這些鍵來進行流量控制。
2.userKeyResolver
@Bean KeyResolver userKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("token")); }
- 功能:該
KeyResolver
基于請求的查詢參數(shù)token
生成唯一的限流鍵。 - 應(yīng)用場景:當(dāng)客戶端使用
token
參數(shù)(可能是API Key或用戶身份標識符)時,可以基于該token
對每個用戶進行限流。每個用戶(或每個token
)的請求次數(shù)將被單獨計數(shù)。 - 具體實現(xiàn):從請求的查詢參數(shù)中獲取
token
參數(shù)的第一個值。如果沒有這個參數(shù),返回null
或空值會導(dǎo)致限流功能不生效。
3.ipKeyResolver
@Bean KeyResolver ipKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); }
- 功能:該
KeyResolver
基于客戶端的 IP 地址生成限流鍵。 - 應(yīng)用場景:當(dāng)需要限制每個IP地址的請求頻率時,使用此
KeyResolver
。例如,可以限制每個IP在一定時間窗口內(nèi)的請求次數(shù),從而避免單個IP的過多請求對系統(tǒng)造成壓力。 - 具體實現(xiàn):通過
exchange.getRequest().getRemoteAddress()
獲取客戶端的遠程IP地址,然后使用getHostName()
獲取IP的主機名。理論上,getHostName()
會嘗試解析IP地址為主機名,但在某些情況下,可能直接返回IP地址。
4.apiKeyResolver
@Bean KeyResolver apiKeyResolver() { return exchange -> Mono.just(exchange.getRequest().getPath().value()); }
- 功能:該
KeyResolver
基于請求的API路徑生成唯一的限流鍵。 - 應(yīng)用場景:當(dāng)需要限制某個API路徑的請求頻率時,使用此
KeyResolver
。例如,限制/api/v1/login
或/api/v1/register
路徑的訪問頻率,可以防止某個特定API被過度訪問。 - 具體實現(xiàn):通過
exchange.getRequest().getPath().value()
獲取請求的路徑。這個路徑通常是 URI 的路徑部分,如/api/v1/resource
。
5.appIpKeyResolver
@Primary @Bean KeyResolver appIpKeyResolver() { return exchange -> { Route route = (Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); return Mono.just(exchange.getRequest().getRemoteAddress().getHostName().concat(route.getUri().getHost())); }; }
- 功能:該
KeyResolver
綜合了客戶端的 IP 地址和路由的 URI 來生成限流鍵。 - 應(yīng)用場景:當(dāng)希望根據(jù)客戶端 IP 和訪問的具體服務(wù)進行限流時,使用此
KeyResolver
。例如,可以限制每個IP對特定API的訪問頻率。 - 具體實現(xiàn):
- 通過
exchange.getRequest().getRemoteAddress().getHostName()
獲取客戶端的 IP 地址。 - 通過
exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR)
獲取當(dāng)前請求的路由信息。 route.getUri().getHost()
獲取請求目標服務(wù)的主機名(或域名),并將其與客戶端IP拼接,作為限流的唯一鍵。- 使用
concat()
方法將客戶端IP與目標服務(wù)主機名合并為一個字符串,以保證限流的獨立性。
- 通過
6.@Primary
注解
@Primary @Bean KeyResolver appIpKeyResolver() { ... }
- 作用:在有多個相同類型的
@Bean
時,@Primary
注解表示優(yōu)先使用該Bean
。如果在其他地方有KeyResolver
的注入需求,Spring 將默認使用appIpKeyResolver()
方法返回的實例。 - 場景:當(dāng)存在多個
KeyResolver
時,如果沒有明確指定使用哪個KeyResolver
,Spring 會自動選擇標記為@Primary
的那個。這里標記了appIpKeyResolver
為默認的KeyResolver
。
總結(jié)
這段代碼定義了多個 KeyResolver
,并為不同的限流策略提供了可選擇的實現(xiàn):
userKeyResolver
:基于請求的token
限流,適用于基于用戶或身份的限流。ipKeyResolver
:基于客戶端 IP 地址限流,適用于限制每個IP的請求次數(shù)。apiKeyResolver
:基于請求路徑限流,適用于限制某個特定API的訪問。appIpKeyResolver
:基于客戶端 IP 地址和路由的 URI 組合限流,適用于更細粒度的限流需求,確保同一IP對不同API的請求可以獨立計數(shù)。
@Primary
注解確保 appIpKeyResolver
是默認的限流鍵生成器,除非特別指定,否則會優(yōu)先使用它。
這些 KeyResolver
會與 RequestRateLimiter
等限流功能配合使用,從而在 API 網(wǎng)關(guān)層實現(xiàn)精細化的限流控制。
怎么沒有指定限流的量,每秒允許訪問的量
在這段代碼中,雖然定義了不同的 KeyResolver
來生成限流的標識符(如 token
、IP
或 API路徑
),但確實沒有指定實際的限流規(guī)則(例如每秒允許的訪問量)。限流的具體控制是通過 Spring Cloud Gateway 的 RequestRateLimiter
過濾器來實現(xiàn)的,而這個過濾器是用來根據(jù)指定的規(guī)則對請求進行限流的。
要實現(xiàn)每秒允許的訪問量,你需要配置 RequestRateLimiter
過濾器,并為它指定限流規(guī)則(如每秒最大訪問量和最大突發(fā)流量)。
完整的限流配置示例
首先,你需要創(chuàng)建一個 RequestRateLimiter
過濾器,并在過濾器中配置限流策略。通常,你可以通過如下方式來配置:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.cloud.gateway.filter.ratelimit.RequestRateLimiter; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.cloud.gateway.config.GlobalFilterAutoConfiguration; @Configuration public class GatewayConfig { @Bean public RequestRateLimiter filter(KeyResolver keyResolver) { // 配置限流:每秒最多允許 10 次請求,突發(fā)流量最多為 20 次 return new RequestRateLimiter() .setRateLimiter(new MyRateLimiter(10, 20)) // 每秒 10 次請求,突發(fā)流量最多 20 次 .setKeyResolver(keyResolver); // 設(shè)置限流的 KeyResolver } // 自定義一個簡單的 RateLimiter 實現(xiàn)類 public static class MyRateLimiter implements RateLimiter { private final int replenishRate; private final int burstCapacity; public MyRateLimiter(int replenishRate, int burstCapacity) { this.replenishRate = replenishRate; this.burstCapacity = burstCapacity; } @Override public boolean isAllowed(String key) { // 此處實現(xiàn)你自己的限流邏輯,可以借助令牌桶算法、漏桶算法等 return true; // 只是示例,實際需要實現(xiàn)限流邏輯 } // 配置每秒最大請求數(shù)(每秒 10 次) public int getReplenishRate() { return replenishRate; } // 配置突發(fā)容量 public int getBurstCapacity() { return burstCapacity; } } }
如何將限流規(guī)則與KeyResolver
配合?
在這段代碼中,RequestRateLimiter
的限流規(guī)則(如每秒允許 10 次請求,突發(fā)容量為 20)會與之前定義的 KeyResolver
配合,限制特定 token
、IP 或 API 路徑的訪問頻率。
KeyResolver
選擇:可以使用你之前定義的userKeyResolver
、ipKeyResolver
或apiKeyResolver
來作為限流的依據(jù)。- 限流邏輯:通過
MyRateLimiter
類實現(xiàn)限流邏輯(如令牌桶、漏桶等算法)。每個限流的“key”(例如token
或IP
)會根據(jù)配置的規(guī)則(如每秒 10 次、突發(fā)流量 20 次)進行訪問次數(shù)的限制。
示例配置:按token
限流
假設(shè)你想基于 token
進行限流,你可以這樣配置:
@Bean public RequestRateLimiter filter(KeyResolver userKeyResolver) { return new RequestRateLimiter() .setRateLimiter(new MyRateLimiter(10, 20)) // 每秒 10 次請求,突發(fā)流量最多 20 次 .setKeyResolver(userKeyResolver); // 使用之前定義的基于 token 的 KeyResolver }
限流的配置項
replenishRate
:每秒允許的請求數(shù)。例如,10
表示每秒最多可以處理 10 個請求。burstCapacity
:突發(fā)容量,表示在短時間內(nèi)可以允許的最大請求數(shù)。例如,20
表示最多允許瞬間訪問 20 次,但通常會平滑地恢復(fù)到正常的請求速率。KeyResolver
:你已經(jīng)定義了多個KeyResolver
,它們決定了限流的粒度。你可以按用戶(token
)、IP 地址、路徑等來分別限流。
總結(jié)
這段代碼本身只是定義了限流的標識符(通過 KeyResolver
)。真正的限流控制需要通過 RequestRateLimiter
過濾器來實現(xiàn),并在其中指定限流的具體限制量(如每秒允許多少次請求)。你可以使用 replenishRate
和 burstCapacity
來配置每秒允許的訪問量及突發(fā)流量。
到此這篇關(guān)于Gateway實現(xiàn)限流的一些常見方式的文章就介紹到這了,更多相關(guān)Gateway限流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring Cloud Gateway層限流實現(xiàn)過程
- SpringCloud Gateway的熔斷限流配置實現(xiàn)方法
- SpringCloud Gateway實現(xiàn)限流功能詳解
- SpringCloud?Gateway詳細分析實現(xiàn)負載均衡與熔斷和限流
- 深入學(xué)習(xí)spring cloud gateway 限流熔斷
- Spring Cloud Gateway不同頻率限流的解決方案(每分鐘,每小時,每天)
- spring cloud gateway整合sentinel實現(xiàn)網(wǎng)關(guān)限流
- spring cloud gateway 限流的實現(xiàn)與原理
- 詳解Spring Cloud Gateway 限流操作
相關(guān)文章
Java 集合框架之List 的使用(附小游戲練習(xí))
這篇文章主要介紹Java 集合框架中List 的使用,下面文章將圍繞Java 集合框架中List 的使用展開話題,并附上一些小游戲練習(xí),需要的朋友可以參考一下2021-10-10Java傳入用戶名和密碼并自動提交表單實現(xiàn)登錄到其他系統(tǒng)的實例代碼
這篇文章主要介紹了Java傳入用戶名和密碼并自動提交表單實現(xiàn)登錄到其他系統(tǒng),非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-01-01詳解log4j-over-slf4j與slf4j-log4j12共存stack overflow異常分析
這篇文章主要介紹了詳解log4j-over-slf4j與slf4j-log4j12共存stack overflow異常分析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07淺談HashMap、HashTable的key和value是否可為null
這篇文章主要介紹了淺談HashMap、HashTable的key和value是否可為null,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09