首頁  >  文章  >  資料庫  >  關於Redis原子計數器incr,防止並發請求

關於Redis原子計數器incr,防止並發請求

藏色散人
藏色散人轉載
2020-09-28 15:13:022805瀏覽

下面由Redis教學欄位來介紹關於Redis原子計數器incr,防止並發請求,希望對需要的朋友有幫助!

關於Redis原子計數器incr,防止並發請求

一、前言






#在一些對高並發請求有限制的系統或功能裡,比如說秒殺活動,或者一些網站返回的當前用戶過多,請稍後嘗試。這些都是透過對同一時刻請求數量進行了限制,一般用作對後台系統的保護,防止系統因為過大的流量衝擊而崩潰。對於系統崩潰帶來的後果,顯然還是拒絕部分請求更能被維護者所接受。

而在各種限流中,除了系統自身設計的帶鎖機制的計數器外,利用Redis實現顯然是一種既高效安全又便捷方便的方式。


二、incr指令


Redis Incr 指令將 key 中儲存的數字值增一。

如果 key 不存在,那麼 key 的值會先初始化為 0 ,然後再執行 INCR 運算。 如果值包含錯誤的類型,或字串類型的值不能表示為數字,那麼回傳一個錯誤。 本操作的值限制在 64 位元(bit)有符號數字表示之內。

範例:

127.0.0.1:6379> set num 10
OK
127.0.0.1:6379> incr num
(integer) 11
127.0.0.1:6379> get num    # 数字值在 Redis 中以字符串的形式保存
"11"
注意: 由於redis並沒有一個明確的型別來表示整數數據,所以這個操作是一個字串操作。 

執行這個動作的時候,key對應儲存的字串被解析為10進位的64位元有符號整數資料。
事實上,Redis 內部採用整數形式(Integer representation)來儲存對應的整數值,所以對該類別字串值實際上是用整數保存,也就不存在儲存整數的字串表示(String representation)所帶來的額外消耗。

三、使用場景


1.計數器

使用想法是:每次有相關操作的時候,就向Redis伺服器發送一個incr命令。

例如這樣一個場景:我們有一個web應用,我們想記錄每個使用者每天造訪這個網站的次數。

web應用程式只需要透過拼接使用者id和代表目前時間的字串作為key,每次使用者造訪這個頁面的時候對這個key執行一下incr指令。

這個場景可以有很多種擴充方法:
透過結合使用INCR和EXPIRE指令,可以實作一個只記錄使用者在指定間隔時間內的存取次數的計數器

客戶端可以透過GETSET命令取得當前計數器的值並且重置為0

透過類似於DECR或INCRBY等原子遞增/遞減的命令,可以根據使用者的操作來增加或減少某些值例如線上遊戲,需要對使用者的遊戲分數進行即時控制,分數可能增加也可能減少。

2.限速器

限速器是可以限制某些操作執行速率的特殊場景。 傳統的例子就是限制某個公共api的請求數目。 ### 假設我們要解決以下問題:限制某個api每秒每個ip的請求次數不超過10次。 ### 我們可以透過incr指令來實作兩種方法來解決這個問題。 #########四、流量控制之java實作#########這裡我們將在java中使用redis-incr的特性來建構一個1分鐘內只允許請求100次的控制程式碼,key代表在redis內存放的被控制的鍵值。 ###
public static boolean flowControl(String key){
        //最大允许100
        int max = 100;
        long total = 1L;
        try {
            if (jedisInstance.get(key) == null) {
                //jedisInstance是Jedis连接实例,可以使单链接也可以使用链接池获取,实现方式请参考之前的blog内容
                //如果redis目前没有这个key,创建并赋予0,有效时间为60s
                jedisInstance.setex(key, 60, "0");
            } else {
                //获取加1后的值
                total = jedisInstance.incr(redisKey).longValue();
                //Redis TTL命令以秒为单位返回key的剩余过期时间。当key不存在时,返回-2。当key存在但没有设置剩余生存时间时,返回-1。否则,以秒为单位,返回key的剩余生存时间。
                if (jedisInstance.ttl(redisKey).longValue() == -1L)
                {
                    //为给定key设置生存时间,当key过期时(生存时间为0),它会被自动删除。
                    jedisInstance.expire(redisKey, 60);
                }
            }
        } catch (Exception e) {
            logger.error("流量控制组件:执行计数操作失败,无法执行计数");
        }
        long keytotaltransations = max;
        //判断是否已超过最大值,超过则返回false
        if (total > keytotaltransations) {
            return false;
        }
        return true;
    }
######

以上是關於Redis原子計數器incr,防止並發請求的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:csdn.net。如有侵權,請聯絡admin@php.cn刪除