例如,我有1万名用户在玩游戏。每个用户每小时可以在游戏中赢得或失去分数几次(可能是100或1000)次。
我需要按最近1小时的点数显示前10名用户。顶部列表应每分钟更新一次。
因此,我每次赢或输都需要存储和更新60个(一小时内的分钟数)zset。旧的zset将在到期前自动删除。
另一种方法是将用户点数按分钟存储在hset中(每次获胜或输掉仅一个hincrby),然后每分钟使用此数据重新计算zset的值。在这种情况下,我应该每分钟使用10000个hkey,删除每个键中的旧数据(大于一小时),对其他数据求和,并创建新的zset进行显示。
我不喜欢这两种情况,因为用户数量可能会增加几倍,或者将来还会增加其他顶部。
可以在Redis中实现另一种方式吗?
最佳答案
要点是您如何定义“最后一小时”。与“过去60分钟”相比,使用“时钟小时”进行操作要简单得多。我将解释简单的时钟时间
您可以将HINCRBY与负数一起使用。因此,如果我对您的理解正确,则应该每小时可以有一个哈希值,并且可以自动删除旧时间。
用户完成游戏后,您可以执行以下操作:
HINCR“排行榜:小时数”用户标识
这将为您提供在该小时内获得或失去的积分。例如,现在要获得前十名,您需要走HGETALL路线将其全部拉回并在客户端进行排序。
要利用缓存方面,您可以将生成的“前X个”用户/点值存储在每N分钟过期的键中(例如,将其存储为JSON)。这样,显示排名的过程将拉出该键并显示(如果找到),否则生成/存储/显示结果。作为上述替代方法或补充,您可以进行计划的作业,该作业计算并存储结果以供每分钟显示。
因为用户有可能(即使很少见)获得相同的净积分变化,所以我不会选择一个以总分作为分数的排序集。
要在滚动窗口中执行此操作,您可以按照上述每分钟散列的方式进行操作,而不是按小时进行操作(也许是排行榜:minutenumber),并在计算方面确定您现在的分钟数并在管道中的前60分钟哈希值上执行HGETALL。当然,请将每分钟的哈希值设置为60后过期以保持较低的使用率。
这样做意味着您要计算密钥而不是查询密钥。
我怀疑您也可以使用Lua脚本来执行摘要方面,但是随着客户端的增长和对其的调用的增加,在客户端上进行这些计算的水平扩展性将更高。
关于redis - 如何使用zsets在Redis之上实现用户,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28221168/