RTT
在上篇文章中说过,Redis 客户端执行一条命令分为如下 4 个部分:
其中 1~4 所消耗的时间称为 Round Trip Time (RTT,往返时间),也就是数据在网络上传输的时间。
Redis 提供了批量操作命令(例如 mget、mset 等),有效地节约 RTT。但大部分命令是不支持批量操作的,例如要执行 n 次 hgetall 命令,并没有 mhgetall 命令存在,需要消耗 n 次 RTT。
Redis 的客户端和服务端可能部署在不同的机器上。 例如客户端在本地,Redis 服务器在阿里云的广州,两地直线距离约为 800 公里,那么 1 次 RTT 时间=800 x2/ ( 300000×2/3 ) =8 毫秒,(光在真空中传输速度为每秒 30 万公里,这里假设光纤为光速的 2/3 ),那么客户端在 1 秒内大约只能执行 125 次左右的命令,这个和 Redis 的高并发高吞吐特性背道而驰。
pipeline 机制
而 pipeline
机制能改善上面这类问题,它能将一组 Redis 命令进行组装,通过一次 RTT 传输给 Redis,再将这组 Redis 命令的执行结果按顺序返回给客户端,没有使用 pipeline
执行了 n 条命令,整个过程需要 n 次 RTT。如下:
如果使用 pipeline
执行了 n 次命令,整个过程需要 1 次 RTT。如下:
pipeline
并不是什么新的技术或机制,很多技术上都使用过。而且 RTT 在不同网络环境下会有不同,例如同机房和同机器会比较快,跨机房跨地区会比较慢。
Redis 命令真正执行的时间通常在微秒级别,所以才会有 Redis 性能瓶颈是网络这样的说法。
性能对比
测试需求:
向 Redis 中写入 1000 次字符类型,通过非
pipeline
和pipeline
的方式对比耗时。
通过 Jedis 客户端来连接 Redis。
properties
基于 SpringConfig 的配置
非 pipeline
测试结果:
非pipeline操作1000次字符串数据类型set写入,耗时:5901毫秒
pipeline
Jedis 客户端中有一个 **Pipeline **类用来支持批量操作。
测试结果:
pipeline操作1000次字符串数据类型set写入,耗时:36毫秒
总结
通过上面的测试可以得到如下两个结论:
- Pipeline 执行速度一般比逐条执行要快。
- 客户端和服务端的网络延时越大,Pipeline 的效果越明显。
Pipeline 虽然好用,但是每次 Pipeline 组装的命令个数不能没有节制,否则一次组装 Pipeline 数据量过大,一方面会增加客户端的等待时间,另一方面会造成一定的网络阻塞,可以将一次包含大量命令的 Pipeline 拆分成多次较小的 Pipeline 来完成,比如可以将 Pipeline 的总发送大小控制在内核输入输出缓冲区大小之内或者控制在 TCP 包的大小 1460 字节之内。
同时 Pipeline 只能操作一个 Redis 实例,但是即使在分布式 Redis 场景中,也可以作为批量操作的重要优化手段。