【问题标题】:Redis notifications: Get key and value on expirationRedis 通知:在过期时获取键和值
【发布时间】:2013-08-22 02:11:44
【问题描述】:

我们有以下用例:每次某个密钥过期时,我们都需要收到通知并根据它的值做一些事情。但是当 redis 触发 expired 事件时,当我们稍后尝试访问它时,密钥已经从数据库中删除,这当然是预期的。

现在有没有办法在条目过期后再次访问它?我猜不是。

所以第二个选项:有没有办法告诉 redis 在发送这些事件时发布整个值对象,而不仅仅是键?我想它可以通过 Lua 添加,但如果可能的话,我对更简单的选项感兴趣。对于其他事件,我们也需要这种行为,我们基本上需要所有通知来发布值,而不是键(我们可以在收到事件后执行 GET,但我们希望绕过第二次调用,主要是为了有一个原子过程,因为值可能在发布事件和执行GET 检索值之间发生了变化。

希望可以理解。也许我们看不到明显的,所以提前谢谢!

【问题讨论】:

  • Redis 2.8 到目前为止仍然是一个候选版本。如果您需要控制密钥过期通知,最好显式地实现它(不依赖于 2.8)。见stackoverflow.com/questions/11810020/…
  • 那么 2.8 仍然是 RC 不是问题。问题是 Redis 使用键而不是条目的值发布事件。由于我们需要所有通知的这种行为,所以 2.6.那些,我们需要一种方法来告诉 Redis 在事件触发时给我们整个对象,而不是键。
  • 我还是会使用基于 zset 的解决方案
  • 我在 github 上创建了一个问题,因为我也需要这个功能 github.com/antirez/redis/issues/1876

标签: database events redis


【解决方案1】:

如果您使用的是 2.8,则可以试用 this new feature(也参考 this page)。它肯定是不稳定的,而且似乎没有经过很好的测试,但如果你在 2.8 上...

问题页面的简短介绍:

具有键值数据模型的数据库中的一个有趣功能(Redis 不完全符合此定义,因为值是复杂数据 结构,但是Redis的外层肯定是key-value 业务)是以某种方式订阅流的能力 针对给定键的事件。

例如,我可能有兴趣查看密钥 foo 何时被删除或 以某种方式修改,或获取所有键的名称 Redis 正在从 数据集,因为他们的生存时间降至零。

Redis 用户群多次请求此功能,但是 到目前为止,我们从未达到提议的 API(包括 我自己提出的建议)似乎很适合 Redis 设计。 此功能请求将尝试描述一种新设计,即 使用、实现非常简单,并且非常适合 Redis 故事。

【讨论】:

    【解决方案2】:

    Eli 链接到的功能允许您在密钥过期时进行监听。但是,它不会为您提供密钥的值。此外,基于filed github issue,您似乎无法期望尽快内置此功能(如果有的话)。我使用的解决方案是创建一个特殊的“影子”过期密钥,该密钥链接到您拥有实际值的密钥。

    假设您有一个名为testkey 的键,它的整数值为100。此外,密钥将在 10 秒后过期,此时您想要获取密钥的值。 (也许您在密钥存在的 10 秒内递增密钥)。

    首先您需要设置监听键空间事件。特别是您想收听expired 事件。您可以从配置中执行此操作,也可以在 redis 中使用 config set 命令。 (请参阅此处了解更多信息:http://redis.io/topics/notifications

    CONFIG SET notify-keyspace-events Ex
    

    现在您可以订阅一个特殊的keyevent 频道,您将在该频道收到密钥已过期的通知。

    SUBSCRIBE __keyevent@0__:expired
    

    订阅频道的格式为__keyevent@<db>__:<eventName>。在我们的示例中,我们假设我们正在使用默认数据库 0,并且我们想要监听 expired 事件。

    testkey 过期时,您现在将在__keyevent__ 频道中收到一条消息,其中消息是过期密钥的名称。当然,此时密钥已消失,因此我们无法再访问该值!解决方案是使用特殊的过期密钥。

    当您创建testkey 时,还要创建一个特殊的到期“影子”密钥(不要使实际的testkey 到期)。例如:

    SET testkey 100
    SET shadowkey:testkey "" EX 10
    

    现在在__keyevent@0__:expired 频道中,您将收到一条消息,告诉您密钥shadowkey:testkey 已过期。获取消息的值(即键的名称),在冒号上拆分(或您决定使用的任何分隔符),然后手动获取键的值并将其删除。

    // set your key value
    SET testkey 100 
    //set your "shadow" key, note the value here is irrelevant
    SET shadowkey:testkey "" EX 10 
    // Get an expiration message in the channel __keyevent@0__:expired
    // Split the key on ":", take the second part to get your original key
    // Then get the value and do whatever with it
    GET testkey
    // Then delete the key
    DEL testkey
    

    请注意,不使用 shadowkey 的值,因此您希望使用可能的最小值,根据此答案 (Redis store key without a value) 是一个空字符串 ""。设置需要做更多的工作,但上述系统完全可以满足您的需要。开销是一些额外的命令来实际检索和删除您的密钥以及空密钥的存储成本。

    【讨论】:

    • 好主意,尽管它确实使该价值的足迹翻了一番。一个可能的调整是仅将值存储在“影子”键中,并将实际键用于到期目的。
    • @ItamarHaber shadowkey 不存储实际值。事实上,基于这个答案 (stackoverflow.com/questions/25557250/…),影子键值应该只是一个空字符串(在我的示例中,我给它的值是“1”,但现在已经更新了它)。所以唯一的开销是额外的密钥(你不应该重复你的值)
    • 非常好的策略!
    • 有一个警告。如果您的客户端在获取事件或删除包含实际值的键之前中断,您最终将用陈旧的键污染您的 redis。对此的解决方案可能是将实际密钥设置为也过期,可能在影子密钥之后 10 秒,这样您就有时间在影子密钥过期后获取它,然后忽略非影子密钥上的事件。
    猜你喜欢
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    • 2014-12-11
    • 2020-04-19
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多