我正在试图找出实现Redis流水线的最佳方法。我们使用redis作为MySQL之上的缓存来存储用户数据,产品列表等。 我将此作为起点:https://joshtronic.com/2014/06/08/how-to-pipeline-with-phpredis/
我的问题是,假设您有一组正确排序的ID。你像这样循环遍历redis管道:
$redis = new Redis();
// Opens up the pipeline
$pipe = $redis->multi(Redis::PIPELINE);
// Loops through the data and performs actions
foreach ($users as $user_id => $username)
{
// Increment the number of times the user record has been accessed
$pipe->incr('accessed:' . $user_id);
// Pulls the user record
$pipe->get('user:' . $user_id);
}
// Executes all of the commands in one shot
$users = $pipe->exec();
当$pipe->get('user:' . $user_id);
不可用时会发生什么情况,因为之前没有被请求过或被Redis驱逐等等?假设结果#15来自50,我们如何a)发现我们无法检索该对象并且b)保持用户数组正确排序?
谢谢
答案 0 :(得分:2)
我将回答有关Redis协议的问题。在这种情况下,它在特定语言中的工作方式或多或少相同。
首先,让我们看一下Redis管道的工作原理: 它只是一种向服务器发送多个命令,执行它们并获得多个回复的方法。没有什么特别之处,您只需获得一个数组,其中包含管道中每个命令的回复。
为什么流水线要快得多是因为保存了每个命令的往返时间,即100个命令只有一个往返时间而不是100个。此外,Redis同步执行每个命令。执行100个命令需要潜在100次,因为Redis选择那个单一命令,管道被视为一个长命令,因此只需要等待一次同步选择。
您可以在此处详细了解管道传输:https://redis.io/topics/pipelining。还有一点需要注意,因为每个流水线批处理都是不间断运行的(就Redis而言),以可浏览的块发送这些命令是有意义的,即不要在单个管道中发送100k命令,这可能会长时间阻塞Redis,将它们分成1k或10k命令的块。
在你的情况下,你在循环中运行以下片段:
// Increment the number of times the user record has been accessed
$pipe->incr('accessed:' . $user_id);
// Pulls the user record
$pipe->get('user:' . $user_id);
问题是投入管道的是什么?假设您要将u1
,u2
,u3
,u4
的数据更新为用户ID。因此,具有Redis命令的管道将如下所示:
INCR accessed:u1
GET user:u1
INCR accessed:u2
GET user:u2
INCR accessed:u3
GET user:u3
INCR accessed:u4
GET user:u4
让我们说:
在这种情况下,结果将是Redis回复的数组:
101
u1 string data stored at user:u1
6
u2 string data stored at user:u2
1
u3 string data stored at user:u3
1
NIL
如您所见,Redis会将缺失的INCR值视为0
并执行incr(0)
。最后,Redis没有对任何内容进行排序,结果将根据要求提供给oder。
语言绑定,例如Redis驱动程序将只解析该协议并为解析数据提供视图。在不保留命令的情况下,Redis驱动程序无法正常工作,并且作为程序员可以推断出smth。请注意,该请求不会在回复中重复,即您在执行u1
时不会收到u2
或GET
的密钥,而只会收到该密钥的数据。因此,您的实现必须记住位置1
(基于零的索引)是GET
u1
的结果。