Saran saya adalah menyimpan min/maks/total untuk semua interval yang Anda minati dan memperbaruinya untuk interval saat ini dengan setiap titik data yang tiba. Untuk menghindari latensi jaringan saat membaca data sebelumnya untuk perbandingan, Anda dapat melakukannya sepenuhnya di dalam server Redis menggunakan skrip Lua.
Satu kunci per titik data (atau, lebih buruk lagi, per bidang titik data) akan menghabiskan terlalu banyak memori. Untuk hasil terbaik, Anda harus mengelompokkannya ke dalam daftar kecil/hash (lihat http://redis.io/topics/memory-optimization). Redis hanya mengizinkan satu tingkat bersarang dalam struktur datanya:jika data Anda memiliki beberapa bidang dan Anda ingin menyimpan lebih dari satu item per kunci, Anda perlu menyandikannya sendiri. Untungnya, lingkungan Redis Lua standar menyertakan dukungan msgpack yang merupakan format mirip JSON biner yang sangat efisien. Entri JSON dalam contoh Anda yang dikodekan dengan msgpack "sebagaimana adanya" akan memiliki panjang 52-53 byte. Saya sarankan mengelompokkan berdasarkan waktu sehingga Anda memiliki 100-1000 entri per kunci. Misalkan interval satu menit sesuai dengan persyaratan ini. Maka skema keying akan menjadi seperti ini:
YYmmddHHMMSS
— hash dari tid
ke titik data yang disandikan msgpack untuk menit tertentu.5m:YYmmddHHMM
, 1h:YYmmddHH
, 1d:YYmmdd
— hash data jendela yang berisi min
, max
, sum
bidang.
Mari kita lihat contoh skrip Lua yang akan menerima satu titik data dan memperbarui semua kunci seperlunya. Karena cara kerja skrip Redis, kita perlu secara eksplisit meneruskan nama semua kunci yang akan diakses oleh skrip, yaitu data langsung dan ketiga kunci jendela. Redis Lua juga memiliki perpustakaan penguraian JSON yang tersedia, jadi demi kesederhanaan mari kita asumsikan kita hanya memberikannya kamus JSON. Itu berarti kita harus mengurai data dua kali:di sisi aplikasi dan di sisi Redis, tetapi efek kinerjanya tidak jelas.
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)
Pengaturan ini dapat melakukan ribuan pembaruan per detik, tidak terlalu memakan memori, dan data jendela dapat diambil secara instan.
PEMBARUAN:Pada bagian memori, 50-60 byte per titik masih banyak jika Anda ingin menyimpan lebih banyak beberapa juta. Dengan data semacam ini, saya pikir Anda bisa mendapatkan serendah 2-3 byte per titik menggunakan format biner khusus, penyandian delta, dan kompresi potongan selanjutnya menggunakan sesuatu seperti tajam. Itu tergantung pada kebutuhan Anda, apakah ini layak dilakukan.