Redis 管道是客户端将多个命令打包一次性发送给服务器,不用等到单独命令的执行结果返回;而 Redis 管理需要服务器在执行所有的命令后返回结果,所有命令发送和接收只发生一次,大大减少了多个命令单独在网络的耗时延迟。Redis 管道官方文档。
管道(pipeline)详解
Redis 是一个使用客户端/服务器模型,遵循请求/响应协议的TCP服务器,这意味着完成请求(通信过程)需要经过以下步骤:
- 客户端向服务发送一个命令。
- 服务器收到命令并将其放入执行队列(阻塞方式,因为 Redis 是单线程执行模型)。
- 命令被执行。
- 服务器将命令执行结果返回给客户端。
客户端和服务器通常需要通过网络连接,数据包从客户端经网络传输到服务器,服务器返回结果到客户端,这发送和返回的时间称为往返时延(RTT)。当客户端需要发送多个命令时(例如,将多个元素加到同一列表等),很容易看出是影响性能的。
通信过程的第1步 和 第4步 耗费的时间完全取决于客户端和服务器之间的网络延迟。若执行多条个命令,服务器执行命令的时间非常短,而网络传输可能花费更多的时间。
Redis 管道是客户端将多个命令打包一次性发送给服务器,不用等到单独命令的执行结果返回;而 Redis 管理需要服务器在执行所有的命令后返回结果,所有命令发送和接收只发生一次,大大减少了多个命令单个在网络的耗时。
管道技术是广泛使用的技术。使如,许多 POP3 协议实现已经支持此功能,大大加快了从服务器下载电子邮件的过程。Redis 从行早就开始支持管道技术,不管运行的什么版本,可理解为使用管道技术可以不考虑版本是否支持的情况。
管道技术不仅仅可以减少由于往返时间而导致的延迟成功,还大大提高了在给定 Redis 服务中每秒可执行的总操作量。这是因为,在不使用管道技术的情况下,为每个命令提供服务,需要调用系统 read()
和write()
,意味着从用户态到内核态,在多命令情况下,频繁的上下文切换需要消耗巨大的系统性能。使用管道技术,通常调用一次read()
可以读取多个命令,并调用一次write()
返回多个执行结果。使用管道技术最多可以提高10
倍的性能。
示例操作:
创建多个 Redis 命令操作的文件
$ touch pipeline.txt $ vim pipeline.txt set key1 value1 sadd key2 value21 value22 get key1 scard key2 cat pipeline.txt
转换行尾结束符
unix2dos pipeline.txt
使用
redis-cli
的--pipe
选项,通过管道发送命令$ cat pipeline.txt | /usr/local/redis/bin/redis-cli -a 123456 - -pipe Warning: Using a password with '-a' option on the command line interface may not be safe. All data transferred. Waiting for the last reply... Last reply received from server. errors: 0, replies: 4
Java 中使用Redis管道
Spring Boot 集成 Redis,使用 RedisTemplate 执行 Pipeline 操作。
/**
* @name: SaveByPipeLine
* @desc: 使用管道技术批量发送数据
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class SendByPipeLine {
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
/**
* 使用管道技术
*/
@Test
public void saveByPipeLine(){
RedisCallback<Object> redisCallback = new RedisCallback<Object>() {
//doInRedis中的redis操作不会立刻执行
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
//执行业务,打包多条命令
for (int i = 0; i < 10000; i++) {
String key = "key:" + i;
String value = "value" + i;
connection.set(key.getBytes(), value.getBytes());
// connection.get(key.getBytes());
}
//所有redis操作会在connection.closePipeline()之后一并提交到redis并执行,这是pipeline方式的优势
// List<Object> resultList = connection.closePipeline();
return null;
}
};
//所有操作的执行结果为executePipelined()的返回值
List<Object> resultList = redisTemplate.executePipelined(redisCallback, redisTemplate.getStringSerializer());
System.out.println(JSON.toJSONString(resultList));
}
}
注意:本文归作者所有,未经作者允许,不得转载