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仍是有明顯的優點。