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