1. 化繁為簡,批量執(zhí)行Redis命令的4種方式!

        共 4771字,需瀏覽 10分鐘

         ·

        2024-04-10 15:56

        前言

        在我們的印象中Redis命令好像都是一個個單條進行執(zhí)行的,

        如果有人問你如何批量執(zhí)行Redis命令,你能回答的上嗎,或者說能答出幾種方式呢?

        最容易想到的是Redis的一些批量命令,例如MGET

        今天小許就這個問題給大家總結一下!

        18560839a7fa620c97b3a92326937019.webp

        Redis命令執(zhí)行過程

        在了解批量執(zhí)行有哪些方式之前,我們簡單回顧下Redis命令執(zhí)行的過程:

        038c7685124f205b11a9d00936797ddc.webp

        Redis執(zhí)行用戶命令的過程是怎樣的

        為什么需要批量執(zhí)行命令呢?

        在了解批量執(zhí)行命令有哪些方式之前,我們先簡單整理下【批量執(zhí)行命令】比【執(zhí)行多個單Redis命令】能帶來哪些好處!

        通過批量執(zhí)行命令好處如下:

        • 提高命令執(zhí)行效率:減少網絡延遲,提高Redis服務器的響應速度

        • 簡化客戶端邏輯:將多個命令封裝成一個操作,簡化客戶端處理邏輯

        • 提升事務性能:可以保證一組命令在同一時間內執(zhí)行,提高事務的性能

        97522fa731e64646dea68947d95594ad.webp

        你看單個執(zhí)行命令每次都需要發(fā)送進行網絡傳輸,同樣多的執(zhí)行,批量執(zhí)行可以有效減小網絡開銷,減少 RTT(往返時間)。

        批量執(zhí)行命令的方式

        有以下四種常見批量執(zhí)行命令的方式:

        1. 1. Redis原生命令:例如 MSET、HMGET、HMSET、SADD

        2. 2. pipeline(管道)

        3. 3. Lua腳本

        4. 4. Redis事務

        f5ed029136fceae6a835c8f5a11286b0.webp

        我們來給每種方式簡單舉個栗子,然后看看有什么需要注意的地方!

        原生批量命令

        Redis的原生命令就支持批量命令的操作,比如:HMSET、HMGET、SADD。

        其實嚴格來說上述命令不屬于批量操作,而是在一個指令中處理多個key,我們來看下具體該如何使用。

        String字符串

        MSET:設置一個或多個指定 key 的值

        MGET:從一個或多個指定的key中獲取值

            
            
              MSET key value [key value ...]
        MGET key [key ...]

        Hash哈希

        操作哈希類型時,使用HMSET和HMGET命令分別設置和獲取多個字段及其值

        HMSET:將一個或多個 field-value 對設置到指定哈希表中

        HMGET:從指定指定哈希表中一個或者多個字段的值

            
              HMSET key field value [field value ...]
        HMGET key field [field ...]

        Sorted Set 有序集合

        SADD可以將多個元素添加到有序集合

            
            
              SADD key member [member ...]
            
          

        ?? 注意

        ?? Redis Cluster中MGET操作可能無法保證原子性!

        因為在 Redis Cluster 中,MGET操作涉及多個鍵的讀取操作,并且這些鍵無法保證所有的 key 都在同一個 hash slot(哈希槽)上。

        而Redis Cluster 的節(jié)點間可能會有網絡延遲和不同的負載情況,MGET 操作不能保證在同一時刻原子地獲取所有鍵的值。

        不過相較于非批量操作,這些指令可以節(jié)省不少網絡傳輸次數,畢竟不用發(fā)送一次命令,服務器響應一次。

        pipeline(管道)

        Redis Pipeline(管道)命令是一種優(yōu)化網絡通信的技術,可以將多個命令一次性發(fā)送給Redis服務器,可以減少客戶端與Redis服務器之間的網絡通信次數。

        004e82e851f76dc95b88987f55f4d3b1.webp

        客戶端將多個命令發(fā)送到Redis服務器,Redis服務器將這些命令緩存起來,然后一次性執(zhí)行,最后將執(zhí)行結果一次性返回給客戶端。

        使用Redis Pipeline好處很明顯,可以避免在每個命令執(zhí)行時都進行一次網絡通信,時間開銷變?yōu)椋?/p>

        ?? 1 次 pipeline(n條命令) = 1 次網絡時間 + 執(zhí)行n 條命令時間

        使用

        這里用Golang語言看看如何使用pipeline , 從代碼中可以看出需要服務端和客戶端的共同實現(xiàn),不像原生批量命令一樣Redis直接支持實現(xiàn)。

            
            package main
        import (

            "github.com/go-redis/redis"
        )
        func main() {
            pipe := client.Pipeline()
            defer pipe.Close()
            // 封裝 pipeline待執(zhí)行命令
            set := pipe.Set("key", "value", 0)
            get := pipe.Get("key")
            // 執(zhí)行 pipeline
            _, err := pipe.Exec()
            if err != nil {
                panic(err)
            }
            // 獲取 pipeline執(zhí)行結果
            val, err := get.Result()
            if err != nil {
                panic(err)
            }
        }

        ?? 注意

        ?? 1:Redis Cluster中Pipeline命令操作可能無法保證原子性!

        因為 Redis Cluster 采用的分片機制,這些鍵無法保證所有的 key 都在同一區(qū)域hash slot(哈希槽)上,所以不同的命令可能會發(fā)送到不同的節(jié)點上。

        這意味著即使你使用 Pipeline,每個命令仍然在不同的節(jié)點上進行處理,可能會導致多個命令的執(zhí)行不是在同一時刻進行的。

        ?? 2:pipeline 能執(zhí)行有依賴關系的命令嗎?

        答案是不可以的,如果pipeline中后一個命令的執(zhí)行需要依賴前一個命令的執(zhí)行結果,就沒辦法滿足需求了。

        ?? 3:pipeline對發(fā)送的命令有數量限制嗎?

        雖然命令可以一次性發(fā)給Redis服務端,但是考慮帶寬等情況,建議不多于500個命令,或者根據實際命令的數據類型定。

        為了保證更高的一致性和原子性,就需要考慮使用其他方式,比如Lua腳本、事務的方式了,我們繼續(xù)往下看!

        Lua腳本

        我們知道Redis支持使用Lua腳本來執(zhí)行自定義的復雜邏輯,因此使用Lua腳本,我們可以在Redis服務器端執(zhí)行多個命令。

        而且Lua腳本具有原子性,即腳本中的所有命令會在同一時間內執(zhí)行,不會被其他命令打斷。

        使用

        在Redis中使用EVAL命令使用 Lua 解釋器執(zhí)行腳本,語法如下:

            
            
              redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...] 
            
          
        • ? script:要執(zhí)行的Lua腳本

        • ? numkeys:腳本中涉及到的鍵的數量

        • ? key和arg:腳本中的鍵和參數

        ?? 注意

        Redis Cluster 下 Lua 腳本的原子操作同樣無法操作,原因也是無法保證所有的 key 都在同一個 hash slot(哈希槽)上。

        Redis事務

        Redis事務(Transaction)通過將多個Redis操作封裝為一個原子性的操作序列,確保在事務執(zhí)行過程中,不會受到其他客戶端的干擾。

        ?? 比起原生命令和pipeline批量執(zhí)行方式,事務的執(zhí)行具備原子性,即全部被執(zhí)行或全部不執(zhí)行,并且在持久化時也具備原子性。

        使用

        Redis事務使用以下三個命令進行操作:

        • ? MULTI:標記事務開始

        • ? EXEC:執(zhí)行所有在MULTI之后的命令

        • ? DISCARD:取消事務

        用過數據庫事務的對這幾個命令也很容易理解,MULTI和EXEC之間的所有命令將作為一個整體被執(zhí)行。這些命令會被放入隊列中,等待EXEC命令的調用,一旦EXEC命令被調用,所有的命令將按照順序被執(zhí)行。

        ?? 注意

        Redis Cluster支持transaction,但是前提是transaction涉及的所有key都屬于同一hash slot

        所有需要被事務處理的鍵必須分布在同一個節(jié)點上

        ?? Redis Cluster模式下該如何正確使用批量命令操作?

        通過對上面四種方式的總結,可以發(fā)現(xiàn)在Redis Cluster模式下會存在key可能不屬于同一個節(jié)點的hash slot(哈希槽)上,導致不能按實際想的方式去執(zhí)行。

        小許查了下也有一些解決方式,看下是否適合你。

        ?? hash-tag方式:

        Redis Cluster模式一般都是支持 hash-tag 功能,它可以將多個 key 強制分配到一個節(jié)點上,它的操作時間 =1 次網絡時間 +n 次命令時間。

        這種方式雖然性能高,可能會因為不均衡問題導致Redis Cluster部分節(jié)點負載過高。

        ?? 維護Hash Slot映射關系:

        因為主要問題在于,不能讓所有的key在同一個節(jié)點上執(zhí)行,那么我們在客戶端維護一個key和slot的映射關系,是不是就讓key固定在了一個節(jié)點的hash slot執(zhí)行了!

        如有不對的地方還請朋友們指出!

        歡迎點贊 ??、收藏 ??、關注 ?? 三連支持一下~??

        知道的越多,不知道的也越多,我是小許,下期見~????


        瀏覽 47
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 欧美馒头逼 | 摸进她的内裤里疯狂揉她动小说 | 国产一级毛片精品A片在线美传媒 | 久久久亚洲精品石原莉奈 | 女人脱了内裤让男人桶爽小说 |