मेरा सुझाव है कि आप जिस अंतराल में रुचि रखते हैं उसके लिए न्यूनतम/अधिकतम/कुल संग्रहित करें और प्रत्येक आने वाले डेटा बिंदु के साथ इसे वर्तमान वाले के लिए अपडेट करें। तुलना के लिए पिछले डेटा को पढ़ते समय नेटवर्क विलंबता से बचने के लिए, आप इसे पूरी तरह से लुआ स्क्रिप्टिंग का उपयोग करके रेडिस सर्वर के अंदर कर सकते हैं।
प्रति डेटा बिंदु एक कुंजी (या, इससे भी बदतर, प्रति डेटा बिंदु फ़ील्ड) बहुत अधिक मेमोरी का उपभोग करने वाली है। सर्वोत्तम परिणामों के लिए, आपको इसे छोटी सूचियों/हैश में समूहित करना चाहिए (देखें http://redis.io/topics/memory-optimization)। रेडिस अपने डेटा संरचनाओं में केवल एक स्तर के नेस्टिंग की अनुमति देता है:यदि आपके डेटा में कई फ़ील्ड हैं और आप प्रति कुंजी एक से अधिक आइटम संग्रहीत करना चाहते हैं, तो आपको किसी तरह इसे स्वयं एन्कोड करने की आवश्यकता है। सौभाग्य से, मानक रेडिस लुआ वातावरण में msgpack समर्थन शामिल है जो बहुत ही कुशल बाइनरी JSON- जैसा प्रारूप है। आपके उदाहरण में JSON प्रविष्टियाँ msgpack "जैसा है" के साथ एन्कोडेड 52-53 बाइट लंबी होंगी। मैं समय के अनुसार समूह बनाने का सुझाव देता हूं ताकि आपके पास प्रति कुंजी 100-1000 प्रविष्टियां हों। मान लीजिए कि एक मिनट का अंतराल इस आवश्यकता को पूरा करता है। तब कुंजीयन योजना इस प्रकार होगी:
YYmmddHHMMSS
— tid
. से एक हैश दिए गए मिनट के लिए msgpack-एन्कोडेड डेटा बिंदुओं के लिए।5m:YYmmddHHMM
, 1h:YYmmddHH
, 1d:YYmmdd
— विंडो डेटा हैश जिसमें min
. होता है , max
, sum
फ़ील्ड।
आइए एक नमूना लुआ स्क्रिप्ट देखें जो एक डेटा बिंदु को स्वीकार करेगी और आवश्यकतानुसार सभी कुंजियों को अपडेट करेगी। रेडिस स्क्रिप्टिंग के काम करने के तरीके के कारण हमें उन सभी कुंजियों के नामों को स्पष्ट रूप से पास करने की आवश्यकता है, जिन्हें स्क्रिप्ट द्वारा एक्सेस किया जाएगा, यानी लाइव डेटा और सभी तीन विंडो कुंजियाँ। रेडिस लुआ में JSON पार्सिंग लाइब्रेरी भी उपलब्ध है, इसलिए सादगी के लिए मान लें कि हम इसे JSON डिक्शनरी पास करते हैं। इसका मतलब है कि हमें डेटा को दो बार पार्स करना होगा:आवेदन पक्ष पर और रेडिस पक्ष पर, लेकिन इसका प्रदर्शन प्रभाव स्पष्ट नहीं है।
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 बाइट अभी भी बहुत कुछ है यदि आप कुछ लाखों स्टोर करना चाहते हैं। इस तरह के डेटा के साथ मुझे लगता है कि आप कस्टम बाइनरी प्रारूप, डेल्टा एन्कोडिंग और स्नैपी जैसी किसी चीज़ का उपयोग करके चंक्स के बाद के संपीड़न का उपयोग करके प्रति बिंदु 2-3 बाइट जितना कम प्राप्त कर सकते हैं। यह आपकी आवश्यकताओं पर निर्भर करता है, क्या यह ऐसा करने योग्य है।