http://blog.csdn.net/oyl822/article/details/44460949
Redis是一個響應式的服務,當客戶端發送一個請求后,就處于阻塞狀態等待Redis返回結果。這樣一次命令消耗的時間就包括三個部分:請求從客戶端到服務器的時間、結果從服務器到客戶端的時間和命令真正執行時間,前兩個部分消耗的時間總和稱為RTT(Round Trip Time),當客戶端與服務器存在網絡延時時,RTT就可能會很大,這樣就會導致性能問題。管道(Pipeline)就是為了改善這個情況的,利用管道,客戶端可以一次性發送多個請求而不用等待服務器的響應,待所有命令都發送完后再一次性讀取服務的響應,這樣可以極大的降低RTT時間從而提升性能。
下面這個例子,在本地分別以普通請求和管道對一個鍵調用2000次incr命令的測試。
- public class App
- {
- public static void main( String[] args ) {
- long start = System.currentTimeMillis();
- withoutPipeline();
- System.out.println("Without Pipeline takes: " + (System.currentTimeMillis() - start) + " ms.");
-
- start = System.currentTimeMillis();
- withPipeline();
- System.out.println("With Pipeline takes: " + (System.currentTimeMillis() - start) + " ms.");
- }
-
- public static void withPipeline() {
- Jedis jedis = null;
-
- try {
- jedis = new Jedis("localhost", 6379);
- jedis.flushDB();
- Pipeline p = jedis.pipelined();
-
- p.set("thekey", Integer.toString(0));
-
- for (int i = 1; i <= 2000; i++) {
- p.incr("thekey");
- }
-
- Response<String> r = p.get("thekey");
-
- p.sync();
-
- System.out.println(r.get());
- } finally {
- jedis.close();
- }
-
- }
-
- public static void withoutPipeline() {
- Jedis jedis = null;
-
- try {
- jedis = new Jedis("localhost", 6379);
- jedis.flushDB();
- jedis.set("thekey", Integer.toString(0));
-
- for (int i = 1; i <= 2000; i++) {
- jedis.incr("thekey");
- }
-
- System.out.println(jedis.get("thekey"));
- } finally {
- jedis.close();
- }
-
- }
- }
-
- //輸出結果
- 2000
- Without Pipeline takes: 183 ms.
- 2000
- With Pipeline takes: 47 ms.
結果很直觀的反映出兩者的差別,要知道這是在本地測試,幾乎不存在網絡延時的問題,如果是在不同的網段測試的話,效果會更明顯。雖然管道在一定程度上對性能有所提升,但是在使用時一點要注意,每個命令的返回結果是先被緩存在服務器端的,最后一次性返回給客戶端。如果一次批量提交涉及大量的返回結果,可能會導至服務器的內存溢出,這在生產環境是致命的,一次批次處理多少量,最好在設計階段做出合理評估。
最后,管道只是一個方案,并不意味著在任何時候都要盡可能的使用它,而是應該結合考慮網絡延遲時間、業務涉及的請求量等等因素綜合考慮,畢竟創建管道本身也會有一定的消耗。