我正在尝试找出实现 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 等驱逐?假设它是 50 的结果 #13,我们如何 a) 发现我们无法检索该对象以及 b) 保持用户数组正确排序?
谢谢
最佳答案
我将回答有关 Redis 协议(protocol)的问题。在这种情况下,它在特定语言中的工作方式或多或少是相同的。
首先,让我们检查一下 Redis 管道是如何工作的: 它只是一种向服务器发送多个命令、执行它们并获得多个回复的方法。没有什么特别的,您只是得到一个数组,其中包含管道中每个命令的回复。
管道之所以快得多,是因为节省了每个命令的往返时间,即对于 100 个命令,只有一个往返时间,而不是 100 个。此外,Redis 同步执行每个命令。执行 100 个命令可能需要战斗 100 次,Redis 会选择单个命令,管道被视为一个长命令,因此只需要一次等待被同步选择。
您可以在此处阅读有关流水线的更多信息:https://redis.io/topics/pipelining .还有一点要注意,因为每个流水线批处理都运行不间断(就 Redis 而言),所以以可概览的 block 发送这些命令是有意义的,即不要在单个流水线中发送 100k 命令,这可能会长时间阻塞 Redis,将它们分成 1k 或 10k 命令 block 。
在您的情况下,您在循环中运行以下片段:
// 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
假设:
- u1 之前被访问过 100 次,
- u2 之前被访问过 5 次,
- u3 之前没有被访问过并且
- 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 没有对任何内容进行排序,结果将按要求按顺序出现。
语言绑定(bind),例如Redis 驱动程序将为您解析该协议(protocol)并提供已解析数据的 View 。如果不保持命令的顺序,Redis 驱动程序将无法正常工作,并且作为程序员的您无法推断出 smth。请记住,该请求不会在回复中重复,即您在执行 GET
时不会收到 u1
或 u2
的 key ,而只是该 key 的数据。因此,您的实现必须记住,1
位置(从零开始的索引)是 u1
的 GET
的结果。
关于caching - Redis 管道,处理缓存未命中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44287954/