Redis限流的幾種實現

2022-09-21 01:21:09 字數 2883 閱讀 5447

目錄

當系統處理能力有限,如何組織計畫外的請求對系統施壓。首先我們先看下一些簡單的限流策略,防止暴力攻擊。比如要對ip訪問,沒5s只能訪問10次,超過進行攔截。

如上圖,一般使用滑動視窗來統計區間時間內的訪問次數。

使用 zset 記錄 ip 訪問次數,每個 ip 通過 key 儲存下來,score 儲存當前時間戳,value 唯一用時間戳或者uuid來實現

**實現

public class redislimitertest

/*** @param ipaddress ip位址

* @param period 特定的時間內,單位秒

* @param maxcount 最大允許的次數

* @return

*/public boolean isiplimit(string程式設計客棧 ipaddress, int period, int maxcount)

public static void main(string args) }}

執行結果

訪問第1次, 結果:允許訪問

訪問第2次, 結果:允許訪問

訪問第3次, 結果:允許訪問

訪問第4次, 結果:允許訪問

訪問第5次, 結果:允許訪問

訪問第6次, 結果:限制訪問

訪問第7次, 結果:限制訪問

... ...

缺點:要記錄時間視窗所有的行為記錄,量很大,比如,限定60s內不能超過100萬次這種場景,不太適合這樣限流,因為會消耗大量的儲存空間。

示例**

public class funnellimitertest

void makespace()

if (deltaquota < 1)

this.leftquotjrrvea += deltaquota; // 漏斗剩餘空間 = 漏斗剩餘空間 + 騰出的空間

this.leakingts = nowts;

if (this.leftquota > this.capacity)

}boolean watering(int quota)

return false;}}

// 所有的漏斗

private map funnels = new hashmap<>();

/*** @param capacity 漏斗容量

* @param leakingrate 漏嘴流水速率 quota/s

*/public boolean isiplimit(string ipaddress, int capacity, float leakingrate)

return !funnel.watering(1); // 需要1個quota

}public static void main(string args) throws exception}}

執行結果

訪問第1次, 結果:允許訪問 # 第1次,容量剩餘2,執行後1

訪問第2次, 結果:允許訪問 # 第2次,容量剩餘1,執行後0

訪問第3次, 結果:允許訪問 # 第3次,由於過了2s, 漏斗流水剩餘1個空間,所以容量剩餘1,執行後0

訪問第4次, 結果:限制訪問 # 第4次,過了1s, 剩餘空間小於1, 容量剩餘0

訪問第5次, 結果:允許訪問 # 第5次,由於過了2s, 漏斗流水剩餘1個空間,所以容量剩餘1,執行後0

訪問第6次, 結果:限制訪問 # 以此類推.程式設計客棧..

訪問第7次, 結果:允許訪問

訪問第8次, 結果:限制訪問

訪問第9次, 結果:允許訪問

訪問第10次, 結果:限制訪問

我們觀察 funnel 物件的幾個字段,我們發現可以將 funnel 物件的內容按欄位儲存到乙個 hash 結構中,灌水的時候將 hash 結構的字段取出來進行邏輯運算後,再將新值回填到 hash 結構中就完成了一次行為頻度的檢測。

但是有個問題,我們無法保證整個過程的原子性。從 hash 結構中取值,然後在記憶體裡運算,再回填到 hash 結構,這三個過程無法原子化,意味著需要進行適當的加鎖控制。而一旦加鎖,就意味著會有加鎖失敗,加鎖失敗就需要選擇重試或者放棄。

如果重www.cppcns.com試的話,就會導致效能下降。如果放棄的話,就會影響使用者體驗。同時,**的複雜度也跟著公升高很多。這真是個艱難的選擇,我們該如何解決這個問題呢?redis-cell 救星來了!

redis 4.0 提供了乙個限流 redis 模組,它叫 redis-cell。該模組也使用了漏斗演算法,並提供了原子的限流指令。

該模組只有1條指令cl.throttle,它的引數和返回值都略顯複雜,接下來讓我們來看看這個指令具體該如何使用。

> cl.throttle key:*** 15 30 60 1

15 : 15 capacity 這是漏斗容量

30 60 : 30 operations / 60 seconds 這是漏水速率

1 : need 1 quota (可選引數,預設值也是1)

> cl.throttle laoqian:reply 15 30 60

1) (integer) 0 # 0 表示允許,1表示拒絕

2) (integer) 15 # 漏斗容量capacity

3) (integer) 14 # 漏斗剩餘空間left_quota

4) (integer) -1 # 如果拒絕了,需要多長時間後再試(漏斗有空間了,單位秒)

5) (integer) 2 # 多長時間後,漏斗完全空出來(left_quota==capacity,單位秒)

在執行限流指令時,如果被拒絕了,就需要丟棄或重試。cl.throttle 指令考慮的非常周到,連重試時間都幫你算好了,直接取返回結果陣列的第四個值進行 sleep 即可,如果不想阻塞執行緒,也可以非同步定時任務來重試。

《redis深度歷險 核心原理與應用實踐》_錢文品

Redis 如何實現限流功能?

限流 這種事在生活中很常見,比如逢年過節時景點的限流,還有工作日的車輛單雙號限流等,有人可能會問為什麼要限流?我既然買了車子你還不讓我上路開?還有我倒景點買了門票,景點不是能賺更多的錢嗎?為什麼要限流呢?其實限流的主要目的就是為了保證整個系統的正常執行,比如以車輛限流為了,它的作用主要有兩個,乙個是...

幾種限流演算法

思路很簡單,請求先進入到漏桶裡,漏桶以固定的速度出水,也就是處理請求,當水加的過快,則會直接溢位,也就是拒絕請求,可以看出漏桶演算法能強行限制資料的傳輸速率。但是對於很多場景來說,除了要求能夠限制資料的平均傳輸速率外,還要求允許某種程度的突發傳輸。這時候漏桶演算法可能就不合適了,令牌桶演算法更為適合...

10 Redis實現限流功能

限流 這種事情即使在生活中也很常見,比如我們銀行辦理業務,銀行不可能給去的所有人同時服務,因為櫃檯就那麼幾個。所以可能一次只給5個人辦理業務,其他的人只能在後面排隊 再比如打飯等等,也是一樣的道理。因為能提供服務的數量有限,所以必須要通過限流的方式。這裡提一下微博,微博因為哪個明星出軌了,或者哪個明...