Redis管道(Pipeline)詳解

在講解管道前,我們首先來了解一下redis的交互,redis的一次交互是由客戶端發起,由服務端接收,那麼我們連續操作一些指令,如下圖所示:

客戶端請求一個指令到服務器到服務器返回數據這個過程非常複雜,既要保證數據能夠快速傳到也要保證不丟包,那麼每次請求響應這個過程中數據傳輸和客戶端接收數據的網絡消耗非常大,那麼我們怎麼來提升這個性能呢?

上面說了,我們來回幾次消耗大,那麼可以一次性請求,一次性接收嗎?當然是可以的,redis可以利用管道來提高性能。

Redis客戶端與服務器之間使用TCP協議進行通信,並且很早就支持管道(pipelining)技術了。Redis 管道 (Pipeline) 本身並不是 Redis 服務器直接提供的技術,這個技術本質上是由客戶端提供的,跟服務器沒有什麼直接的關係。

這裏值得注意的是,管道空間也有上限,合理利用纔是最好的選擇。

管道壓力測試 

接下來我們測試一下管道的性能,Redis自帶了一個壓力測試工具redis-benchmark,使用這個工具就可以進行管道測試。 

首先我們對一個普通的set指令進行壓測,QPS大約5w/s。 

> redis-benchmark -t set -q SET: 53975.05 requests per second 

我們加入管道選項-P參數,它表示單個管道內並行的請求數量,看下面 P=2,QPS達到了9w/s。 

> redis-benchmark -t set -P 2 -q SET: 94240.88 requests per second 

再看看 P=3,QPS達到了 10w/s。 

> redis-benchmark -t set -P 2 -q SET: 102354.15 requests per second

但如果再繼續提升 P 參數,發現 QPS 已經上不去了。這是爲什麼呢? 

因爲這裏CPU處理能力已經達到了瓶頸,Redis的單線程CPU已經飆到了 100%,所以無法再繼續提升了

深入理解管道本質 

接下來我們深入分析一個請求交互的流程

上圖就是一個完整的請求交互流程圖: 

    1、客戶端進程調用write將消息寫到操作系統內核爲套接字分配的發送緩衝send buffer。 

    2、客戶端操作系統內核將發送緩衝的內容發送到網卡,網卡硬件將數據通過「網關路由」送到服務器的網卡。 

    3、服務器操作系統內核將網卡的數據放到內核爲套接字分配的接收緩衝 recv buffer。 

     4、服務器進程調用read從接收緩衝中取出消息進行處理。 

    5、服務器進程調用write將響應消息寫到內核爲套接字分配的發送緩衝 send buffer。 

    6、服務器操作系統內核將發送緩衝的內容發送到網卡,網卡硬件將數據通過「網關路由」送到客戶端的網卡。 

    7、客戶端操作系統內核將網卡的數據放到內核爲套接字分配的接收緩衝 recv buffer。 

    8、客戶端進程調用read從接收緩衝中取出消息返回給上層業務邏輯進行處理。 

    9、結束。 

我們開始以爲write操作是要等到對方收到消息纔會返回,但實際上不是這樣的。write操作只負責將數據寫到本地操作系統內核的發送緩衝然後就返回了。剩下的事交給操作系統內核異步將數據送到目標機器。但是如果發送緩衝滿了,那麼就需要等待緩衝空出空閒空間來,這個就是寫操作IO操作的真正耗時。我們開始以爲read操作是從目標機器拉取數據,但實際上不是這樣的。read操作只負責將數據從本地操作系統內核的接收緩衝中取出來就了事了。

所以對於value=redis.get(key)這樣一個簡單的請求來說,write操作幾乎沒有耗時,直接寫到發送緩衝就返回,而read就會比較耗時了,因爲它要等待消息經過網絡路由到目標機器處理後的響應消息,再回送到當前的內核讀緩衝纔可以返回。這纔是一個網絡來回的真正開銷。 而對於管道來說,連續的write操作根本就沒有耗時,之後第一個read操作會等待一個網絡的來回開銷,然後所有的響應消息就都已經回送到內核的讀緩衝了,後續的 read 操作直接就可以從緩衝拿到結果,瞬間就返回了。 

這就是管道的本質了,它並不是服務器的什麼特性,而是客戶端通過改變了讀寫的順序帶來的性能的巨大提升。 

 

 

一名正在搶救的coder

筆名:mangolove

CSDN地址:https://blog.csdn.net/mango_love

GitHub地址:https://github.com/mangoloveYu

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章