2013-12-12 60 views
0

我正在嘗試構建實時股票申請。 每秒鐘我可以從Web服務的一些數據,如下面:Redis實時股票申請的關鍵設計

[{ 「量」: 「20」, 「日期」:1386832664, 「價格」: 「183.8」, 「TID」: 5354831「type」:「sell」},{「amount」:「22」,「date」:1386832664,「price」:「183.61」,「tid」:5354833,「type」:「buy」}]

tid是股票買入和賣出的票證ID;日期是從1970.1.1開始的第二個日期; 價格/數量是在什麼價格和多少股票交易。

Reuirement

我的要求是顯示用戶最高/最低價格在每分鐘/ 5分鐘/小時/天,實時性;實時顯示用戶每分鐘/ 5分鐘/小時/天的總金額。

問題

我的問題是如何將數據存儲到Redis的,這樣我就可以方便,快捷地獲得來自DB不同時期的最高/最低交易。

我的設計是類似下面的東西:

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

我在Redis的新。如果設計是這意味着我需要使用排序集合,那麼是否會有任何性能問題?或者還有什麼其他方式可以在不同時期獲得最高/最低價格。

期待您的建議和設計。

+0

我想你想要3個滑動窗口(每5分鐘一個,每個小時一個,每天一個),你想每個時間段的最高/最低值,我理解正確嗎? – zenbeni

+1

是的,有些圖表就像http://www.investing.com/equities/yahoo-inc-candstick。我想知道將原始數據存儲到數據庫的最佳做法是什麼。 – yuyue007

回答

1

我的建議是存儲您感興趣的所有區間的最小/最大/總數,並使用每個到達的數據點更新當前區間。爲了避免在讀取以前的數據進行比較時出現網絡延遲,您可以使用Lua腳本完全在Redis服務器內完成此操作。

每個數據點的一個關鍵(或者更糟糕的是,每個數據點字段)將消耗太多內存。爲了獲得最佳效果,您應該將它分組爲小列表/散列(請參閱http://redis.io/topics/memory-optimization)。 Redis只允許在其數據結構中嵌套一層:如果數據有多個字段,並且您希望每個鍵存儲多個項目,則需要以某種方式自己對其進行編碼。幸運的是,標準的Redis Lua環境包括msgpack支持,這是一種非常有效的二進制JSON格式。在您的示例中,msgpack「按原樣」編碼的JSON條目長度爲52-53字節。我建議按時分組,以便每個鍵有100-1000個條目。假設一分鐘的時間間隔適合這個要求。然後,密鑰方案將如下所示:

YYmmddHHMMSS - 從tid到給定分鐘的msgpack編碼數據點的散列值。 5m:YYmmddHHMM,1h:YYmmddHH,1d:YYmmdd - 包含min,max,sum字段的窗口數據散列。

讓我們來看一個示例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個字節的數據。這取決於你的要求,是否值得這樣做。