您好,登錄后才能下訂單哦!
小編給大家分享一下redis中限流的應用示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
首先讓我們先看一看系統架構設計中,為什么要做“限流”。
旅游景點通常都會有最大的接待量,不可能無限制的放游客進入,比如故宮每天只賣八萬張票,超過八萬的游客,無法買票進入,因為如果超過八萬人,景點的工作人員可能就忙不過來,過于擁擠的景點也會影響游客的體驗和心情,并且還會有安全隱患;「只賣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){ //判斷60秒內請求個數是否已經達到上限 //直接返回,不處理請求 return } $redis->incr($redis_key, 1);//請求計數 $redis->expire($redis, $rate_seconds); //設置過期時間 60s //to do 業務邏輯處理.......
這種計數方式比較簡單快捷,但是有很大的缺點,因為請求的訪問不一定是很平穩的,如果0:59過來了1000個請求,1:01已經是下一個窗口,又過來了1000個請求,但實際上三秒內來了2000個請求,已經超過我們的限流上限了。所以這種方法是不推薦的。
還拿上面的例子,一分鐘分6份,每份10秒;每過10秒鐘,我們的時間窗口就會往右滑動一格,每個格子都有獨立的計數器,我們每次都計算時間窗口內的數量,可以解決計數器法中的問題,而且當滑動窗口的格子越多,那么限流的統計就會越精確。具體可以參考下圖,看圖比較清晰
偽代碼實現如下
function api_limit($scene, $period, $maxCount){ $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $key = sprintf('hist:%s', $scene); //限流場景唯一標識 $now = msectime(); // 毫秒時間戳,這樣更精確 $pipe=$redis->multi(Redis::PIPELINE); //使用管道提升性能 $pipe->zadd($key, $now, $now); //value 和 score 都使用毫秒時間戳 $pipe->zremrangebyscore($key, 0, $now - $period); //移除時間窗口之前的行為記錄,剩下的都是時間窗口內的 $pipe->zcard($key); //獲取窗口內的行為數量 $pipe->expire($key, $period/1000 + 1); //多加一秒過期時間 $replies = $pipe->exec(); return $replies[2] <= $maxCount; //$replies[2]為zcard返回的個數 如果zcard結果大于maxCount,則不處理結果 } for ($i=0; $i<20; $i++){ //測試限流是否實現代碼 var_dump(isActionAllowed("uniq_scene", 60*1000, 5)); //執行可以發現只有前5次是通過的 } //返回當前的毫秒時間戳 function msectime() { list($msec, $sec) = explode(' ', microtime()); $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000); return $msectime; }
這段代碼還是略顯復雜,需要讀者花一定的時間好好啃。它的整體思路就是:每一個行為到來時,都維護一次時間窗口。將時間窗口外的記錄全部清理掉,只保留窗口內的記錄。
因為這幾個連續的 Redis 操作都是針對同一個 key 的,使用 pipeline 可以顯著提升Redis 存取效率。「但這種方案也有缺點,因為它要記錄時間窗口內所有的行為記錄,如果這個量很大,比如限定 60s 內操作不得超過 100w 次這樣的參數,它是不適合做這樣的限流的,因為會消耗大量的存儲空間
」。
后面還有漏桶算法和令牌桶算法,由于各自的實現比較復雜,所以準備各自新開一篇文章單獨描述
以上是“redis中限流的應用示例”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。