【问题标题】:Redis: fan out news feeds in list or sorted set?Redis:在列表或排序集中扇出新闻提要?
【发布时间】:2014-04-18 00:18:04
【问题描述】:

我正在通过以下方式使用 Redis 缓存扇出新闻提要:

每个提要活动都是一个键/值,例如 activity:id,其中值是数据的 JSON 字符串。

当前每个新闻提要都是一个列表,键是 feed:user:user_id 并且列表包含相关活动的键。

检索我使用的新闻提要,例如:'sort feed:user:user_id by nosort get * limit 0 40'

我正在考虑将提要更改为排序集,其中分数是活动的时间戳,这样提要始终按时间排序。

我读过http://arindam.quora.com/Redis-sorted-sets-and-lists-Pertaining-to-Newsfeed,它推荐使用列表,因为排序集的时间复杂度,但通过继续使用列表,我必须注意插入顺序, 插入过去的故事需要遍历列表并找到要推送的正确索引。 (这可能会在分布式环境中导致新问题)。

我应该继续使用列表还是使用排序集?

有没有办法从排序集中立即检索新闻提要(例如使用 sort ... get * 命令来获取列表)还是必须是 zrange 然后遍历结果并获取每个值?

【问题讨论】:

    标签: redis


    【解决方案1】:

    是的,排序集非常快速且强大。它们似乎比SORT 操作更符合您的要求。时间复杂度经常被误解。 O(log(N)) 非常快,并且可以很好地扩展。我们将它用于一个排序集中的数千万成员。检索和插入是亚毫秒级的。

    使用ZRANGEBYSCORE key min max WITHSCORES [LIMIT offset count] 获取结果。

    根据您将时间戳存储为“分数”的方式,ZREVRANGEBYSCORE 可能会更好。

    关于时间戳的一点说明:不需要小数部分的排序集 SCORES 应该使用 15 位或更少。所以SCORE 必须保持在 -999999999999999 到 999999999999999 的范围内。注意:存在这些限制是因为 Redis 服务器实际上在内部将分数(浮点数)存储为 redis 字符串表示形式。

    因此,我推荐这种格式,将其转换为 Zulu Time: -20140313122802 以获得第二精度。您可以为 100 毫秒精度添加 1 位数字,但 如果 您不希望精度损失更多。顺便说一句,它仍然是 float64,因此在某些情况下精度损失可能没问题,但您的情况符合“完美精度”范围,所以我建议这样做。

    如果您的数据在 10 年内到期,您还可以跳过前三位(CCY of CCYY),以达到 .0001 秒的精度。

    我在这里建议负分,因此您可以使用更简单的ZRANGEBYSCORE 而不是REV。您可以使用 -inf 作为起始分数(负无穷大)并使用LIMIT 0 100 来获得前 100 个结果。

    两个排序集members(或'keys',但这是不明确的,因为排序集本身也是一个键)可能共享一个score,没问题,结果在一个相同的score 按字母顺序排列。

    希望这有帮助,TW

    聊天后编辑

    OP 想要从不同的键(GET/SETHGET/HSET 键)收集数据(使用 ZSET)。 JOIN 可以为你做到这一点,ZRANGEBYSCORE 不能。 这样做的首选方式是一个简单的 Lua 脚本。 Lua 脚本在服务器上执行。在下面的示例中,为了简单起见,我使用EVAL,在生产中您将使用SCRIPT EXISTSSCRIPT LOADEVALSHA。大多数客户端库都内置了一些记账逻辑,因此您不必每次都上传脚本。

    这是example.lua

    local r={}
    local zkey=KEYS[1]
    local a=redis.call('zrangebyscore', zkey, KEYS[2], KEYS[3], 'withscores', 'limit', 0, KEYS[4])
    for i=1,#a,2 do
      r[i]=a[i+1]
      r[i+1]=redis.call('get', a[i])
    end
    return r
    

    你像这样使用它(原始示例,不是为性能而编码)

    redis-cli -p 14322 set activity:1 act1JSON
    redis-cli -p 14322 set activity:2 act2JSON
    redis-cli -p 14322 zadd feed 1 activity:1
    redis-cli -p 14322 zadd feed 2 activity:2 
    
    redis-cli -p 14322 eval '$(cat example.lua)' 4 feed '-inf' '+inf' 100
    

    结果:

    1) "1"
    2) "act1JSON"
    3) "2"
    4) "act2JSON"
    

    【讨论】:

    • 我使用 UNIX 时间戳(10 位数字)作为分数。我可以直接从排序集中获取提要吗?有了一个列表,我可以做 `sort feed by nosort get *....'
    • 当然可以。 10 位数小于 15。顺便说一下,我在 big-O 上的帖子中添加了一些额外信息。
    • 感谢您的详细解答,如何直接获取Feed? (实际活动的价值,而不仅仅是它们的键)。 'ZRANGE' 将返回带或不带分数的键..
    • ZRANGEBYSCORE 也返回密钥。如果您使用 WITHSCORES,它还会返回您的时间戳。这在分页时很有用,因为 LIMIT OFFSET 的性能损失很小(如果您进入千分之十)。如果要从 ZSET 指向 HSET:使用简单的 Lua 脚本在服务器端聚合结果。
    • 我的问题是:排序后的集合包含活动的键,例如活动:1,活动:2,...每个活动的分数是时间戳。有没有一种方法可以通过 sorted set 直接获取活动的内容?或者我需要使用“ZRANGE”然后遍历结果并获得每一个?使用“排序”命令可以使用列表..
    猜你喜欢
    • 2017-12-19
    • 2018-09-15
    • 1970-01-01
    • 2013-05-14
    • 2017-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多