Redis 队列或其他方法来处理勾号数据?
在我们的电子交易系统中,我们需要根据100多份合约的勾号数据进行计算 未在一条消息中接收到合同的勾号数据。一条消息仅包含一份合同的勾号数据。合同的时间戳略有不同(有时差异很大,但我们忽略这种情况) 只有那些价格发生变化的公司才会有数据。所以我无法计算合同号,以了解我是否已收到此勾号的所有数据 但另一方面,我们不想等到收到所有滴答声的数据,因为有时数据可能会延迟很长时间,我们希望排除它们 需要低延迟。所以我认为我们将定义一个窗口,比如说50毫秒,然后根据我们在过去50毫秒内收到的任何数据开始计算 处理此类用例的最佳方式是什么 最初我想使用redis stream来维护一个小队列,即每当接收到合同的数据时,我都会将其推送到redis stream。但我不知道什么是在特定时间(比如50毫秒)过去后立即提取数据的最佳方式 我在考虑也许我应该使用其他技术?Redis 队列或其他方法来处理勾号数据?,redis,time-series,queue,Redis,Time Series,Queue,在我们的电子交易系统中,我们需要根据100多份合约的勾号数据进行计算 未在一条消息中接收到合同的勾号数据。一条消息仅包含一份合同的勾号数据。合同的时间戳略有不同(有时差异很大,但我们忽略这种情况) 只有那些价格发生变化的公司才会有数据。所以我无法计算合同号,以了解我是否已收到此勾号的所有数据 但另一方面,我们不想等到收到所有滴答声的数据,因为有时数据可能会延迟很长时间,我们希望排除它们 需要低延迟。所以我认为我们将定义一个窗口,比如说50毫秒,然后根据我们在过去50毫秒内收到的任何数据开始计算
任何建议都将不胜感激。使用
XRANGE myStream-+COUNT 1
获取第一个条目
使用XREVRANGE myStream+-COUNT 1
获取最后一个条目
XINFO STREAM myStream
也会带来第一个和最后一个条目,但要说它是O(logn)
假设将时间戳用作ID或字段,则可以计算时间差
如果您使用的是Redis Streams自动ID(XADD myStream*…
),则ID的第一部分是UNIX时间戳(以毫秒为单位)
假设存在上述情况,您可以使用Lua脚本以原子方式执行检查:
EVAL "local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1') local firstTime = {} if next(first) == nil then return redis.error_reply('Stream is empty or key doesn`t exist') end for str in string.gmatch(first[1][1], '([^-]+)') do table.insert(firstTime, tonumber(str)) end local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1') local lastTime = {} for str in string.gmatch(last[1][1], '([^-]+)') do table.insert(lastTime, tonumber(str)) end local ms = lastTime[1] - firstTime[1] if ms >= tonumber(ARGV[1]) then return redis.call('XRANGE', KEYS[1], '-', '+') else return redis.error_reply('Only '..ms..' ms') end" 1 myStream 50
local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1')
local firstTime = {}
if next(first) == nil then
return redis.error_reply('Stream is empty or key doesn`t exist')
end
for str in string.gmatch(first[1][1], '([^-]+)') do
table.insert(firstTime, tonumber(str))
end
local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1')
local lastTime = {}
for str in string.gmatch(last[1][1], '([^-]+)') do
table.insert(lastTime, tonumber(str))
end
local ms = lastTime[1] - firstTime[1]
if ms >= tonumber(ARGV[1]) then
return redis.call('XRANGE', KEYS[1], '-', '+')
else
return redis.error_reply('Only '..ms..' ms')
end
参数是numKeys(这里1个)streamKey timeInMs(这里50个)
:1 myStream 50
下面是Lua脚本的友好视图:
EVAL "local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1') local firstTime = {} if next(first) == nil then return redis.error_reply('Stream is empty or key doesn`t exist') end for str in string.gmatch(first[1][1], '([^-]+)') do table.insert(firstTime, tonumber(str)) end local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1') local lastTime = {} for str in string.gmatch(last[1][1], '([^-]+)') do table.insert(lastTime, tonumber(str)) end local ms = lastTime[1] - firstTime[1] if ms >= tonumber(ARGV[1]) then return redis.call('XRANGE', KEYS[1], '-', '+') else return redis.error_reply('Only '..ms..' ms') end" 1 myStream 50
local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1')
local firstTime = {}
if next(first) == nil then
return redis.error_reply('Stream is empty or key doesn`t exist')
end
for str in string.gmatch(first[1][1], '([^-]+)') do
table.insert(firstTime, tonumber(str))
end
local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1')
local lastTime = {}
for str in string.gmatch(last[1][1], '([^-]+)') do
table.insert(lastTime, tonumber(str))
end
local ms = lastTime[1] - firstTime[1]
if ms >= tonumber(ARGV[1]) then
return redis.call('XRANGE', KEYS[1], '-', '+')
else
return redis.error_reply('Only '..ms..' ms')
end
它返回:
(错误)流为空或密钥不存在
(错误)如果没有所需的时间,则仅34 ms
- 如果第一条消息和最后一条消息之间的时间已过,则为实际条目列表
确保检查以熟悉Redis Streams,并了解Lua脚本。使用
XRANGE myStream-+COUNT 1
获取第一个条目
使用XREVRANGE myStream+-COUNT 1
获取最后一个条目
XINFO STREAM myStream
也会带来第一个和最后一个条目,但要说它是O(logn)
假设将时间戳用作ID或字段,则可以计算时间差
如果您使用的是Redis Streams自动ID(XADD myStream*…
),则ID的第一部分是UNIX时间戳(以毫秒为单位)
假设存在上述情况,您可以使用Lua脚本以原子方式执行检查:
EVAL "local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1') local firstTime = {} if next(first) == nil then return redis.error_reply('Stream is empty or key doesn`t exist') end for str in string.gmatch(first[1][1], '([^-]+)') do table.insert(firstTime, tonumber(str)) end local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1') local lastTime = {} for str in string.gmatch(last[1][1], '([^-]+)') do table.insert(lastTime, tonumber(str)) end local ms = lastTime[1] - firstTime[1] if ms >= tonumber(ARGV[1]) then return redis.call('XRANGE', KEYS[1], '-', '+') else return redis.error_reply('Only '..ms..' ms') end" 1 myStream 50
local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1')
local firstTime = {}
if next(first) == nil then
return redis.error_reply('Stream is empty or key doesn`t exist')
end
for str in string.gmatch(first[1][1], '([^-]+)') do
table.insert(firstTime, tonumber(str))
end
local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1')
local lastTime = {}
for str in string.gmatch(last[1][1], '([^-]+)') do
table.insert(lastTime, tonumber(str))
end
local ms = lastTime[1] - firstTime[1]
if ms >= tonumber(ARGV[1]) then
return redis.call('XRANGE', KEYS[1], '-', '+')
else
return redis.error_reply('Only '..ms..' ms')
end
参数是numKeys(这里1个)streamKey timeInMs(这里50个)
:1 myStream 50
下面是Lua脚本的友好视图:
EVAL "local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1') local firstTime = {} if next(first) == nil then return redis.error_reply('Stream is empty or key doesn`t exist') end for str in string.gmatch(first[1][1], '([^-]+)') do table.insert(firstTime, tonumber(str)) end local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1') local lastTime = {} for str in string.gmatch(last[1][1], '([^-]+)') do table.insert(lastTime, tonumber(str)) end local ms = lastTime[1] - firstTime[1] if ms >= tonumber(ARGV[1]) then return redis.call('XRANGE', KEYS[1], '-', '+') else return redis.error_reply('Only '..ms..' ms') end" 1 myStream 50
local first = redis.call('XRANGE', KEYS[1], '-', '+', 'COUNT', '1')
local firstTime = {}
if next(first) == nil then
return redis.error_reply('Stream is empty or key doesn`t exist')
end
for str in string.gmatch(first[1][1], '([^-]+)') do
table.insert(firstTime, tonumber(str))
end
local last = redis.call('XREVRANGE', KEYS[1], '+', '-', 'COUNT', '1')
local lastTime = {}
for str in string.gmatch(last[1][1], '([^-]+)') do
table.insert(lastTime, tonumber(str))
end
local ms = lastTime[1] - firstTime[1]
if ms >= tonumber(ARGV[1]) then
return redis.call('XRANGE', KEYS[1], '-', '+')
else
return redis.error_reply('Only '..ms..' ms')
end
它返回:
(错误)流为空或密钥不存在
(错误)如果没有所需的时间,则仅34 ms
- 如果第一条消息和最后一条消息之间的时间已过,则为实际条目列表
请务必检查以熟悉Redis Streams,并了解Lua脚本。我不确定是否遵循。听起来Redis streams应该可以做到这一点。你能详细说明一下你在使用Redis streams时遇到了什么问题吗?实际上我还不太熟悉Redis stream。我知道它的工作原理类似于队列,但我如何才能使它像这样工作:检查队列中的消息,如果(最新时间戳-最新时间戳)>阈值,读取所有这些消息?redis stream是否支持它?我不确定是否支持。听起来Redis streams应该可以做到这一点。你能详细说明一下你在使用Redis streams时遇到了什么问题吗?实际上我还不太熟悉Redis stream。我知道它的工作原理类似于队列,但我如何才能使它像这样工作:检查队列中的消息,如果(最新时间戳-最新时间戳)>阈值,读取所有这些消息?redis stream支持吗?非常感谢。我想这将能够满足我的要求!非常感谢你。我想这将能够满足我的要求!