Redis 管道pipeline

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

一個client能夠經過一個socket鏈接發起多個請求命令。redis

每一個請求命令發出後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測試代碼socket

 

    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) {  
            }  
        }  
    }  

 

運行結果:tcp

127.0.0.1 循環10000次 效果性能

usePipeline:151
withoutPipeline:6229
測試

 

外網IP循環10000次 效果

 

usePipeline:201
withoutPipeline:94909

結果仍是很明顯有較大的差距,因此屢次操做用pipeline仍是有明顯的優點。

相關文章
相關標籤/搜索