2017-02-19 16 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

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