Redis(六)管道(Pipelining)
管道技術並不是Redis特有的,管道技術在計算機科學中有很多地方的應用。
來自wiki的解釋:
In computing, a pipeline, also known as a data pipeline,[1] is a set of data processing elements connected in series, where the output of one element is the input of the next one. The elements of a pipeline are often executed in parallel or in time-sliced fashion. Some amount of buffer storage is often inserted between elements.
在計算機中,管道又叫做數據管道,是數據處理元件。一個元件的輸出作為另一個元件的輸入。管道中元素經常是並行或者是基於事件分片。在元素之間會插入緩沖區。
說白了就是傳輸計算元素。與計算機領域相關的管道非常多,其中平時應用開發中遇到的就是網絡協議的HTTP pipelining。
HTTP Pipelining
HTTP pipelining is a technique in which multiple HTTP requests are sent on a single TCP connection without waiting for the corresponding responses.[1]
HTTP pipelining是一種技術,多個HTTP請求基於一個TCP連接以無等待匹配的響應的方式被發送。
HTTP中引入pipelining主要是為了提高性能。在一些高延遲的網絡中,如果需要等待上一個HTTP請求的響應後再發送下一個請求,那麽網絡延遲勢必是性能瓶頸之所在。pipelining為了解決這個問題,即流水線式發送HTTP請求,client不等待上一個請求的響應,只要server端按照請求的順序返回響應即可。這樣雖然無法從根本上解決網絡延遲的問題,但是卻可以減少request/response這種模式帶來的環回時間。
Pipelining帶來了以下的優勢:
- 如上所述,減少了多個請求的整體環回時間,提高了性能
- 對於server端,能夠在單位時間內接收到更多的請求,在server性能滿足的前提下,提高了server端的吞吐量
同樣萬物平衡,Pipelining也有很多限制:
- 請求之間應該保證無依賴,後一個請求不能依賴前一個請求的響應結果。這種場景不適合使用pipelining
- 非冪等性請求不能使用pipelining(如post請求),同樣的post請求會改變資源的狀態,在使用pipelining技術中,會導致不冪等
下圖引用wiki和《HTTP權威指南》中關於HTTP pipelining的描述:
參考
Pipelining
HTTP pipelining
《HTTP權威指南》
Redis-Pipelining
在看完pipelining,相信大家對管道(流水線)技術有一個初識。下面再來看下它是如何在Redis中被應用,為什麽應用。
- Redis Pipelining介紹
- Redis Pipelining解決的問題
- Jedis中Pipelining的使用
- Jedis中的Pipleling的Benchmark
- Redis Pipelining在項目實戰中的應用
一.Redis Pipelining介紹
Redis是是一種client-server的request/response的模式,Redis有單獨的TCP Server。
- client發送請求請求到server端,然後需要阻塞等待server端的響應
- server端處理請求然後返回響應給client
即如上中介紹的HTTP的request/response一樣。在這種模式中,數據包必須從client發送到server端,然後再從server端返回到client端,這個時間叫做RTT(Round Trip Time)。
假設Redis Server每秒能處理100k請求,但是RTT是250ms,這樣Redis Server實際每秒只能處理4個請求,而且這種影響會隨著網絡延遲越大而逐漸加劇。所帶來的直接影響:
- 阻塞客戶端線程或進程,消耗資源,大量請求時無疑降低client性能
- 降低server端的吞吐量
為了解決該問題,需要一種client無等待響應的方式發送請求至server的模式,即Redis pipelining。
Redis pipelining使得client能夠無等待響應的方式連續發送多條命令請求至Redis Server端,然後Server端按照請求順序返回響應結果,類似:
client> set k0 v0;
client> set k1 v1;
client> set k2 v2;
server> ok
server> ok
server> ok
二.Redis Pipelining解決的問題
從以上的Redis pipelining介紹中可以看出,Redis pipelining降低了高延遲網絡中,request/response方式帶來的請求應答的環回時間消耗:
- 無序等待響應的方式發送請求,減少等待時間(特別在高延遲網絡中)
- 一次性返回響應,減少多次響應的帶來的時間消耗
更重要的一點是,在request/response的方式中,逐次發送請求至server端,server端每次都需要read/write,這裏的read/write是systcall,涉及到內核態和用戶態的切換,非常消耗系統資源。Redis pipelining的方式盡量減少了這種系統狀態的切換開銷。
三.Jedis中Pipelining的使用
Pipelining急需要Redis Server端的支持又需要Redis client的支持。client需要能夠不獲取響應的情況下發送多個命令,server端需要編排好響應以請求的順序返回給客戶端。
Redis的經典Client jedis是支持Pipelining的。使用方式可以分為兩種,獲取響應方式也可以分為兩種。
1.使用pipelining方式:
- 直接使用pipelining
- 在事務中使用pipelining
2.獲取響應方式:
- 同步,一次性獲取所有請求的響應,以list方式返回
- 同步,在調用pipelining的操作時,指定返回的響應
關於測試的代碼和pipelining的api使用詳情可以戮
四.Jedis中的Pipleling的Benchmark
前面第二節中分析Pipelining就是解決網絡延遲,提高吞吐量。那麽在使用Pipelining的情況下,相對於不使用的情況下,性能是否提高了?提高多少?
一切都需要用數據來說話。下面分別跑下測試,比較下。Jedis的測試案例中有Benchmark模塊,這裏直接使用其Pipelining和GetSet的Benchmark的測試程序:
執行命令數 | ops(no pipelining/pipelining) |
---|---|
100 | 6666 ops/9090 ops |
100000 | 26870 ops/316455 ops |
1000000 | 28967 ops/422922 ops |
從以上的可以看出使用Pipelining的情況下大致能提高20倍的性能。
五.Redis Pipelining在項目實戰中的應用
首先認識下Pipelining的特點:
- 批量流水線發送
- 一次返回相應的響應
兩個特點決定了應用場景必須有以下特點:
- 由於是批量流水線發送,所以每個請求之間需要無狀態,即後請求不依賴前請求的響應結果
- 由於一次返回響應,所以響應中可能會存在有些請求命令執行成功,有些失敗。所以應用場景必須能夠容忍數據處理錯誤或者數據丟失的風險,或者能夠接受通過其他機制彌補丟失或者錯誤的數據方式
一般適用於批量緩存數據或者預加載緩存數據。因為不需要逐條發送緩存的數據,可以pipelining方式發送。因為是緩存數據,緩存的場景能夠容忍某一些數據緩存失敗,無非是沒有命中,再次加載單條加載至緩存。
最近在做一個業務數據預警檢查的項目,采用責任鏈模式,將需要預警檢查的每條數據遍歷責任鏈,完成數據一致性校驗檢查。責任鏈中每個檢查器都是可配置生效失效,而且支持可擴展檢查器。擴展性、可配置型較強,但是帶來的問題即每條需要預警檢查的數據遍歷責任鏈檢查器時,都需要重復的查詢一些其他的表數據與配置。這裏從而引入了巨大的磁盤I/O,產生性能瓶頸。
後來想如果,能將這些其他表的數據預加載進入緩存中,每次遍歷需要預警檢查的數據時,不從DB中查詢獲取,直接從緩存中獲取即可。由於服務是集群的,所以需要使用分布式緩存且本地緩存容量有限。
這裏最終采用懶加載的方式緩存其他表的數據或者配置,在預警檢查第一條數據時,各個檢查器將其他表的數據或者配置加載到緩存中,同時采用pipelining模式緩存到Redis中。
這樣下條預警數據的遍歷檢查器時,每個檢查器從緩存中獲取其他表的數據或者配置即可。大幅度減少DB帶來的I/O,突破性能瓶頸。
Redis(六)管道(Pipelining)