在我的网站中,允许用户保留相同的用户名。此外,在用户登录的任何时间点,我暂时将其用户名保存在一个redis密钥中,其中ttl
为10分钟。
问题是:有没有办法 - 使用Redis - 在过去10分钟内在线查找所有用户ID,共享相同的用户名?
目前,我正在提取所有键的值并在Python中查找冲突 - 这实际上并没有帮助,因为我需要在运行时多次执行此操作(并且有大量用户流量)。
我假设我可以使用唯一的用户名创建集合作为密钥,并将所有用户ID存储在集合中,以便对共享相同用户名的用户进行O(1)查找。但是,我必须牺牲10分钟ttl条件(我需要为每个用户名单独)。
Btw Redis / Lua初学者在这里,因此noob问题(如果是)。
答案 0 :(得分: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