Redis性能調優之Pipeline(管道)

1、性能問題

一、概述

Redis使用的是客戶端-服務端這種CS模型和請求/響應的TCP服務器。這意味着一般狀況下一個請求會遵循如下步驟:java

  • 客戶端向服務端發送一個請求,並監聽SOCKET返回,一般是阻塞模式,等待服務端響應。
  • 服務端處理客戶端發來的命令並進行處理,最終將結果返回給客戶端。

redis確實是非阻塞,可是redis服務端處理是非阻塞,用戶端來說仍是阻塞。
至於redis爲何這麼快,能夠看這個一文帶你完全掌握Redis爲何這麼快?web

二、舉例

也就是說一個客戶端能夠經過一個socket鏈接發起多個請求命令,每一個請求命令發出後客戶端一般會阻塞並等待redis服務器處理,redis處理完請求命令後會將結果經過響應報文返回給客戶端。由於當執行多條命令的時候都須要等待上條命令執行完畢才能執行,好比:redis

set k1 1
keys *
get k1

Redis採起IO因爲通訊會有網絡延遲,假如 client 和 server 之間的包傳輸時間須要0.125秒。那麼上面的三個命令6個報文至少須要0.75秒才能完成。這樣即便 redis 每秒能處理100個命令,而咱們的 client 也只能一秒鐘發出四個命令。這顯然沒有充分利用 redis 的處理能力。編程

2、什麼是Pipeline

咱們已經知道上面的問題了,也知道性能是耗費再了通訊上,這時候pipeline橫空出世,他的目的是將一批命令打包到一個內部維護的queue裏,而後創建socket與server交互,這時候是隻會發送一次命令,也就是隻會交互一次,而後queue內的命令都執行完後會一塊兒返回結果,這樣大大減小了通訊的次數,天然下降了通訊所耗費的時間。queue是先進先出,因此能夠保證執行順序。服務器

3、說明

並非pipeline就無敵了,之後都用這個。這須要看需求的。好比你的需求get key 實時性很高,並且要用他的返回值作處理。那你把get key這個命令與其餘100個命令放到一塊兒去批處理進行,那反而在業務角度分析,效率更爲低下。微信

4、測試

以下demo是從http://www.javashuo.com/article/p-gbozipgk-he.html這個地址而來,若有侵權請聯繫我~網絡

/* * 測試普通模式與 PipeLine 模式的效率: * 測試方法:向 redis 中插入 10000 組數據 */
public static void testPipeLineAndNormal(Jedis jedis) throws InterruptedException {
	Logger logger = Logger.getLogger("javasoft");
	long start = System.currentTimeMillis();
	for (int i = 0; i < 10000; i++) {
		jedis.set(String.valueOf(i), String.valueOf(i));
	}
	long end = System.currentTimeMillis();
	logger.info("the jedis total time is:" + (end - start));

	Pipeline pipe = jedis.pipelined(); // 先建立一個 pipeline 的連接對象
	long start_pipe = System.currentTimeMillis();
	for (int i = 0; i < 10000; i++) {
		pipe.set(String.valueOf(i), String.valueOf(i));
	}
	pipe.sync(); // 獲取全部的 response
	long end_pipe = System.currentTimeMillis();
	logger.info("the pipe total time is:" + (end_pipe - start_pipe));
	
	BlockingQueue<String> logQueue = new LinkedBlockingQueue<String>();
	long begin = System.currentTimeMillis();
	for (int i = 0; i < 10000; i++) {
		logQueue.put("i=" + i);
	}
	long stop = System.currentTimeMillis();
	logger.info("the BlockingQueue total time is:" + (stop - begin));
}

在這裏插入圖片描述

5、使用場景

不適用場景:socket

  • 要求可靠性高,每次都須要實時知道此次操做是否成功,數據是否寫入redis了等對實時性的這種需求都不適合。

適用場景:svg

  • 對實時性要求不高的
  • 批量的將數據寫入 redis,容許必定比例的寫入失敗

好比羣發短信、郵件這種,失敗了我補償,我不須要及時知道發送結果的,這種用pipeline合適 。性能

6、總結

  • 什麼是Pipeline
  • Pipeline能夠性能調優
  • 使用場景

7、我的公衆號

微信公衆號【Java碼農社區】
在這裏插入圖片描述