天天看點

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

這是 Java 技術驿站第 103 篇原創

-------------

在前面部落格中小編提到過 Redis 性能瓶頸主要是網絡,主要原因就在于 Redis 執行指令的時間通常在微妙級别。正常情況下,我們執行一條 Redis 指令流程要經過如下幾個步驟:

  1. 用戶端發送 Redis 指令,阻塞等待 Redis 應答
  2. Redis 接收到指令,執行指令
  3. 應答,用戶端收到響應資訊
redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

其中 1 、3 稱之為一次 RTT(Round Trip Time)。在這種情況下,如果同時執行大量指令,那目前指令需要等待上一條指令應答完成後才會執行,這個過程不僅僅隻有多次 RTT,還有頻繁的調用系統 IO,發送網絡請求,如下圖:

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

把大量的時間消耗在來回路上,真正辦事的時間就隻有一點點,這種做法是非常不明智且低效的,為了解決這種低效的做法,pipeline 出現了,它允許用戶端一次性發送多條指令,減少 RTT 和 IO 的調用次數(IO 調用涉及到使用者态到核心态之間的切換)。如下圖:

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

實作原理

要支援 pipeline,除了需要 Redis 服務端支援,也需要各個用戶端的支援,例如 jedis 就對 pipeline 提供了很好的支援。對于服務端來說,所需要的就是能夠處理用戶端通過一個 TCP 連接配接發送的多個指令,對多個指令進行排隊,執行。而用戶端,則需要将多個指令緩存起來,待緩沖區滿了就發送,同時還需要處理 Redis 的應答。

pipeline 不是什麼新鮮技術,很多技術都使用過,它能提供性能的核心就在于:它能将一組 Redis 指令進行組裝,通過一次 RTT 傳輸給 Redis,同時再将這組指令的執行結果按照順序傳回給用戶端。将原來一組指令多次 RTT 以及 IO 互動變成了一組 RTT 和 IO 互動,大大減少了網絡傳輸時間和 IO 調用的時間。

下圖是一次請求互動的流程(圖檔來自:《Redis 深度曆險:核心原理與應用實踐》),

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

需要注意的是,在使用 pipeline 的過程中需要控制其中指令的大小,如果一次組裝的指令過多,則會增加造成一定的網絡阻塞,也會增加用戶端的等待時間。

性能壓測

Redis 提供了一個壓測工具

redis-benchmark

,該工具可以進行 pipeline 測試。如下:

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

-P 參數:它表示單個管道内并行的請求數量

與批量的比較

pipeline 的批次送出指令與 Redis 的批量指令有很多相似之處,可以利用 pipeline 模拟出批次的效果,但是他們還是存在一些不同之處:

  1. pipeline 可以一次性發送多個不同的指令,例如 set、get、而批量這是一次一個指令,隻不過這一次對應的是多個 key 而已。
  2. pipeline 隻是将多個指令一起發出去而已,不保證這些指令的執行是原則性,而批量則是原子性的,他需要保證整個操作的正确性,避免中途出錯而導緻最後産生的資料不一緻。

與單個指令的性能測試

publicstaticvoid main(String[] args) throwsIOException{

Jedis jedis = newJedis("127.0.0.1");

Pipeline pipeline = jedis.pipelined();

long pipelineBegin = System.currentTimeMillis();

for(int i = 0; i < 100000; i++){

pipeline.set("pipeline:test_"+i,i + "");

}

//擷取所有的 response

pipeline.sync();

long pipelineEnd = System.currentTimeMillis();

System.out.println("the pipeline is :"+ (pipelineEnd - pipelineBegin));

long start = System.currentTimeMillis();

for(int i = 0; i < 100000; i++) {

jedis.set("jedis:test_"+i,i + "");

}

long end = System.currentTimeMillis();

System.out.println("the jedis is:"+ (end - start));

}

redis 深度曆險 pdf_【死磕 Redis】 了解 pipeline 管道

從圖中可以看出,普通的方式與 pipeline 性能相差 10 倍,從這裡可以看出 pipeline 的性能之強悍。

參考

  • 付磊:《Redis 開發與運維》
  • 掘金小冊子:Redis 深度曆險:核心原理與應用實踐

往期精彩

【死磕 Redis】----- 開篇

【死磕 Redis】----- Redis 通信協定 RESP

【死磕 Redis】----- Redis 的線程模型

【死磕 Redis】----- 事務