1. 问题

redis的multi相信很多同学用过,先看下面的代码。

<?php
$redis = new Redis();
$host = "10.136.30.144";
$port = "7777";$redis->connect($host, $port);
$multi = $redis->multi();
for ($i=0; $i<5; $i++){$multi->incr("x");
}$res = $redis->exec();
var_dump($res);

代码对x执行了5次incr操作,输出结果也很容易理解

array(5) {[0]=>int(1)[1]=>int(2)[2]=>int(3)[3]=>int(4)[4]=>int(5)
}

问题来了
1. 这5次incr命令是一起发给redis的么?
2. 服务端是一次返回所有结果还是分5次返回?
3. 整个过程客户端除了发送incr命令外是否还发送了其它命令?

如果你对上面几个问题的答案不是很确定,那么不妨继续往下读。

2. 回答

要解答上面的问题,最方便的办法是~抓个包。
在客户端机器上执行

tcpdump port 7777 -n -s 1024 -i eth0 -w multi.dump

结果如下:

整个过程一共有22个tcp包,耗时0.013s其中:
- 4包向服务端发MULTI指令
- 6包服务端回复OK
- 8包向服务端发送INCR
- 9包服务端返回QUEUED
- 10-17包内容与8-9一样,是循环执行的过程
- 18包向服务端发送EXEC
- 19包返回执行结果

现在我们可以回答上面的问题了
1. 5次incr命令是单独发给服务端的,每发送服务端都要回复QUEUED
2. 服务端将执行结果打包一次返回给了客户端
3. 除了INCR,客户端还额外发送了MULTI和EXEC指令。

3. 对比

如果使用普通方式,串行执行5个INCR会怎么样呢?
我们将代码调整为

<?php
$redis = new Redis();
$host = "10.136.30.144";
$port = "7777";$redis->connect($host, $port);for ($i=0; $i<5; $i++){$res = $redis->incr("x");var_dump($res);
}

重新抓包,结果如下:

18个数据包,0.0076s完成,比MULTI方式略少。

4. 如何更高效

有没有方法将所有想执行的命令一次打包发给redis服务端,使得整个执行过程更高效呢(节省网络交互时间)?答案是肯定的。
multi有个可选参数,默认值是使用Redis::MULTI。将参数值设为Redis::PIPELINE即可解决问题。
将上1中的代码改动一行。

$multi = $redis->multi(Redis::PIPELINE);

重新抓包,结果如下:

整个过程一共有10个tcp包,其中:
- 4包向服务端打包发送所有INCR指令
- 6包返回执行结果

再对比下执行时间,由于PIPELINE方式网络交互少,从抓包图上看,整个过程只要0.0036s,只有2中的MULTI方式(0.013s)的28%!,2中普通串行方式(0.076s)的47%。

5. 更进一步

  • PIPE方式,对打包的命令条数有限制么?

我们将上面的循环次数改为500次,也就是将500条INCR一下发给redis,也可以正常运行。唯一不同的是,受限于TCP包大小,500条INCR被拆成了2个数据包发给redis服务端,服务端返回的数据也同样由于包大小的限制,被拆成了3个数据包。所以,可以认为PIPE对打包命令的条数没有限制。

6.如何选择

  • Redis::MULTI方式会将命令逐条发给redis服务端。只有在需要使用事物时才选择Redis::MULTI方式,它可以保证发给redis的一系列命令以原子方式执行。但效率相应也是最低的。
  • Redis::PIPELINE方式,可以将一系列命令打包发给redis服务端。如果只是为了一下执行多条redis命令,无需事物和原子性,那么应该选用Redis::PIPELINE方式。代码的性能会有大幅度提升!

redis的MULTI与PIPELINE相关推荐

  1. redis中multi和pipeline区别以及效率(推荐使用pipeline)

    手册得知 pipeline 只是把多个redis指令一起发出去,redis并没有保证这些指定的执行是原子的:multi相当于一个redis的transaction的,保证整个操作的原子性,避免由于中途 ...

  2. redis中的multi和pipeline

    事务块 multi redis中的 multi 方法,提供了一个队列用于缓存多个指令,在客户端调用 exec 后将该队列中的指令批量执行,执行过程中不会被其他指令干扰(具有原子性). 客户端每发送一个 ...

  3. Redis的Multi的内幕真相

    今天遇到个Redis奇慢的问题,断点分析发现跟multi有关. 由于本人太忙不想去阅读Redis Server的源代码(其实是懒),就通过TCPDump来分析吧. 步骤: 1. 先在Redis Ser ...

  4. Python中使用Redis的批处理工具pipeline(这种方法从底层思考效率还是低于“订阅发布机制”)

    一.pipeline出现的原因 1.Redis执行命令的过程 redis客户端执行一条命令的过程: 发送命令-〉命令排队-〉命令执行-〉返回结果 使用python给redis发送命令时的过程: 客户端 ...

  5. redis的批量操作命令pipeline(PHP实现)

    redis执行一条命令有四个过程:发送命令.命令排队.命令执行.返回结果:整个过程是一个往返时间(RTT).如果有n条命令,就会消耗n次RTT.Redis的客户端和服务端可能部署在不同的机器上.在两地 ...

  6. --Redis入坑--RedisPipelineException:Pipeline contained one or more invalid commands;WRONGTYPE ...

    异常说明 最近在写代码的时候,redis报了如下错误: org.springframework.data.redis.connection.RedisPipelineException: Pipeli ...

  7. Nodejs redis客户端multi命令批量操作

    multi支持所有client支持的命令,如multi.set将set命令参数(包括回调函数)加入命令队列,由multi.exec最终执行命令队列并依次调用队列中的回调函数,最后再调用multi.ex ...

  8. redis 使用redisTemplate使用PipeLine方式 利用lRange 批量获取队列内容并移除当前获取的消息

    Redis基础配置 配置解析方式,泛型类自动转换更加方便 private RedisTemplate redisTemplate;private RedisSerializer<String&g ...

  9. Redis事务Multi介绍

    Redis事务 Redis的事务是通过multi.exec.discard和watch这四个命令来完成的. Redis的单个命令都是原子性的,所以这里需要确保事务性的对象是命令集合. Redis将命令 ...

最新文章

  1. 英特尔将进行重大业务重组
  2. 拦截器 java_在Java后端如何添加拦截器
  3. 启明云端分享|乐鑫ESP32-WROOM-32E和ESP32-WROOM-32UE两款模组的区别
  4. Oracle 外连接和 (+)号的用法
  5. 前端学习(3124):react-hello-react之props的简写
  6. java国际规范标准,国际化 - Java Servlet 3.1 规范
  7. lombok在IntelliJ IDEA下的使用
  8. bootstraptable导出excel独立使用_JavaWeb系列之-一小时搞定POI导出Excel
  9. MySQL中with rollup的用法
  10. 判断点是否在三角形内
  11. 崩溃!还未修复的 Bug,凌晨三点遭到黑客 DDoS 攻击 | 技术头条
  12. unix--Tripwire 应用
  13. word把选择答案弄到题目里_怎样将word中后面的答案和题目合并到一起 - 卡饭网...
  14. 顺丰同城赴港IPO 有望凭借高增速和生态布局成为第三方即时配送平台第一股
  15. 机器学习:AI数据集划分(训练集、验证集、测试集)
  16. html中如何淡化背景图片,Word2010如何去除图片背景
  17. 【计算机体系结构量化与研究方法笔记】
  18. cad图纸打印出来更高效的方法介绍
  19. android APP开发时,全屏手机适配的问题解决
  20. 【晒出你的第83行代码】《阿里巴巴Java开发手册》主要作者孤尽晒出入职第一年的代码...

热门文章

  1. 不用找,你想要的游戏3d纹理图片素材都在这里
  2. Python量化交易平台开发教程系列3-vn.py项目中API封装的编译
  3. 忽然看到自己十年前发的关于转计算机专业的帖子
  4. 山西经济林栽培技术之形考作业三
  5. HDU3527(杭电)spy问题
  6. 【java】剑指offer46_把数字翻译成字符串
  7. 弹性云服务器的规格系列,新睿云简析云服务器的配置规格怎么选择?
  8. laravel mysql超时时间_Laravel数据库MySQL查询需要很长时间
  9. 人工智能之python打卡学习100天计划-day11
  10. 强大的矩阵奇异值分解(SVD)及其应用