Redis實現簡單限流


使用Redis進行簡單的限流

限流

限流的目的是當系統的處理能力有限時,阻止計划外的請求繼續對系統施壓,通過對並發/請求進行限速或者一個時間窗口內的請求進行限速來保護系統,達到限制速率則可以拒絕服務。還有一個應用目的是用於控制用戶的行為,比如在論壇中的發帖,回復等。一般是要控制某行為在規定時間內允許的次數。

redis實現的限流

常見的限流算法有:計數器,令牌桶和漏桶算法

計數器算法是最簡單粗暴的算法,系統限制在指定時間內只允許發生N次事件。使用時間窗口

使用到的redis數據結構

redis中有個很特色的數據結構:zset(有序集合)
有點兒類似於java的SortSet和HashMap的結合體,一方面是個set,保證內部的value的唯一性,另一方面可以給每個value賦予一個score,表示這個value的排序權重。
命令為:ZADD KEY SCORE VALUE
redis限流

通過zset的score值,圈出一個時間窗口,將時間窗口之外的數據移除,時間窗口內的數據就是需要的數據。
因為value的值需要唯一,value中存放納秒級的時間戳,存放毫秒級的可能會出現重復在高並發下。

每個用戶使用一個zset記錄其操作記錄,因為zset為空時會自動從內存中移除,所以低活躍用戶不會有自己的zset。降低了內存消耗。

具體實現
   public void userReply () throws IOException {
        String actionKey = "test";
        String userId = "cjl";
        for(int i=0;i<20;i++) {
            System.out.println(isActionAllowed(userId, actionKey, 30, 5));
        }
    }
	
	/**
     * 查看用戶操作是否正常
     * @param userId 用戶Id
     * @param actionKey 行為名
     * @param period 時間范圍
     * @param maxCount 最大次數
     * @return 是否正常
     * @throws IOException
     */
    public boolean isActionAllowed(String userId, String actionKey, int period, int maxCount) throws IOException {
        String key = String.format("hist:%s:%s", userId, actionKey);
        long nowTs = System.nanoTime();
        Pipeline pipe = jedis.pipelined();
        pipe.multi();
        // 記錄行為
        pipe.zadd(key, nowTs, "" + nowTs);
        // 移除超時行為
        pipe.zremrangeByScore(key, 0, nowTs - period * 1000*1000);
        // 查找時間窗口中的行為數量
        Response<Long> count = pipe.zcard(key);
        // 重制所有行為的過期時間
        pipe.expire(key, period + 1);
        pipe.exec();
        pipe.close();
        return count.get() <= maxCount;
    }
運行結果
true
true
true
true
true
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false

因為操作都是針對同一個key,所以使用pipline提升redis的存取效率。

pipline是將多條命令一次性發送給redis,並在所有命令執行完后一次性返回,通過減少客戶端和redis的通行次數來實現降低往返延時時間。

缺點

如果在時間窗口中需要記錄的行為次數過多,將會有很大的消耗,比如60s內1000次操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM