2017-02-19 3 views
3

In meiner Website dürfen Benutzer die gleichen Benutzernamen behalten. Darüber hinaus speichere ich zu jedem Zeitpunkt, zu dem sich ein Benutzer anmeldet, vorübergehend seinen Benutzernamen in einem Rediskey mit einer ttl von 10 Minuten.Suche nach Wertkollisionen aus einer sich ändernden Sammlung von Redis Schlüsseln

Die Frage ist: gibt es irgendeinen Weg - mit Redis - alle Benutzer-IDs online innerhalb der letzten 10 Minuten zu finden, teilen den gleichen Benutzernamen?

Derzeit extrahiere ich alle Schlüsselwerte und finde Kollisionen in Python - was nicht wirklich hilft, da ich dies zur Laufzeit mehrmals machen muss (und es gibt viel Benutzerverkehr).

Ich vermute, dass ich Sets mit einem eindeutigen Benutzernamen als Schlüssel erstellt haben könnte, und alle Benutzer-IDs im Set gespeichert, um mir O (1) Look-Ups für Benutzer mit den gleichen Benutzernamen zu geben. Aber dann müsste ich die 10 Minuten TTL-Bedingung opfern (die ich für jeden Benutzernamen einzeln benötige).

Btw Redis/Lua Anfänger hier, daher die noob Frage (wenn es ist).

Antwort

1

Wo ein Wille ist, ist auch ein Weg ... :)

Sie zunächst die Anmeldungen in einer sortierten Set speichern. Unter der Annahme, dass die Benutzer-ID 123 hatte zum Zeitpunkt 456 mit dem Benutzernamen „foo“ angemeldet sind, können Sie erklären, dass als:

ZADD logins 456 123:foo 

Hinweis: Sie werden auch alte Elemente zu entfernen, aus, die sortiert Set so es doesn nicht außer Kontrolle geraten.

Als nächstes möchten Sie nach den Benutzern der letzten 10 Minuten suchen, also würden Sie ZRANGEBYSCORE dafür verwenden. Anstatt das gesamte Produkt an Ihren Kunden zurückzusenden, verwenden Sie Lua, um es zu verarbeiten und auf Kollisionen zu prüfen.

Das folgende Skript Beispiel wickelt zusammen alle oben:

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

Cool! Das sieht gut aus und wird mich endlich dazu bringen, mein erstes richtiges Lua-Skript zu schreiben. Ich dachte mir, ich werde lokal eine 'usernames.lua' speichern und dann in Python aufrufen. Soll ich https://labix.org/lunatic-python verwenden, oder kann ich einfach die lua-Datei als ein Modul wie typische py-Dateien importieren? –

+0

Das ist eine andere Frage Hassan :) Folgen Sie diesem Beispiel - https://pypi.python.org/pypi/redis#lua-scripting –

+1

Gotcha! Wie immer, vielen Dank, dass Sie den Weg gezeigt haben. –

Verwandte Themen