阅读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 版-阿里云