標籤:
redis是一個cs模式的tcp server,使用和http類似的請求響應協議。一個client可以通過一個socket串連發起多個請求命令。每個請求命令發出後client通常會阻塞並等待redis服務處理,redis處理完後請求命令後會將結果通過響應報文返回給client。基本的通訊過程如下:
Client: INCR XServer: 1Client: INCR XServer: 2Client: INCR XServer: 3Client: INCR XServer: 4
基本上四個命令需要8個tcp報文才能完成。由於通訊會有網路延遲,假如從client和server之間的包傳輸時間需要0.125秒。那麼上面的四個命令8個報文至少會需要1秒才能完成。這樣即使redis每秒能處理100個命令,而我們的client也只能一秒鐘發出四個命令。這顯示沒有充分利用 redis的處理能力。除了可以利用mget,mset 之類的單條命令處理多個key的命令外我們還可以利用pipeline的方式從client打包多條命令一起發出,不需要等待單條命令的響應返回,而redis服務端會處理完多條命令後會將多條命令的處理結果打包到一起返回給用戶端。通訊過程如下:
Client: INCR XClient: INCR XClient: INCR XClient: INCR XServer: 1Server: 2Server: 3Server: 4
假設不會因為tcp報文過長而被拆分。可能兩個tcp報文就能完成四條命令,client可以將四個incr命令放到一個tcp報文一起發送,server則可以將四條命令的處理結果放到一個tcp報文返回。通過pipeline方式當有大批量的操作時候。我們可以節省很多原來浪費在網路延遲的時間。需要注意到是用 pipeline方式打包命令發送,redis必須在處理完所有命令前先緩衝起所有命令的處理結果。打包的命令越多,緩衝消耗記憶體也越多。所以並是不是打包的命令越多越好。具體多少合適需要根據具體情況測試。下面是個jedis用戶端使用pipeline的測試:
package com.jd.redis.client; import redis.clients.jedis.Jedis;import redis.clients.jedis.Pipeline; publicclass PipelineTest { /** * @param args */ publicstaticvoid main(String[] args) { int count = 1000; long start = System.currentTimeMillis(); withoutPipeline(count); long end = System.currentTimeMillis(); System.out.println("withoutPipeline: " + (end-start)); start = System.currentTimeMillis(); usePipeline(count); end = System.currentTimeMillis(); System.out.println("usePipeline: " + (end-start)); } privatestaticvoid withoutPipeline(int count){ Jedis jr = null; try { jr = new Jedis("10.10.224.44", 6379); for(int i =0; i<count; i++){ jr.incr("testKey1"); } } catch (Exception e) { e.printStackTrace(); } finally{ if(jr!=null){ jr.disconnect(); } } } privatestaticvoid usePipeline(int count){ Jedis jr = null; try { jr = new Jedis("10.10.224.44", 6379); Pipeline pl = jr.pipelined(); for(int i =0; i<count; i++){ pl.incr("testKey2"); } pl.sync(); } catch (Exception e) { e.printStackTrace(); } finally{ if(jr!=null){ jr.disconnect(); } } }}
輸出:
withoutPipeline: 11341usePipeline: 344
測試結果還是很明顯有較大的差距,所以多次操作用pipeline還是有明顯的優勢。我用的是Win7中的Jedis Java用戶端程式串連區域網路的Linux虛擬機器上的Redis Server。
Redis管道(pipeline)