从不断变化的 Redis 键集合中查找值冲突
Finding value collisions from a changing collection of Redis keys
在我的网站上,允许用户保留相同的用户名。此外,在用户登录的任何时间点,我都会将他们的用户名临时保存在一个 ttl
为 10 分钟的 redis 密钥中。
问题是:有没有办法 - 使用 Redis - 查找最近 10 分钟内在线的所有用户 ID,共享相同的用户名?
目前,我正在提取所有键的值并在 Python 中查找冲突 - 这并没有真正帮助,因为我需要在运行时多次执行此操作(并且有很多用户流量) .
我假设我可以使用唯一的用户名作为键来创建集合,并将所有用户 ID 存储在集合中,以便为我提供 O(1) 查找共享相同用户名的用户。但是,我不得不牺牲 10 分钟的 ttl 条件(我需要为每个用户名单独设置)。
顺便说一下 Redis/Lua 初学者,因此是菜鸟问题(如果是的话)。
有志者事竟成...:)
首先将登录信息存储在有序集中。假设用户 ID 123 在时间 456 使用用户名 "foo" 登录,您可以将其表示为:
ZADD logins 456 123:foo
注意:您还必须从该 Sorted Set 中删除旧元素,这样它才不会失去控制。
接下来,您想要搜索过去 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
在我的网站上,允许用户保留相同的用户名。此外,在用户登录的任何时间点,我都会将他们的用户名临时保存在一个 ttl
为 10 分钟的 redis 密钥中。
问题是:有没有办法 - 使用 Redis - 查找最近 10 分钟内在线的所有用户 ID,共享相同的用户名?
目前,我正在提取所有键的值并在 Python 中查找冲突 - 这并没有真正帮助,因为我需要在运行时多次执行此操作(并且有很多用户流量) .
我假设我可以使用唯一的用户名作为键来创建集合,并将所有用户 ID 存储在集合中,以便为我提供 O(1) 查找共享相同用户名的用户。但是,我不得不牺牲 10 分钟的 ttl 条件(我需要为每个用户名单独设置)。
顺便说一下 Redis/Lua 初学者,因此是菜鸟问题(如果是的话)。
有志者事竟成...:)
首先将登录信息存储在有序集中。假设用户 ID 123 在时间 456 使用用户名 "foo" 登录,您可以将其表示为:
ZADD logins 456 123:foo
注意:您还必须从该 Sorted Set 中删除旧元素,这样它才不会失去控制。
接下来,您想要搜索过去 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