caching - Redis 管道,处理缓存未命中

标签 caching redis pipelining

我正在尝试找出实现 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);

问题是将什么放入管道?假设您要将 u1u2u3u4 的数据更新为用户 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 时不会收到 u1u2 的 key ,而只是该 key 的数据。因此,您的实现必须记住,1 位置(从零开始的索引)是 u1GET 的结果。

关于caching - Redis 管道,处理缓存未命中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44287954/

相关文章:

rxjs - RxJS v5+ 中的 `Observable.transduce` 发生了什么?

http - HTTP/1.1 流水线和 HTTP/2 多路复用有什么区别?

JavaScript 同步选项

使用 Spring Boot 进行缓存 - Redis 键名中的 ~keys 是什么?

适用于 Windows 的 Redis 哨兵

node.js - 为什么我看到一个新的 sess : key in redis on every request?

c - 基本指令如何并行运行

redirect - 带有缓存响应 header 的 IIS 重定向

php - 高效的 PHP 缓存策略?

java访问redis抛出java.util.NoSuchElementException : Unable to validate object