【发布时间】:2014-08-22 06:04:00
【问题描述】:
我正在尝试优化我的 Redis 代码,但我目前在扩展我的解决方案时遇到了一些困难。 Redis 托管在 Redis Cloud 上,这是 Heroku 上的应用程序,我使用 Ruby 作为我的语言。
我的 Redis 设置:
我有一系列有序集合,每个集合包含大约 1,000 个评分成员和系统中每个用户的相应集合(可以是散列、字符串、列表、集合、有序集合或任何其他结构)。
例如在 news:sports 键中,我有以下结构。其他关键示例是 news:entertainment、news:business。
news:sports -- 会员评分
StoryOID1 1000
StoryOID2 999
StoryOID3 998
StoryOID4 997
StoryOID5 996
...
对于每个主排序集 (user1:news:sports),我还有一个用户特定的键(一组),其中包含用户已经看过的故事列表。即
seen:user1:sports StoryOID2
我的挑战:
在每个用户请求中,我需要返回用户尚未看到的特定排序集中的前 3 名成员(得分最高,尽管我不需要知道分数)。我不想将结果保存在 Redis 中,因为没有长期使用,我只需要删除密钥。
鉴于上面的例子,用户 1 请求体育:新闻,我会返回:
StoryOID1
StoryOID3
StoryOID4
作为我的代码的一部分,我循环遍历 10 个排序集(10 个流派),从每个集返回前 3 个不可见的故事,每个请求总共返回 30 个 OID。
对于每个用户请求:
Do this 10 times:
ZRANGEBYSCORE top 24 members
loop user genres key using SISMEMBER until I return 3 unseen members
end
在 60 dynos (heroku) 上进行基准测试时,我只能达到 500 个同时连接(并且响应时间为 1000 毫秒),下面的 Redis 循环是瓶颈。我的目标是在当前设置上扩展几个倍数。任何东西都可以改变以扩展这个过程。
我当前的进程(在 Ruby 中):
def newslist (userOID,genres)
#pull top 24 stories for the given news:genres -- 24 could be replaced by 1,3,6,12 etc
newsscores = @@redis.zrevrangebyscore("news:#{genres}", "+inf", "-inf", :limit => [0, 24],:with_scores => true)
newsstories = Array.new(3)
i = 0 #news acceptance counter
loopcnt = 0 #loop counter
while i < 3
if newsscores.count == loopcnt - 1 #loop to the max number of news returned in news news
break #breakout of loop
end
seen = @@redis.sismember("seen:#{userOID}:#{genres}", newsscores[loopcnt][0])
if seen == false
newsstories[i] = newsscores[loopcnt][0]
i+=1
end
loopcnt += 1
end
if i==3
return newsstories #return 3 news newss
else
return 0 #return 0 -- this should cause a repick
end
return 0 #return 0 -- this should cause a repick
end
我知道我为大量的 Redis requets 付出了巨大的代价。我目前的思考过程是基本上将上述内容转换为可以在服务器端运行的 Lua 脚本,但我不禁觉得有一个更优雅的解决方案可以更好地扩展。
有没有更好的办法?
【问题讨论】:
-
你每次都打电话给 sismember 有什么原因吗?您可以在循环 IIUC 之前调用它一次。 (顺便说一句 - 感谢您使用我们的服务!)
-
挑战是不知道调用多少次。
-
我在循环中使用 sismembers,因为一旦获得前 3 个未见过的成员,我就会停止。我试图限制 puling 成员 4 -24 的 sismembers 的开销(除非需要它们)。循环的嵌入式特性和扩展到 1000 个并发请求似乎会在服务器上产生大量不需要的负载。
-
是的 - 我没有想清楚 :) 让我再考虑一下。
标签: ruby optimization heroku redis scalability