Redis限流算法解析與實(shí)戰(zhàn)教程
一、經(jīng)典限流算法的深度對比與選型建議
| 算法 | 核心思想 | 適用場景 | 推薦使用場景 |
|---|---|---|---|
| 固定窗口 | 時間分段統(tǒng)計(jì),每段獨(dú)立計(jì)數(shù) | 對性能要求極高、允許短時突增的簡單限流 | 日志上報、非核心接口限流 |
| 滑動窗口 | 連續(xù)時間區(qū)間內(nèi)動態(tài)統(tǒng)計(jì)請求 | 需要平滑流量控制、避免“窗口邊界突增”問題 | 用戶行為監(jiān)控、支付/下單類高敏感接口 |
| 令牌桶 | 以恒定速率生成令牌,請求消耗令牌 | 支持突發(fā)流量、靈活控制峰值 | API 網(wǎng)關(guān)、微服務(wù)入口、消息推送 |
| 漏桶 | 請求進(jìn)入后按固定速率輸出,超出則排隊(duì)或丟棄 | 下游系統(tǒng)處理能力有限,需絕對平滑 | 數(shù)據(jù)庫寫入、文件上傳、第三方調(diào)用 |
關(guān)鍵差異總結(jié)
| 維度 | 固定窗口 | 滑動窗口 | 令牌桶 | 漏桶 |
|---|---|---|---|---|
| 是否允許突發(fā) | ? 否 | ? 是(部分) | ? 完全支持 | ?? 可容忍但延遲增加 |
| 流量平滑性 | 差(邊界突增) | 極好 | 中等(有突發(fā)) | 最好 |
| 內(nèi)存占用 | 極低(單個 key) | 高(Zset 存 timestamp) | 中等(Hash) | 高(List 隊(duì)列長度不確定) |
| 實(shí)現(xiàn)復(fù)雜度 | 低 | 中 | 高(需 Lua 腳本) | 中(需定時任務(wù)/異步消費(fèi)) |
| 原子性要求 | 一般 | 高(范圍查詢+更新) | 極高(讀-算-寫閉環(huán)) | 高(隊(duì)列操作) |
選型建議:
- 若追求極致性能且可接受“59秒+1秒”突發(fā) → 用 固定窗口;
- 若業(yè)務(wù)對流量平滑性要求嚴(yán)格,如防止刷 單、搶購 → 用 滑動窗口 或 令牌桶;
- 若希望在突發(fā)情況下仍能放行一定數(shù)量請求,同時長期速率受控 → 優(yōu)先選擇 令牌桶;
- 若下游是數(shù)據(jù)庫/文件系統(tǒng)等慢速資源,必須保證輸入速率穩(wěn)定 → 選 漏桶。
二、RedisCell 模塊詳解:官方推薦的“開箱即用”限流利器
為什么推薦使用 RedisCell?
| 特性 | 說明 |
|---|---|
| ? 原生支持 | 4.0+ 版本內(nèi)置模塊,無需額外依賴 |
| ? 高性能 | 使用 C 編寫,減少網(wǎng)絡(luò)往返和解釋成本 |
| ? 原子性保障 | CL.THROTTLE 是原子命令,無需手動封裝 Lua |
| ? 突發(fā)容忍 | 支持 max_burst,允許短時間內(nèi)批量通過 |
| ? 返回信息豐富 | 返回 [status, remaining_tokens, delay],便于前端/中間件決策 |
命令詳解(結(jié)合實(shí)例)
# 示例:用戶 user123 每分鐘最多 15 次請求,突發(fā)容量 15,正常速率 1次/秒 CL.THROTTLE user123 15 60 1
返回值解析:
[1, 14, 0] # 允許,剩余令牌 14,無需等待 [0, 15, 2] # 拒絕,剩余令牌 15,需等待 2 秒后再試
1: 允許請求0: 拒絕請求remaining_tokens: 當(dāng)前可用令牌數(shù)(可用于降級提示)delay: 如果拒絕,建議等待多少秒再嘗試(單位:秒)
注意:CL.THROTTLE 的 period 是以秒為單位,但內(nèi)部是以毫秒精度計(jì)算的,因此即使周期較短(如 1 秒),也能做到精確控制。
如何啟用 RedisCell?
確保 Redis 版本 ≥ 4.0;
修改 redis.conf 啟用模塊:
loadmodule /path/to/redis-cell.so
通常安裝 Redis 時會自帶該模塊(路徑可能為 /usr/lib/redis/modules/redis-cell.so);
啟動后可通過 MODULE LIST 查看是否加載成功。
使用建議:
- 不要濫用
max_burst:雖然它提升了用戶體驗(yàn),但可能導(dǎo)致下游瞬間壓力激增。 - 配合熔斷機(jī)制使用:當(dāng)
delay大于閾值(如 >3 秒),應(yīng)觸發(fā)熔斷或降級策略。 - 日志埋點(diǎn):記錄被限流的請求,用于分析異常流量來源。
三、工程優(yōu)化與避坑指南(進(jìn)階篇)
1.原子性:必須用 Lua 腳本!
? 錯誤做法(易出并發(fā)問題):
GET counter IF count > limit: RETURN reject INCR counter
→ 存在“競態(tài)條件”,多個請求可能同時讀到 count=14,導(dǎo)致超限。
? 正確做法(使用 Lua 腳本):
-- 令牌桶邏輯(簡化版)
local key = KEYS[1]
local capacity = tonumber(ARGV[1])
local rate = tonumber(ARGV[2]) -- 令牌生成速度(個/秒)
local now = tonumber(ARGV[3])
local bucket = redis.call('HMGET', key, 'last_time', 'tokens')
local last_time = tonumber(bucket[1]) or 0
local tokens = tonumber(bucket[2]) or capacity
local delta = math.max(0, now - last_time)
local add_tokens = delta * rate
tokens = math.min(capacity, tokens + add_tokens)
if tokens >= 1 then
tokens = tokens - 1
redis.call('HMSET', key, 'last_time', now, 'tokens', tokens)
return 1
else
return 0
end
使用方式:
EVAL "lua_script" 1 user123 10 1 1700000000
優(yōu)勢:所有操作在一個事務(wù)中完成,無中間狀態(tài)暴露。
2.內(nèi)存治理:防止“數(shù)據(jù)堆積”
常見陷阱:
- 滑動窗口使用 Zset:若不清理過期數(shù)據(jù),會導(dǎo)致內(nèi)存持續(xù)增長;
- 令牌桶使用 Hash:若用戶過多,且未設(shè)置合理過期時間,也會造成內(nèi)存泄漏;
- 漏桶使用 List:如果消費(fèi)者處理慢,隊(duì)列無限增長。
解決方案:
| 結(jié)構(gòu) | 清理策略 |
|---|---|
| 滑動窗口(Zset) | 定期執(zhí)行 ZREMRANGEBYSCORE key -inf <now - window_size; 或利用 EXPIRE 設(shè)置自動過期(注意:只對 key 有效,不能清除舊元素) |
| 令牌桶(Hash) | 給每個 key 設(shè)置合理的過期時間(如 1 小時),或使用 LRU 策略淘汰不活躍用戶 |
| 漏桶(List) | 消費(fèi)端通過定時任務(wù)定期清理空桶或超時桶;也可設(shè)置最大長度,超過則丟棄新請求 |
最佳實(shí)踐:
# 滑動窗口:每分鐘清理一次過期時間戳
SCHEDULED JOB:
ZREMRANGEBYSCORE window_key -inf < (now - 60)
強(qiáng)烈建議:將限流數(shù)據(jù)的 TTL 控制在合理范圍內(nèi)(如 1~2 小時),避免內(nèi)存爆炸。
3.分布式環(huán)境下的限流一致性
問題:多個服務(wù)節(jié)點(diǎn)共享同一份 Redis,但各自緩存本地計(jì)數(shù) → 不一致!
? 解決方案:
| 方案 | 說明 |
|---|---|
| ? 所有計(jì)數(shù)統(tǒng)一由 Redis 統(tǒng)一維護(hù) | 所有請求都走 Redis,避免本地緩存干擾 |
| ? 使用 Redis Cluster 保證數(shù)據(jù)分布一致性 | 確保 key 落在同一個 shard,避免跨節(jié)點(diǎn)同步延遲 |
| ? 限流 key 命名規(guī)范統(tǒng)一 | 如 rate_limit:user:123, rate_limit:api:/order/create |
切忌:在本地內(nèi)存做限流計(jì)數(shù),除非配合 Redis 作為主源同步。
4.限流策略的可觀測性 & 監(jiān)控
限流不是“黑盒”,必須具備可觀測性:
必須采集的關(guān)鍵指標(biāo):
| 指標(biāo) | 用途 |
|---|---|
| request_count_per_second | 整體流量趨勢 |
| throttle_rate | 被限流比例(= 被拒請求數(shù) / 總請求數(shù)) |
| average_delay | 拒絕后平均等待時間 |
| burst_hit_ratio | 突發(fā)請求占比 |
| top_blocked_keys | 哪些接口/用戶最常被限流 |
推薦監(jiān)控方式:
- 將限流返回結(jié)果寫入日志(如 OpenTelemetry Trace);
- 使用 Prometheus + Grafana 可視化限流率;
- 在網(wǎng)關(guān)層集成限流統(tǒng)計(jì)器,發(fā)送至 Metrics Server。
四、實(shí)戰(zhàn)場景推薦組合
| 場景 | 推薦算法 | 實(shí)現(xiàn)方式 |
|---|---|---|
| 微服務(wù)入口限流(如網(wǎng)關(guān)) | 令牌桶 | RedisCell + CL.THROTTLE |
| 搶購活動防刷 | 滑動窗口 | ZREVRANGEBYSCORE + Lua 腳本 |
| 第三方服務(wù)調(diào)用保護(hù) | 漏桶 | List + BRPOP + 定時任務(wù)消費(fèi) |
| 用戶行為分析(防爬蟲) | 固定窗口 | SETNX + EXPIRE |
| 高頻日志上報 | 令牌桶 | 自定義腳本,支持突發(fā)容忍 |
五、總結(jié):構(gòu)建健壯限流系統(tǒng)的黃金法則
| 法則 | 說明 |
|---|---|
| ?? 原子性第一 | 任何涉及“查-判-改”的操作,必須用 Lua 腳本 |
| ?? 內(nèi)存要可控 | 定期清理過期數(shù)據(jù),合理設(shè)置 TTL |
| ?? 一致性優(yōu)先 | 分布式下統(tǒng)一依賴 Redis,禁止本地緩存 |
| ?? 可觀測性強(qiáng) | 限流行為必須可監(jiān)控、可告警、可回溯 |
| ??? 善用官方工具 | 優(yōu)先使用 RedisCell,降低出錯概率 |
| ?? 按需選型 | 不是越復(fù)雜越好,根據(jù)業(yè)務(wù)特性選擇最適合的算法 |
附錄:常用限流命令速查表
| 功能 | 命令 |
|---|---|
| 固定窗口計(jì)數(shù) | SET key value NX EX seconds |
| 滑動窗口統(tǒng)計(jì) | ZREVRANGEBYSCORE key -inf <timestamp |
| 令牌桶判斷 | EVAL "lua_script" |
| RedisCell 限流 | CL.THROTTLE key max_burst count period |
| 刪除過期數(shù)據(jù) | ZREMRANGEBYSCORE key -inf <now - window |
最終建議:
在生產(chǎn)環(huán)境中,優(yōu)先使用 RedisCell,除非有特殊定制需求;
對于復(fù)雜場景,基于 Lua 腳本實(shí)現(xiàn)令牌桶/滑動窗口,并加入監(jiān)控與自動化清理機(jī)制;
所有策略都應(yīng)可配置、可觀察、可降級。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis 事務(wù)知識點(diǎn)相關(guān)總結(jié)
這篇文章主要介紹了Redis 事務(wù)相關(guān)總結(jié),幫助大家更好的理解和學(xué)習(xí)使用Redis,感興趣的朋友可以了解下2021-03-03
Redis結(jié)合 Docker 搭建集群并整合SpringBoot的詳細(xì)過程
這篇文章主要介紹了Redis結(jié)合Docker搭建集群并整合SpringBoot的詳細(xì)過程,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-06-06
Redis主從架構(gòu)和高可用性實(shí)現(xiàn)過程
本文詳細(xì)介紹了使用Redis主從架構(gòu)和Linux虛擬服務(wù)器(LVS)實(shí)現(xiàn)高可用性的方法,并回顧了最近完成的Redis集群遷移部署過程,主從架構(gòu)通過復(fù)制數(shù)據(jù)來提高性能和數(shù)據(jù)冗余,而LVS用于實(shí)現(xiàn)負(fù)載均衡和故障切換,感興趣的朋友跟隨小編一起看看吧2024-09-09
Redis實(shí)現(xiàn)IP限流的2種方式舉例詳解
通俗的說限流就是限制一段時間內(nèi)用戶訪問資源的次數(shù),減輕服務(wù)器壓力,這篇文章主要給大家介紹了關(guān)于Redis實(shí)現(xiàn)IP限流的2種方式,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08

