Redis数据类型最适合以下示例

时间:2016-07-15 18:18:59

标签: redis node-redis

我有以下情况:

  1. 获取数字数组(来自REDIS) 有条件地
  2. 对于每个号码,请执行一些异步内容(根据号码从DB中获取内容)
  3. 对于DB中的结果集中的每一件事做另一个异步的东西
  4. 定期重复1. 2. 3.,因为新的数字将不断添加到REDIS结构中。这些数字代表unix时间戳(以毫秒为单位),因此开箱即用的数字将始终按照添加的时间进行排序

    有条件地表示从REDIS获取那些小于或等于当前unix时间戳的unix时间戳,以毫秒为单位(Date.now()

    问题是REDIS数据类型最适合此用例的情况,因为此代码将扩展到N个实例,因此N个实例将共享对单个REDIS实例的访问。为了平均分担负载,每个实例将读取例如来自REDIS的第一个(最旧的)5个数字。 数字是唯一的(添加相同的数字应该无声地失败)所以REDIS SET似乎是一个不错的选择,但是从REDIS集中读取M个第一个元素似乎是不可能的。

    为了防止两个不同的代码实例读取相同的数字,REDIS读取操作应该是原子的,它应该读取数字并删除它们。如果任何异步操作在特定号码(steps 2. and 3.)上失败,则应再次将数字添加到REDIS以便再次处理。它们应该重新添加到头部而不是最后,以便尽快再次处理。据我所知SADD会将它推到尾部。

    SMEMBERS key会阅读所有内容,它对我来说就像是一把锤子。我需要包含一些应用程序逻辑来获得前五个,而不是检查什么小于或等于Date.now(),然后删除它们并以单个事务包装某些东西。除此之外,基数可能很大 SSCAN听起来很有趣,但我不知道它如何在如上所述的“缩放”环境中工作。除此之外,根据REDIS文档:SCAN系列命令仅对返回的元素提供有限的保证,因为我们递增迭代的集合可以在迭代过程中改变。如上所述,收藏将经常更改

1 个答案:

答案 0 :(得分:2)

更合适的数据结构是排序集 - 成员具有非常适合存储时间戳的浮点数,您可以执行范围搜索(即任何小于或等于给定值的搜索)。

相关的起点是ZADDZRANGEBYSCOREZREMRANGEBYSCORE命令。

为确保readingremoving成员的原子性,您可以选择以下选项:Redis transactionsRedis Lua script以及下一个版本(v4)a Redis module

Transactions

使用事务只是意味着在您的实例上运行以下代码:

MULTI
ZRANGEBYSCORE <keyname> -inf <now-timestamp>
ZREMRANGEBYSCORE <keyname> -inf <now-timestamp>
EXEC

<keyname>是您的密钥名称,<now-timestamp>是当前时间。

Lua script

Lua脚本可以缓存并运行嵌入在服务器中,因此在某些情况下,这是一种更好的方法。如果您需要流量控制,它绝对是原子逻辑短片段的最佳方法(请记住,MULTI事务仅在执行后返回值)。这样的脚本如下所示:

local r = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
return r

要运行此功能,请先使用SCRIPT LOAD对其进行缓存,然后使用EVALSHA调用它,如下所示:

EVALSHA <script-sha> 1 <key-name> <now-timestamp>

<script-sha>SCRIPT LOAD返回的脚本的sha1。

Redis modules

在不久的将来,一旦v4成为GA,您就能够编写和使用模块。一旦这成为现实,您将能够使用我们提供ZPOP命令的模块,并且可以扩展以涵盖此用例。