从Redis键的变化集合中查找值冲突

3
在我的网站上,允许用户使用相同的用户名。此外,当用户登录时,我会在 Redis 键中暂时保存他们的用户名,并设置 ttl 为10分钟。
问题是:有没有办法 - 使用 Redis - 找到在过去 10 分钟内在线且共享相同用户名的所有用户 ID?
目前,我正在使用 Python 提取所有键的值并查找冲突 - 这并没有真正帮助我,因为我需要在运行时多次执行此操作(而且有很多用户流量)。
我假设我可以创建以唯一用户名为键的集合,并将所有用户 ID 存储在集合中,从而使我能够 O(1) 查找共享相同用户名的用户。但是,我将不得不牺牲 10 分钟 ttl 条件(这对我每个用户名都是必需的)。
顺便说一句,我是 Redis/Lua 初学者,因此是初级问题(如果是的话)。
1个回答

1

有志者事竟成... :)

首先将登录信息存储在排序集合中。假设用户ID为123的用户在456时刻使用用户名“foo”登录,您可以这样表示:

ZADD logins 456 123:foo

注意:您还需要从排序集合中删除旧元素,以便它不会无限增长。

接下来,您想要搜索最近10分钟的用户,因此您可以使用ZRANGEBYSCORE。不要将整个内容返回给客户端,而是使用Lua进行处理并检查冲突。

以下脚本示例将上述所有内容包装在一起:

-- Keys: 1) The logins Sorted Set
-- Args: 1) The epoch value of 'now'
--       2) The logged in user id
--       3) The logged in user name         

-- Get logins from the last 10 minutes
local l = redis.call('ZRANGEBYSCORE', KEYS[1], ARGV[1]-600, '+inf')

-- "Evict" old logins
redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', '(' .. ARGV[1]-600)

-- Store the new login
redis.call('ZADD', KEYS[1], ARGV[1], ARGV[2] .. ':' .. ARGV[3])

local c = {}  -- detected name collision
for _, v in pairs(l) do
  local p = v:find(':')  -- no string.split in Lua
  local i = v:sub(1,p-1) -- id
  local n = v:sub(p+1)   -- name
  if n == ARGV[3] then
    c[#c+1] = i
  end
end

return c

太棒了!这看起来不错,终于可以让我写我的第一个合适的Lua脚本了。我想我会在本地存储一个usernames.lua文件,然后在Python中调用它。我应该使用https://labix.org/lunatic-python,还是可以像典型的py文件一样导入lua文件作为模块? - Hassan Baig
那是另一个问题,哈桑 :) 参考这个例子 - https://pypi.python.org/pypi/redis#lua-scripting - Itamar Haber
顺便问一下,如何最好地组织我的Lua脚本?创建一个单独的Python模块,将它们全部放在那里,并在需要时在我的Redis实用程序中调用它们?或者你有什么建议? - Hassan Baig
好问题 - 我没有一个有根据的答案。 - Itamar Haber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接