首先讓我們先看一看系統架構設計中,為什麼要做「限流」。
旅遊景點通常都會有最大的接待量,不可能無限制的放遊客進入,比如故宮每天只賣八萬張票,超過八萬的遊客,無法買票進入,因為如果超過八萬人,景點的工作人員可能就忙不過來,過於擁擠的景點也會影響遊客的體驗和心情,並且還會有安全隱患;「只賣n張票,這就是一種限流的手段」。
軟體架構中的服務限流也是類似,也是當系統資源不夠的時候,已經不足以應對大量的請求,為了保證服務還能夠正常執行,那麼按照規則,「系統會把多餘的請求直接拒絕掉,以達到限流的效果」;
不知道大家注意過沒有,比如雙11,剛過12點有些顧客的網頁或app會顯示下單失敗的提示,有些就是被限流掉了。
計數法顧名思義就是來乙個,記錄乙個,比如我1分鐘只能處理1000個請求,那麼我們就可以設定乙個計數器,來乙個請求就incr+1,當1分鐘之內的數量大於等於1000之後不處理了即可,偽**如下
$redis = new redis();
$redis->connect('127.0.0.1', 6379);
$rate_limit = 1000; //限制個數
$rate_seconds = 60; //程式設計客棧限制時間
$redis_key = "redis_limit";
$count = $redis->get($redis_key);
if ($count >= $rate_limit)
$redis->incr($redis_key, 1);//ombdm請求計數
$redis->expire($redis, $rate_seconds); //設定過期時間 60s
//to do 業務邏輯處理.......
這種計數方式比較簡單快捷,但是有很大的缺點,因為請求的訪問不一定是很平穩的,如果0:59過來了1000個請求,1:01已經是下乙個視窗,又過來了1000個請求,但實際上三秒內來了2000個請求,已經超過我們的限流上限了。所以這種方法是不推薦的。
還拿上面的例子,一分鐘分6份,每份10秒;每過10秒鐘,我們的時間視窗就會往右滑動一格,每個格仔都有獨立的計數器,我們www.cppcns.com每次都計算時間視窗內的數量,可以解決計數器法中的問題,而且當滑動視窗的格仔越多,那麼限流的統計就會越精確。具體可以參考下圖,看圖比較清晰
偽**實現如下
function api_limit($scene, $period, $maxcount)
for ($i=0; $i<20; $i++)
//返回當前的毫秒時間戳
function msectime()
這段**還是略顯複雜,需要讀者花一定的時間好好啃。它的整體思路就是:每乙個行為到來時,都維護一次時間視窗。將時間視窗外的記錄全部清理掉,只保留視窗內的記錄。
因為這幾個連續的 redis 操作都是針對同乙個 key 的,使用 pipeline 可以顯著提公升redis 訪問效率。「但這種方案也有缺點,因為它要記錄時間視窗內所有的行為記錄,如果這個量很大,比如限定 60s 內操作不得超過 100w 次這樣的引數,它是不適合做這樣的限流的,因為會消耗大量的儲存空間」。
後面還有漏桶演算法和令牌桶演算法,由於各自的實現比較複雜,所以準備各自新開一篇文章單獨描述
redis鎖的實際應用
以前對redis上鎖概念一直不太清楚,現在來整理下 其實就是當你的一次操作要保證資料的原子性和一致性,你需要先加個鎖 這個加鎖的動作其實也包含了驗證是否上鎖 然後進行操作,完了即使沒有成功也要解鎖,這個redis的操作為什麼要用lua語句因為要保證原子操作 解鎖的原則 在乙個使用者下 如下示例 lo...
redis10 Setbit 的實際應用
setbit 的實際應用 場景 1億個使用者,每個使用者 登陸 做任意操作 記為 今天活躍,否則記為不活躍 每週評出 有獎活躍使用者 連續7天活動,每月評,等等。思路 userid dt active 12013 07 2711 2013 0726 1如果是放在表中,1 表急劇增大,2 要用grou...
Redis 簡單限流
首先我們來看乙個常見 的簡單的限流策略。系統要限定使用者的某個行為在指定的時間裡只能允許發生 n 次,如何使用 redis 的資料結構來實現這個限流的功能?這個限流需求中存在乙個滑動時間視窗,想想 zset 資料結構的 score 值,是不是可以通過 score 來圈出這個時間視窗來。而且我們只需要...