Redis是实时库存应用的关键设计

时间:2013-12-12 09:18:19

标签: node.js redis real-time

我正在尝试建立一个实时股票申请。 每一秒我可以从以下网络服务获取一些数据:

  

[{ “量”: “20”, “日期”:1386832664, “价格”: “183.8”, “TID”:5354831, “类型”: “卖”},{ “量”: “22” , “日期”:1386832664, “价格”: “183.61”, “TID”:5354833, “类型”: “买”}]

tid是股票买卖的门票ID; 日期是1970.1.1的第二个; 价格/金额是以什么价格和多少股票交易。

Reuirement

我的要求是每分钟/ 5分钟/小时/天实时显示用户最高/最低价格;以实时的方式向用户显示每分钟/ 5分钟/小时/天的金额总和。

问题

我的问题是如何将数据存储到redis中,以便我可以轻松快速地从DB获得最高/最低的交易时间。

我的设计如下:

[date]:[tid]:amount
[date]:[tid]:price
[date]:[tid]:type

我是redis的新手。如果设计是这意味着我需要使用有序集,是否会出现任何性能问题?或者还有其他方法可以获得不同时期的最高/最低价格。

期待您的建议和设计。

1 个答案:

答案 0 :(得分:3)

我的建议是存储您感兴趣的所有间隔的最小值/最大值/总数,并针对每个到达的数据点更新当前的间隔。为了避免在读取以前的数据进行比较时出现网络延迟,您可以使用Lua脚本完全在Redis服务器内完成。

每个数据点一个密钥(或者更糟糕的是,每个数据点字段)将消耗太多内存。为获得最佳效果,您应将其分组为小列表/哈希(请参阅http://redis.io/topics/memory-optimization)。 Redis只允许在其数据结构中进行一级嵌套:如果数据有多个字段,并且您希望每个键存储多个项目,则需要以某种方式自行编码。幸运的是,标准的Redis Lua环境包括msgpack支持,这是一种非常有效的二进制JSON格式。使用msgpack“按原样”编码的示例中的JSON条目长度为52-53个字节。我建议按时间分组,以便每个键有100-1000个条目。假设一分钟间隔符合此要求。然后键控方案将是这样的:

YYmmddHHMMSS - 给定分钟内从tid到msgpack编码数据点的哈希值。 5m:YYmmddHHMM1h:YYmmddHH1d:YYmmdd - 包含minmaxsum字段的窗口数据哈希值。

让我们看一个示例Lua脚本,该脚本将接受一个数据点并根据需要更新所有密钥。由于Redis脚本的工作方式,我们需要显式传递脚本将访问的所有键的名称,即实时数据和所有三个窗口键。 Redis Lua也提供了JSON解析库,所以为了简单起见,我们假设我们只是传递它的JSON字典。这意味着我们必须两次解析数据:在​​应用程序端和Redis端,但它的性能影响尚不清楚。

local function update_window(winkey, price, amount)
    local windata = redis.call('HGETALL', winkey)
    if price > tonumber(windata.max or 0) then
        redis.call('HSET', winkey, 'max', price)
    end
    if price < tonumber(windata.min or 1e12) then
        redis.call('HSET', winkey, 'min', price)
    end
    redis.call('HSET', winkey, 'sum', (windata.sum or 0) + amount)
end

local currkey, fiveminkey, hourkey, daykey = unpack(KEYS)
local data = cjson.decode(ARGV[1])
local packed = cmsgpack.pack(data)
local tid = data.tid
redis.call('HSET', currkey, tid, packed)
local price = tonumber(data.price)
local amount = tonumber(data.amount)
update_window(fiveminkey, price, amount)
update_window(hourkey, price, amount)
update_window(daykey, price, amount)

此设置每秒可以进行数千次更新,内存不会非常耗费,并且可以立即检索窗口数据。

更新:在内存部分,如果你想存储更多的数百万,每点50-60字节仍然很多。有了这种数据,我认为使用自定义二进制格式,增量编码以及使用类似snappy之类的块的后续压缩,每个点可以获得低至2-3个字节的数据。这取决于您的要求,是否值得这样做。