❝一次性打包发送多条指令,节省往返时间
❞
requset/response 和 RTT
redis采用TCP client-server 模式通信,redis客户发送命令请求后会阻塞,直到拿到响应结果。
从request到response回来中间的网络通信时间称之为 往返时间 RTT(Round Trip Time),可能会因为客户端和服务端中间的网络节点特别多而在网络传输上浪费太多时间
场景A:假如一个redis服务器每秒能处理10万个命令(极限速度),RTT为250ms,因受限于RTT,服务器一分钟也就只能处理4个请求,若一个请求只包含一条命令,服务器将会处于空闲状态。客户端急不可耐的想要发送更多命令而受限于RTT,服务端却一直处于空闲状态 ~~~
Redis Pipelining 管道
批量命令发送,redis收到请求后挨个处理命令,并把每个命令的结果放到内存中的队列里,一次性返回队列中的响应
批量命令的数量要调整好, 太大了会导致redis要消耗过多内存来存储响应数据,太小了则会浪费过多RTT。
如果使用了Pipelining ,场景A中服务端每秒处理的命令数可以轻松饱和到10万。甚至会超过10万的极限,这怎么可能?
Pipelining可以提升服务端处理命令的极限速度?
几句话总结官方文档:批量命令时可以减少redis服务端系统调用read()和write()的次数,减少到1次,减少内核区(网卡)和用户区(redis主存)间读写scoket I/O。若不使用pipelining,每条命令都会发生系统调用。
一次pipeline只会发生一次系统调用read(),批量命令执行完又会发生一次write()把执行结果写到内核区(网卡那里,因为命令的响应结果要发送给客户端啦~)
先抛开RTT不谈,单从redis服务端执行读写命令的速度来讲,即服务端一直有连续不断的执行不完的命令需要处理,这种情况下使用pipeline的命令处理速度是不使用pipeline的10倍(官方基准测试结果)。当然倍数取决于批量命令的个数。见下图

- 横轴是pipeline命令的个数
- 纵轴是服务端读写命令执行速度
1e+06是100000的十倍
pipeline Vs lua脚本
脚本可以read, compute, write 大部分情况下脚本可以代替pipeline,
pipeline有一个明显不足是: 无法计算,必须先读取到客户端,由应用程序计算,然后再写回服务端。
当然可以在pipeline中发送EVAL or EVALSHA命令
附录: 为什么loopback接口也很慢?
loopback接口可以理解为localhost
换句话问:基准测试时,为什么在同一台服务器启动redis-cli和redis-server ,用cli循环发送下面的命令给server也很慢?
伪代码
FOR-ONE-SECOND:
Redis.SET("foo","bar")
END
redis进程和基准测试脚本跑在同一个环境中,难道不就是把消息(命令)在内存中拷到另外一个地方吗,中间不需要任何网络传输吧?
实际上啊,基准测试发送的命令,是放到了loopback接口的buffer中的,redis-server要想获取它,必须通过系统调用,系统调用都是阻塞的。实际上啊,这仍然会存在类似网络的延迟,因为系统内核的调度会来负责是基准测试的运行还是redis-server的运行,redis-servier想要发出系统调用首先要被内核调度执行。