2017-02-19 78 views
3

在我的网站中,用户可以保留相同的用户名。而且,在用户登录的任何时间点,我暂时将他们的用户名保存在具有10分钟的ttl的Redis密钥中。从不断变化的Redis密钥集合中查找值冲突

问题是:是否有任何方法 - 使用Redis - 在最近10分钟内在线查找所有用户ID,共享相同的用户名?

目前,我正在提取所有键的值并在Python中查找冲突 - 这并没有真正的帮助,因为我需要在运行时多次执行此操作(并且存在大量用户流量)。

我推测我可以用一个唯一的用户名作为关键字创建集合,并将所有用户标识符存储在集合中,以便为共享相同用户名的用户提供O(1)查找功能。但是,然后,我不得不牺牲10分钟ttl条件(我需要为每个用户名单独)。

btw Redis/Lua初学者在这里,因此noob问题(如果是)。

回答

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 
+0

酷!这看起来不错,最终会让我写我的第一个适当的Lua脚本。我想我会在本地存储'usernames.lua',然后在python中调用它。我应该使用https://labix.org/lunatic-python,还是只能像典型的py文件那样将lua文件导入为模块? –

+0

这是另一个问题哈桑:)按照这个例子 - https://pypi.python.org/pypi/redis#lua-scripting –

+1

嘿!一如既往,感谢您展示道路。 –