如何用好redis pipeline


編者注:pipeline是Redis的一個提高吞吐量的機制,適用於多key讀寫場景,比如同時讀取多個key的value,或者更新多個key的value。工作過程中發現挺多小伙伴都對pipeline多少有些了解,但是更深入的理解或者說有哪些坑就不知道了,下面咱們就一起分析下redis pipeline機制,揭開它的神秘面紗。

Redis本身是基於Request/Response協議(停等機制)的,正常情況下,客戶端發送一個命令,等待Redis返回結果,Redis接收到命令,處理后響應。在這種情況下,如果同時需要執行大量的命令,那就是等待上一條命令應答后再執行,這中間不僅僅多了RTT(Round Time Trip),而且還頻繁調用系統IO,發送網絡請求。為了提升效率,這時候pipeline出現了,它允許客戶端可以一次發送多條命令,而不等待上一條命令執行的結果,這和網絡的Nagel算法有點像(TCP_NODELAY選項)。pipeline不僅減少了RTT,同時也減少了IO調用次數(IO調用涉及到用戶態到內核態之間的切換)

要支持Pipeline,其實既要服務端的支持,也要客戶端支持。對於服務端來說,所需要的是能夠處理一個客戶端通過同一個TCP連接發來的多個命令,可以理解為,這里將多個命令切分,和處理單個命令一樣(之前老生常談的黏包現象),Redis就是這樣處理的。而客戶端,則是要將多個命令緩存起來,緩沖區滿了或者達到發送條件就發送出去,最后才處理Redis的應答。


注意:Redis的Pipeline和Transaction(Redis事務)不同,Transaction會存儲客戶端的命令,最后一次性執行,而Pipeline則是處理一條(批次),響應一條,從二者的不同處理機制來看,Redis事務中命令的執行是原子的(注意,其中一部分命令出現錯誤后續命令會繼續執行,這里的原子說的是命令執行是完整的,中間不會被其他Redis命令所打斷),而pipeline中命令的執行不一定是原子的。但是這里卻有一點不同,就是pipeline機制中,客戶端並不會調用read去讀取socket里面的緩沖數據(除非已經發完pipeline中所有命令),這也就造成了,如果Redis應答的數據填滿了該接收緩沖(SO_RECVBUF),那么客戶端會通過ACK,WIN=0(接收窗口)來控制服務端不能再發送數據,那樣子,數據就會緩沖在Redis的客戶端應答緩沖區里面。所以需要注意控制Pipeline的大小。如下圖:


這里可以設想一下,如果客戶端通過ACK,WIN=0(接收窗口)來控制服務端不能再發送數據,那么數據就會堆積在服務端socket發送緩沖區中,如果服務端socket發送緩沖區也滿了,那么此時服務端調用write(socket)就會阻塞或者失敗。

既然提到了tcp/ip的滑動窗口概念,這里就簡單總結下滑動窗口:

滑動窗口在TCP中的作用是提供TCP的可靠性和流控特性,滑動窗口可分為發送窗口和接收窗口,它們分別對應於發送緩沖區和接收緩沖區。發送窗口的大小是根據客戶端接收緩沖區的大小而設定的(三次握手的目的是連接服務器指定端口,建立 TCP 連接,並同步連接雙方的序列號和確認號,交換 TCP 窗口大小信息)。

發送窗口中包含的內容是已發送但還未收到Ack的數據和未發送但對端允許發送的數據。


TCP接收緩沖區中包含應用為讀取數據、已接收數據(已回復ACK)、待接收,其中待接收空間可稱為接收窗口。

使用pipeline過程中,要注意控制一次pipeline中的命令總大小,不能使響應結果撐爆socket接收緩沖區。這里我們思考一個問題,還有沒有其他方式提高pipeline的處理性能呢?理論上是有的,比如可以使用數據壓縮機制,進一步減小數據傳輸的總大小,不過這需要客戶端和服務端提供解壓縮機制,同時會耗費一定量服務器CPU。

歡迎小伙伴關注【TopCoder】閱讀更多精彩好文。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM