Redis 管道pipeline


Redis是一個cs模式的tcp server,使用和http類似的請求響應協議。

一個client可以通過一個socket連接發起多個請求命令。

每個請求命令發出后client通常會阻塞並等待redis服務處理,redis處理完后請求命令后會將結果通過響應報文返回給client。

基本的通信過程如下:

./bin/redis-cli -h 192.168.36.189 -p 6379  
192.168.36.189:6379> incr x  
(integer) 1  
192.168.36.189:6379> incr x  
(integer) 2  
192.168.36.189:6379> incr x  
(integer) 3  

 

 

客戶端和服務端通過網絡進行連接。這樣的連接可能非常快(在一個回路網絡中),也可能非常慢(在廣域網上經過多個結點才能互通的兩個主機)。但是無論是否存在網絡延遲,數據包從客戶端傳輸到服務端,以及客戶端從服務端獲得相應都需要花費一些時間。這段時間就成為往返時延(Round Trip Time)。因此當客戶端需要執行一串請求的時候,很容易看出它對性能的影響(例如往同一個隊列中加入大量元素,或者往數據庫中插入大量的鍵)。如果RTT時長為250毫秒(在基於廣域網的低速連接環境下),即使服務器每秒可以處理10萬個請求,但是實際上我們依然只能每秒處理最多4個請求。
如果處於一個回路網絡中,RTT時長則相當短(我的主機ping 127.0.0.1時只需要0.044ms),但是如果你執行一大串寫入請求的時候,還是會有點長。
幸運的是,redis給我們提供了管道技術。

1.Redis管道技術
一個請求/相應服務可以實現為,即使客戶端沒有讀取到舊請求的響應,服務端依舊可以處理新請求。通過這種方式,可以完全無需等待服務端應答地發送多條指令給服務端,並最終一次性讀取所有應答。管道技術最顯著的優勢是提高了redis服務的性能。
通過pipeline方式當有大批量的操作時候。我們可以節省很多原來浪費在網絡延遲的時間。需要注意到是用pipeline方式打包命令發送,redis必須在處理完所有命令前先緩存起所有命令的處理結果。打包的命令越多,緩存消耗內存也越多。所以並是不是打包的命令越多越好。具體多少合適需要根據具體情況測試。

$(echo -en "PING\r\n SET key redis\r\nGET key\r\nINCR x\r\nINCR x\r\nINCR x\r\n"; sleep 10) | nc 192.168.36.189 6379  
+PONG  
+OK  
$5  
redis  
:4  
:5  
:6  

 

以上實例中我們通過使用 PING 命令查看redis服務是否可用, 之后我們們設置了key的值為 redis,然后我們獲取key 的值並使得x自增 3 次。
在返回的結果中我們可以看到這些命令一次性向redis服務提交,並最終一次性讀取所有服務端的響應。


2.java測試代碼

 

    package cn.slimsmart.redis.demo.pipeline;  
      
    import redis.clients.jedis.Jedis;  
    import redis.clients.jedis.Pipeline;  
      
    @SuppressWarnings("resource")  
    public class PipelineTest {  
      
        public static void main(String[] args) {  
            long start = System.currentTimeMillis();  
            usePipeline();  
            long end = System.currentTimeMillis();  
            System.out.println("usePipeline:"+(end - start));  
      
            start = System.currentTimeMillis();  
            withoutPipeline();  
            end = System.currentTimeMillis();  
            System.out.println("withoutPipeline:"+(end - start));  
        }  
      
        private static void withoutPipeline() {  
            try {  
                Jedis jedis = new Jedis("192.168.36.189", 6379);  
                for (int i = 0; i < 1000; i++) {  
                    jedis.incr("test2");  
                }  
                jedis.disconnect();  
            } catch (Exception e) {  
            }  
        }  
      
        private static void usePipeline() {  
            try {  
                Jedis jedis = new Jedis("192.168.36.189", 6379);  
                Pipeline pipeline = jedis.pipelined();  
                for (int i = 0; i < 1000; i++) {  
                    pipeline.incr("test2");  
                }  
                pipeline.sync();  
                jedis.disconnect();  
            } catch (Exception e) {  
            }  
        }  
    }  

 

運行結果:

127.0.0.1 循環10000次 效果

usePipeline:151
withoutPipeline:6229

 

外網IP循環10000次 效果

 

usePipeline:201
withoutPipeline:94909

結果還是很明顯有較大的差距,所以多次操作用pipeline還是有明顯的優勢。

 


免責聲明!

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



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