閱讀533 返回首頁    go 魔獸


管道傳輸__最佳實踐_雲數據庫 Redis 版-阿裏雲

管道傳輸(pipeline)

場景介紹

ApsaraDB for Redis 提供了與 Redis 相同的管道傳輸(pipeline)機製。管道(pipeline)將客戶端 client 與服務器端的交互明確劃分為單向的發送請求(Send Request)和接收響應(Receive Response):用戶可以將多個操作連續發給服務器,但在此期間服務器端並不對每個操作命令發送響應數據;全部請求發送完畢後用戶關閉請求,開始接收響應獲取每個操作命令的響應結果。

管道(pipeline)在某些場景下非常有用,比如有多個操作命令需要被迅速提交至服務器端,但用戶並不依賴每個操作返回的響應結果,對結果響應也無需立即獲得,那麼管道就可以用來作為優化性能的批處理工具。性能提升的原因主要是減少了 TCP 連接中交互往返的開銷。

不過在程序中使用管道請注意,使用 pipeline 時客戶端將獨占與服務器端的連接,此期間將不能進行其他“非管道”類型操作,直至 pipeline 被關閉;如果要同時執行其他操作,可以為 pipeline 操作單獨建立一個連接,將其與常規操作分離開來。

代碼示例1

性能對比

  1. package pipeline.kvstore.aliyun.com;
  2. import java.util.Date;
  3. import redis.clients.jedis.Jedis;
  4. import redis.clients.jedis.Pipeline;
  5. public class RedisPipelinePerformanceTest {
  6. static final String host = "xxxxxx.m.cnhza.kvstore.aliyuncs.com";
  7. static final int port = 6379;
  8. static final String password = "password";
  9. public static void main(String[] args) {
  10. Jedis jedis = new Jedis(host, port);
  11. //ApsaraDB for Redis的實例ID及密碼
  12. String authString = jedis.auth(password);// password
  13. if (!authString.equals("OK")) {
  14. System.err.println("AUTH Failed: " + authString);
  15. jedis.close();
  16. return;
  17. }
  18. //連續執行多次命令操作
  19. final int COUNT=5000;
  20. String key = "KVStore-Tanghan";
  21. // 1 ---不使用pipeline操作---
  22. jedis.del(key);//初始化key
  23. Date ts1 = new Date();
  24. for (int i = 0; i < COUNT; i++) {
  25. //發送一個請求,並接收一個響應(Send Request and Receive Response)
  26. jedis.incr(key);
  27. }
  28. Date ts2 = new Date();
  29. System.out.println("不用Pipeline > value為:"+jedis.get(key)+" > 操作用時:" + (ts2.getTime() - ts1.getTime())+ "ms");
  30. //2 ----對比使用pipeline操作---
  31. jedis.del(key);//初始化key
  32. Pipeline p1 = jedis.pipelined();
  33. Date ts3 = new Date();
  34. for (int i = 0; i < COUNT; i++) {
  35. //發出請求 Send Request
  36. p1.incr(key);
  37. }
  38. //接收響應 Receive Response
  39. p1.sync();
  40. Date ts4 = new Date();
  41. System.out.println("使用Pipeline > value為:"+jedis.get(key)+" > 操作用時:" + (ts4.getTime() - ts3.getTime())+ "ms");
  42. jedis.close();
  43. }
  44. }

運行結果1

在輸入了正確的 ApsaraDB for Redis 實例訪問地址和密碼之後,運行以上 Java 程序,輸出結果如下。從中可以看出使用 pipeline 的性能要快的多。

  1. 不用Pipeline > value為:5000 > 操作用時:5844ms
  2. 使用Pipeline > value為:5000 > 操作用時:78ms

代碼示例2

在 Jedis 中使用管道(pipeline)時,對於響應數據(response)的處理有兩種方式,請參考以下代碼示例。

  1. package pipeline.kvstore.aliyun.com;
  2. import java.util.List;
  3. import redis.clients.jedis.Jedis;
  4. import redis.clients.jedis.Pipeline;
  5. import redis.clients.jedis.Response;
  6. public class PipelineClientTest {
  7. static final String host = "xxxxxxxx.m.cnhza.kvstore.aliyuncs.com";
  8. static final int port = 6379;
  9. static final String password = "password";
  10. public static void main(String[] args) {
  11. Jedis jedis = new Jedis(host, port);
  12. // ApsaraDB for Redis的實例ID及密碼
  13. String authString = jedis.auth(password);// password
  14. if (!authString.equals("OK")) {
  15. System.err.println("AUTH Failed: " + authString);
  16. jedis.close();
  17. return;
  18. }
  19. String key = "KVStore-Test1";
  20. jedis.del(key);//初始化
  21. // -------- 方法1
  22. Pipeline p1 = jedis.pipelined();
  23. System.out.println("-----方法1-----");
  24. for (int i = 0; i < 5; i++) {
  25. p1.incr(key);
  26. System.out.println("Pipeline發送請求");
  27. }
  28. // 發送請求完成,開始接收響應
  29. System.out.println("發送請求完成,開始接收響應");
  30. List<Object> responses = p1.syncAndReturnAll();
  31. if (responses == null || responses.isEmpty()) {
  32. jedis.close();
  33. throw new RuntimeException("Pipeline error: 沒有接收到響應");
  34. }
  35. for (Object resp : responses) {
  36. System.out.println("Pipeline接收響應Response: " + resp.toString());
  37. }
  38. System.out.println();
  39. //-------- 方法2
  40. System.out.println("-----方法2-----");
  41. jedis.del(key);//初始化
  42. Pipeline p2 = jedis.pipelined();
  43. //需要先聲明Response
  44. Response<Long> r1 = p2.incr(key);
  45. System.out.println("Pipeline發送請求");
  46. Response<Long> r2 = p2.incr(key);
  47. System.out.println("Pipeline發送請求");
  48. Response<Long> r3 = p2.incr(key);
  49. System.out.println("Pipeline發送請求");
  50. Response<Long> r4 = p2.incr(key);
  51. System.out.println("Pipeline發送請求");
  52. Response<Long> r5 = p2.incr(key);
  53. System.out.println("Pipeline發送請求");
  54. try{
  55. r1.get(); //此時還未開始接收響應,所以此操作會出錯
  56. }catch(Exception e){
  57. System.out.println(" <<< Pipeline error:還未開始接收響應 >>> ");
  58. }
  59. // 發送請求完成,開始接收響應
  60. System.out.println("發送請求完成,開始接收響應");
  61. p2.sync();
  62. System.out.println("Pipeline接收響應Response: " + r1.get());
  63. System.out.println("Pipeline接收響應Response: " + r2.get());
  64. System.out.println("Pipeline接收響應Response: " + r3.get());
  65. System.out.println("Pipeline接收響應Response: " + r4.get());
  66. System.out.println("Pipeline接收響應Response: " + r5.get());
  67. jedis.close();
  68. }
  69. }

運行結果2

在輸入了正確的 ApsaraDB for Redis 實例訪問地址和密碼之後,運行以上 Java 程序,輸出結果如下:

  1. -----方法1-----
  2. Pipeline發送請求
  3. Pipeline發送請求
  4. Pipeline發送請求
  5. Pipeline發送請求
  6. Pipeline發送請求
  7. 發送請求完成,開始接收響應
  8. Pipeline接收響應Response: 1
  9. Pipeline接收響應Response: 2
  10. Pipeline接收響應Response: 3
  11. Pipeline接收響應Response: 4
  12. Pipeline接收響應Response: 5
  13. -----方法2-----
  14. Pipeline發送請求
  15. Pipeline發送請求
  16. Pipeline發送請求
  17. Pipeline發送請求
  18. Pipeline發送請求
  19. <<< Pipeline error:還未開始接收響應 >>>
  20. 發送請求完成,開始接收響應
  21. Pipeline接收響應Response: 1
  22. Pipeline接收響應Response: 2
  23. Pipeline接收響應Response: 3
  24. Pipeline接收響應Response: 4
  25. Pipeline接收響應Response: 5

最後更新:2016-12-16 17:25:21

  上一篇:go 消息發布與訂閱__最佳實踐_雲數據庫 Redis 版-阿裏雲
  下一篇:go 事務處理__最佳實踐_雲數據庫 Redis 版-阿裏雲