Redis管道技术

Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务,无论是发出请求还是接收响应,都必须经过网络传输。在tcp连接过程中,客户端和服务器端是通过阻塞式的一问一答方式进行通信的,即客户端必须接收到服务端完整的响应,才能进行后续请求。

有时我们会在短时间内发送大量互不依赖的命令(例如:后执行的命令不需要使用前面返回的结果)。由于网络传输不可避免的会造成一定的延迟,特别是在跨机器远程访问redis的时候,如果使用常规的方式,一条命令对应一次请求和响应的话,大量命令累计的延迟会显得很高。redis的设计者考虑到这一点,在底层的通信协议上,通过支持”管道(pipeline)“来解决这一问题。

普通命令:3次请求/响应

1
2
3
4
5
6
client:INCR num001;
server:1;
client:INCR num001;
server:2;
client:INCR num001;
server:3;

Redis管道

管道命令:1次请求/响应

1
2
3
4
5
6
client:INCR num001;
client:INCR num001;
client:INCR num001;
server:1;
server:2;
server:3;

Redis管道

实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$redis = new Redis();

$redis->connect('127.0.0.1',6379);

// Redis::MULTI或Redis::PIPELINE. 默认是 Redis::MULTI
// Redis::MULTI:将多个操作当成一个事务执行
// Redis::PIPELINE:让(多条)执行命令简单的,更加快速的发送给服务器,但是没有任何原子性的保证
$pipe = $redis->multi(Redis::PIPELINE);
for ($i = 0; $i < 10000; $i++) {
// $pipe->set("key::$i", $i);
// $pipe->get("key::$i");
$pipe->del("key::$i");
}

$replies = $pipe->exec();
print_r($replies);

注意事项

  • 由于Redis的管道要求服务器一次性的将请求返回,因此redis服务端只能将靠前命令处理的结果暂时缓存起来。如果管道一次响应的数据量过多(大规模查询之类的),可能会对redis服务器的内存造成较大的压力。因此,管道批量处理的命令数量并不是越多越好,需要结合实际需求,合理的决定一次管道批处理命令的数量。
  • Redis的管道在客户端通常会设置一个命令缓冲区来存储即将被批量发送的命令,当缓冲区被填满时,才会一次性的将缓冲区的命令发送。这里需要注意的一点是:当业务上的同一批命令使用管道进行请求时,如果最后剩余的命令无法填满缓冲区,如果不使用相应的flush操作,这些命令将不会被发送出去,而是保留在命令缓冲区等待新的命令来填满缓冲区。

适用场景

在批量操作无因果关联的多命令(set/get)时,我们通过减少网络交互来提升效率,这时可以使用管道实现。

有用就打赏一下作者吧!