使用redis實(shí)現(xiàn)令牌桶算法和漏桶算法方式
流量控制算法,用于限制請(qǐng)求的速率。
可以應(yīng)對(duì)緩存雪崩
令牌桶算法
核心思想是:
- 有一個(gè)固定容量的桶,里面存放著令牌(token)。
- 每過(guò)一定時(shí)間(如 1 秒),桶中會(huì)自動(dòng)增加一定數(shù)量的令牌,直到達(dá)到桶的容量上限。
- 當(dāng)有請(qǐng)求到來(lái)時(shí),會(huì)從桶中取出一個(gè)令牌。如果桶中有令牌,則請(qǐng)求被允許通過(guò);如果桶中沒(méi)有令牌,則拒絕該請(qǐng)求。
基于Redis的實(shí)現(xiàn)
- 初始化
使用 Redis 的 Sorted Set(有序集合)來(lái)存儲(chǔ)令牌。
初始化時(shí),向有序集合中添加一定數(shù)量的令牌,每個(gè)令牌的時(shí)間戳作為分?jǐn)?shù)(score)。
ZADD user:rate_limit 1633072800 1633072800
或者,可以預(yù)先為每個(gè)用戶生成大量令牌,時(shí)間戳作為分?jǐn)?shù),均勻分布在一定時(shí)間段內(nèi)。
- 令牌生成
定期向桶中添加令牌??梢允褂?Redis 的 ZADD 命令來(lái)添加新的令牌,每個(gè)令牌的時(shí)間戳作為分?jǐn)?shù)。
ZADD user:rate_limit NX 1633072801 1633072801
這里的 NX 表示如果鍵不存在,則不執(zhí)行操作(可選)。
- 檢查和消耗令牌
當(dāng)請(qǐng)求到來(lái)時(shí),檢查桶中是否有可用的令牌??梢允褂?ZCOUNT 命令統(tǒng)計(jì)當(dāng)前時(shí)間戳之前的有效令牌數(shù)量。
ZCOUNT user:rate_limit -inf +inf
如果有可用令牌,則使用 ZPOPMIN 命令取出一個(gè)令牌,并允許請(qǐng)求通過(guò)。
ZPOPMIN user:rate_limit
如果沒(méi)有可用令牌,則拒絕請(qǐng)求。
- 清理過(guò)期令牌
定期清理過(guò)期的令牌,避免數(shù)據(jù)堆積。例如,可以使用 ZREMRANGEBYSCORE 命令刪除時(shí)間戳小于當(dāng)前時(shí)間的令牌。
ZREMRANGEBYSCORE user:rate_limit -inf $(current_time)
漏桶算法
漏桶算法類似于一個(gè)漏斗,它的核心思想是:
- 有一個(gè)固定容量的漏桶,里面存儲(chǔ)著請(qǐng)求。
- 漏桶以恒定的速率將請(qǐng)求漏出(處理)。
- 當(dāng)請(qǐng)求到達(dá)時(shí),如果漏桶未滿,則將請(qǐng)求放入漏桶;如果漏桶已滿,則拒絕該請(qǐng)求。
基于 Redis 的實(shí)現(xiàn)
- 初始化
使用 Redis 的 String 類型鍵來(lái)存儲(chǔ)漏桶的狀態(tài)。例如,鍵 user:leaky_bucket 可以存儲(chǔ)最后一個(gè)請(qǐng)求的時(shí)間戳。
SET user:leaky_bucket 1633072800
- 請(qǐng)求處理
當(dāng)請(qǐng)求到來(lái)時(shí),首先檢查漏桶是否已滿。這可以通過(guò)比較當(dāng)前時(shí)間與最后一個(gè)請(qǐng)求的時(shí)間戳來(lái)實(shí)現(xiàn)。
如果當(dāng)前時(shí)間與最后一個(gè)請(qǐng)求的時(shí)間差小于漏桶的處理時(shí)間間隔(例如 1 秒),則認(rèn)為漏桶已滿,拒絕請(qǐng)求。
否則,更新漏桶的時(shí)間戳,并允許請(qǐng)求通過(guò)。
SET user:leaky_bucket $(current_time)
- 處理速率
通過(guò)設(shè)置漏桶的處理速率(例如每秒處理一個(gè)請(qǐng)求)來(lái)控制流量??梢酝ㄟ^(guò) Redis 的 SET 命令中的參數(shù) NX 和 XX 來(lái)實(shí)現(xiàn)線程安全。
總結(jié)
令牌桶算法允許突發(fā)流量,適合作為速率限制器。
漏桶算法適用于平滑流量的情況,適用于需要恒定處理速率的場(chǎng)景。
在 Redis 中,可以通過(guò)組合使用有序集合、字符串等數(shù)據(jù)結(jié)構(gòu)以及原子操作(如 ZADD、ZPOPMIN 和 SET)來(lái)高效地實(shí)現(xiàn)這兩類限流算法。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Redis定時(shí)任務(wù)原理的實(shí)現(xiàn)
本文主要是基于?redis?6.2?源碼進(jìn)行分析定時(shí)事件的數(shù)據(jù)結(jié)構(gòu)和常見(jiàn)操作,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Redis高階使用消息隊(duì)列分布式鎖排行榜等(高階用法)
在大多數(shù)傳統(tǒng)的web系統(tǒng)中,使用Redis一般都是作為緩存使用,在大數(shù)據(jù)查詢時(shí)作為緩解性能的一種解決方案,這篇文章主要介紹了Redis高階使用消息隊(duì)列分布式鎖排行榜等,需要的朋友可以參考下2024-03-03
基于Redis自動(dòng)過(guò)期的流處理暫停機(jī)制
基于Redis自動(dòng)過(guò)期的流處理暫停機(jī)制是一種高效、可靠且易于實(shí)現(xiàn)的解決方案,防止延時(shí)過(guò)大的數(shù)據(jù)影響實(shí)時(shí)處理自動(dòng)恢復(fù)處理,以避免積壓的數(shù)據(jù)影響實(shí)時(shí)性,下面就來(lái)詳細(xì)的介紹一下2025-08-08
關(guān)于redigo中PubSub的一點(diǎn)小坑分析
這篇文章主要給大家介紹了關(guān)于redigo中PubSub的一點(diǎn)小坑的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01

