天天看點

Redis開發與運維. 3.3 Pipeline

<b>3.3 pipeline</b>

<b>3.3.1 pipeline概念</b>

redis用戶端執行一條指令分為如下四個過程:

1)發送指令

2)指令排隊

3)指令執行

4)傳回結果

其中1)+4)稱為round trip time(rtt,往返時間)。

redis提供了批量操作指令(例如mget、mset等),有效地節約rtt。但大部分指令是不支援批量操作的,例如要執行n次hgetall指令,并沒有mhgetall指令存在,需要消耗n次rtt。redis的用戶端和服務端可能部署在不同的機器上。例如用戶端在北京,redis服務端在上海,兩地直線距離約為1300公裡,那麼1次rtt時間=1300 ×2/(300000×2/3)=

13毫秒(光在真空中傳輸速度為每秒30萬公裡,這裡假設光纖為光速的2/3),那麼用戶端在1秒内大約隻能執行80次左右的指令,這個和redis的高并發高吞吐特性背道而馳。

pipeline(流水線)機制能改善上面這類問題,它能将一組redis指令進行組裝,通過一次rtt傳輸給redis,再将這組redis指令的執行結果按順序傳回給用戶端,圖3-5為沒有使用pipeline執行了n條指令,整個過程需要n次rtt。

圖3-6為使用pipeline執行了n次指令,整個過程需要1次rtt。

pipeline并不是什麼新的技術或機制,很多技術上都使用過。而且rtt在不同網絡環境下會有不同,例如同機房和同機器會比較快,跨機房跨地區會比較慢。redis指令真正執行的時間通常在微秒級别,是以才會有redis性能瓶頸是網絡這樣的說法。

redis-cli的--pipe選項實際上就是使用pipeline機制,例如下面操作将set

hello world和incr counter兩條指令組裝:

echo -en

'*3\r\n$3\r\nset\r\n$5\r\nhello\r\n$5\r\nworld\r\n*2\r\n$4\r\nincr\r\

n$7\r\ncounter\r\n' | redis-cli --pipe

但大部分開發人員更傾向于使用進階語言用戶端中的pipeline,目前大部分redis用戶端都支援pipeline,第4章我們将介紹如何通過java的redis用戶端jedis使用pipeline功能。

<b>3.3.2 性能測試</b>

表3-1給出了在不同網絡環境下非pipeline和pipeline執行10000次set操作的效果,可以得到如下兩個結論:

pipeline執行速度一般比逐條執行要快。

用戶端和服務端的網絡延時越大,pipeline的效果越明顯。

圖3-6 使用pipeline執行n條指令模型

因測試環境不同可能得到的具體數字不盡相同,本測試pipeline每次攜帶100條

指令。

表3-1 在不同網絡下,10000條set非pipeline和pipeline的執行時間對比

網  絡         延  遲         非pipeline        pipeline

本機         0.17ms     573ms      134ms

内網伺服器     0.41ms     1?610ms 240ms

異地機房         7ms 78?499ms        1?104ms

<b>3.3.3 原生批量指令與pipeline對比</b>

可以使用pipeline模拟出批量操作的效果,但是在使用時要注意它與原生批量指令的差別,具體包含以下幾點:

原生批量指令是原子的,pipeline是非原子的。

原生批量指令是一個指令對應多個key,pipeline支援多個指令。

原生批量指令是redis服務端支援實作的,而pipeline需要服務端和用戶端的共同實作。

<b>3.3.4 最佳實踐</b>

pipeline雖然好用,但是每次pipeline組裝的指令個數不能沒有節制,否則一次組裝pipeline資料量過大,一方面會增加用戶端的等待時間,另一方面會造成一定的網絡阻塞,可以将一次包含大量指令的pipeline拆分成多次較小的pipeline來完成。

pipeline隻能操作一個redis執行個體,但是即使在分布式redis場景中,也可以作為批量操作的重要優化手段,具體細節見第11章。