文件名稱 | 版本號 | 作者 | 版本 | |
---|---|---|---|---|
成功:SpringCloud Gateway限流_RateLimiter_RedisRateLimiter | v0.0.1 | 學生宮布 | 8416837 | SpringBoot 2.2.6 SpringCloud Gateway 2.2.2 |
配置
yaml
- 注意看註釋
- 反面教材
[錯誤的配置],id不對,應該配置在id是微服務的配置大項下面
。這樣不會起效,按下文修正後,起效了。
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route # 過濾器名稱,不必在意
uri: https://example.org # 上游,有的地方叫下游-_-||
predicates:
- Path=/xxx/**
filters:
- StripPrefix=1
- name: RequestRateLimiter # 官方給的名稱,對應Java類,有需要再改
args:
redis-rate-limiter.replenishRate: 10 # 每秒補充10個
redis-rate-limiter.burstCapacity: 20 # 突發20個
redis-rate-limiter.requestedTokens: 1 # 每次請求消耗1個
# rate-limiter: "#{@redisRateLimiter}" # 限流器
key-resolver: "#{@userAPIKeyResolver}" # 限流key|字段解析器
-
正確的
:
...
# 系統模塊
- id: abc-system
uri: lb://abc-system
predicates:
- Path=/system/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
key-resolver: "#{@userAPIKeyResolver}"
# key-resolver: "#{@ipKeyResolver}"
依賴
- xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<!-- 版本號可以繼承父項目或自己寫 RELEASE表示最新版-->
<version>RELEASE</version>
</dependency>
Java
標識
- user結合API 限流成功
前提是QueryParams攜帶user參數(一般不會這麼做),否則報空指針錯誤
// 根據什麼字段限流,甚至是組合字段
@Bean
public KeyResolver userAPIKeyResolver() {
// rt,根據字段限流,下文根據Query參數值作爲限流標識,請酌情更改爲自己的方式
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
// todo 獲取消費者消費的API的id,與user組合
}
- ip 限流成功 響應碼429 服務降級 拒絕服務
/**
* 功能描述: 基於ip限流
*
* @param: []
* @return: org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
* @qq: 8416837
* @author: cc
* @date: 2020/6/10 11:56
*/
@Bean("ipKeyResolver")
public KeyResolver ipKeyResolver() {
System.out.println("限流解析器");
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
- 限流器 Redis限流器(可以省去,可以使用上文的yaml配置代替)
@Bean
RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(9, 16); // yaml配置文件已經有了,那麼這裏就省了。9,16對應replenishRate、burstCapacity
}
- 其它key限流
原理一樣,使用設置的key存儲redis令牌,調用的時候消耗令牌,單位時間內的令牌耗盡則拒絕服務,另外還有個突發流量功能,當突發的時候,令牌會增加,見配置
burstCapacity
。
執行
將配置拷貝到項目或配置中心、代碼拷貝到項目,並修改Java代碼:KeyResolver
啓動項目,使用壓測工具壓測或者手動發送Http請求,進行測試。
故障
不起效
- 多線程調用接口,每秒發送10個請求,仍然成功了:
分析原因
- 限流過濾器沒有攔截到請求
- 可能與路由配置有關,回顧路由配置:
...
# 限流
- id: requestratelimiter_route # 過濾器名稱,不必在意
uri: lb://abc-system # 上游,有的地方叫下游-_-||
predicates:
- Path=/system/**
filters:
- name: RequestRateLimiter # 官方給的名稱,對應Java類,有需要再改
args:
...
- requestratelimiter_route名稱是按照官方的,應該沒問題;
- uri表示路由的目標是它,也沒問題吧;
- predicates斷言是Path類型,是個正則,當正則匹配訪問路徑時,即將請求指向目標,好像也沒問題;
- RequestRateLimiter ,沒有找到這個類,但是好像找到了相關Bean:
解決方案
1)增加public,KeyResolver userAPIKeyResolver() {
改爲public KeyResolver userAPIKeyResolver() {
2)限流配置改正確
# 系統模塊
- id: abc-system
uri: lb://abc-system
predicates:
- Path=/system/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
key-resolver: "#{@userAPIKeyResolver}"
限流成功
根據配置進行限流:
調用接口,限流開始工作,日誌
上圖使用多線程模擬10個併發,只有2個請求成功,剩餘請求返回429(Too Many Request
),說明限流已經ok了,更多細節可以繼續優化。