
Redisson 分布式限流實戰3 步給 API 網關裝上流量閘門【免費下載鏈接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..項目地址: https://gitcode.com/GitHub_Trending/re/redisson大促零點單機限流器明明攔住了 3000 QPS后端還是被打穿——流量攤到 8 臺網關每臺只看到自己那一份。把配額挪進 Redis用 Redisson 的分布式限流讓全集群共用一個桶本文給出從建實例到網關過濾器的完整落地路徑。單機限流器為什么在集群下失效3 個盲區定位先排除一個常見誤區限流沒生效往往不是限流器壞了而是限流范圍錯了。盲區一配額被實例數放大。Guava 的 RateLimiter、JUC 的信號量都是進程內對象。8 臺網關每臺放 100 QPS集群實際放行 800 QPS是配置的 8 倍。后端看到的是 800你以為配的是 100對不上賬。盲區二配額隨擴縮容漂移。網關按 HPA 自動擴到 16 臺單機配額不變集群上限直接翻倍。想臨時壓回去只能改每臺實例的配置——8 次發布或者干脆放棄。盲區三節點故障導致配額漏氣。一臺網關掛了它的配額跟著消失集群總配額被動收縮。反過來擴容瞬間新節點還沒預熱配額又短暫偏高。運維側看不到一個穩定的集群級配額數字。根因只有一個配額狀態散落在各進程內存里沒有共享存儲。解法也只有一個——把桶挪到所有節點都能訪問的地方Redis 是最順手的候選。Redisson 限流器原理令牌桶 Lua 腳本一次原子扣減令牌桶一個桶按固定速率注水比如每秒 100 枚桶容量 速率。請求來就拿一枚桶空了要么等、要么拒。比喻成水龍頭勻速滴水進杯子杯子滿了新水溢出——突發流量能短時吸收桶里的存量持續超載會被限住注水速率封頂。為什么狀態放 Redis所有網關節點從同一個 key 取令牌配額天然共享擴容縮容不影響總量。為什么必須用 Lua 腳本一次取令牌包含 4 步——讀當前剩余、判斷夠不夠、扣減、把已用令牌連同時間戳記進 ZSet。如果拆成 4 條獨立 Redis 命令兩個節點并發時都會讀到剩 1 枚都判定通過都扣成 0最終超發。Redisson 把這 4 步打包成一段 Lua 腳本通過EVAL一次性發給 Redis。Redis 單線程執行腳本腳本內不可能被別的命令插隊讀-判-扣-記就是一個原子事務。這就是分布式環境下的扣減一致性來源。令牌怎么補回來已消耗令牌帶時間戳存在 ZSet 里score 是消耗時刻。每次取令牌前腳本先用zrangebyscore撈出超過 rateInterval 沒被釋放的舊令牌累加回當前值再從 ZSet 里刪掉。不需要后臺線程定時補補桶邏輯嵌在每次取令牌的路徑里。這套腳本的 Java 封裝就是RedissonRateLimiterredisson/src/main/java/org/redisson/RedissonRateLimiter.java對使用者只暴露幾個方法。3 步配置 RRateLimiter建實例、設速率、取許可第 1 步建實例。限流器名字就是 Redis key 前綴命名帶業務語義方便排查。Config config new Config(); config.useSingleServer().setAddress(redis://127.0.0.1:6379); RedissonClient client Redisson.create(config); RRateLimiter limiter client.getRateLimiter(gw:order:create);第 2 步設速率。trySetRate只在限流器還沒初始化時生效已存在就跳過不會覆蓋線上配置。limiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.SECONDS); // rate100窗口內放行上限 // rateInterval1 SECONDS窗口長度 1 秒第 3 步取許可。tryAcquire()立即返回不等待。if (limiter.tryAcquire()) { // 放行執行真實業務 } else { // 拒絕返回 429 或直接丟棄 }三個參數各管一件事rate定窗口內總量rateInterval unit定窗口時長RateType定配額歸屬范圍。跑通這三步限流器就活了。網關過濾器怎么接Spring Cloud Gateway 放行與 429 分支Spring Cloud Gateway 是響應式的過濾器返回MonoVoid。限流判定塞在filter方法里兩條分支拿到許可 → 走chain.filter(exchange)繼續后續過濾器鏈沒拿到 → 直接置 429 并 complete不往后走。public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path exchange.getRequest().getPath().value(); RRateLimiter limiter client.getRateLimiter(gw: path); limiter.trySetRate(RateType.OVERALL, 100, 1, RateIntervalUnit.SECONDS); if (limiter.tryAcquire()) { return chain.filter(exchange); } exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS); return exchange.getResponse().setComplete(); }key 怎么拼全局配額用路徑要按用戶限就把 userId 拼進來gw: userId : path。一個業務維度一個 key互不干擾。trySetRate每請求都調沒關系它底層是HSETNX已初始化時直接 no-op不會把線上速率改掉。所以過濾器里每請求先 trySetRate 再 tryAcquire是安全寫法首次部署自動完成初始化后續請求零副作用。一個要留意的點tryAcquire()是同步阻塞調用。在 WebFlux 的 event loop 里調它會占住事件循環線程。生產環境建議改用tryAcquireAsync()拿到RFuture再包一層Mono.fromFuture把等待交還 reactor 調度別阻塞 event loop。RateLimiter 配置選型OVERALL 與 PER_CLIENT 對比 調速避坑兩種 RateType 怎么選維度OVERALLPER_CLIENT配額歸屬所有客戶端共享一個桶每個 Redisson 客戶端實例獨立一個桶典型場景保護下游接口集群總吞吐封頂防單租戶刷爆允許整體流量高擴容影響配額固定與節點數無關客戶端越多總吞吐線性放大Redis 鍵單一value鍵帶 clientId 后綴的獨立value鍵適合做網關全局 QPS 閘用戶級 / 租戶級 API 配額判斷標準一句話你要限制的是總盤子還是每個玩家的分額。總盤子選 OVERALL分額選 PER_CLIENT。兩者也可以疊加——外層 OVERALL 保下游內層 PER_CLIENT 防單點濫用。三個進階提示動態調速setRate(...)會強制覆蓋配置同時DEL掉當前令牌狀態value 和 permits 鍵都清。等價于發一個新滿桶。高流量時調用舊請求已經扣掉的額度瞬間歸零可能引發一次放行尖峰。只調速率、不想清桶目前 API 層面沒有保留狀態改速率的路徑要么接受清桶副作用要么用trySetRate走未初始化才生效的語義。批量取許可acquire(10)一次扣 10 枚。適合一個上游請求背后扇出 10 次下游調用的場景按真實消耗配額比按請求數限更貼近后端壓力。異步取許可tryAcquireAsync()返回RFutureBoolean不阻塞當前線程。WebFlux 環境用它套Mono.fromFuture后.subscribe處理兩條分支。容易踩的坑tryAcquire(permits)的 permits 不能大于 rate。Lua 腳本里有assert(tonumber(rate) tonumber(ARGV[1]))超了直接拋錯。setRate 會清桶線上動態調速前想清楚清空瞬間的放行尖峰能否接受。限流器 key 建議設過期。trySetRate支持keepAliveTime參數或事后對 key 調expire。不設過期的話Redis 里會積累一堆歷史業務的空桶長期占用內存。PER_CLIENT 的客戶端是 Redisson 實例 ID不是 HTTP 用戶 ID。同一業務里所有網關節點共享同一個 Redisson 實例 ID 的話它們會被視為同一個客戶端。要按業務用戶維度分桶得在 key 名里手動拼 userId。收尾分布式限流的核心不是算法而是配額狀態放哪里、誰保證扣減原子。Redisson 把這兩件事都壓在 Redis Lua 上業務側只剩三行代碼。落地時先確認 OVERALL 還是 PER_CLIENT再決定 key 粒度和速率窗口剩下的交給RRateLimiter。官方文檔docs/overview.md【免費下載鏈接】redissonRedisson: Valkey Redis Java Client and Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..項目地址: https://gitcode.com/GitHub_Trending/re/redisson創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考