Mijn suggestie is om min/max/totaal op te slaan voor alle intervallen waarin u geïnteresseerd bent en deze bij elk aankomend gegevenspunt bij te werken voor de huidige. Om netwerklatentie te voorkomen bij het lezen van eerdere gegevens ter vergelijking, kunt u dit volledig binnen de Redis-server doen met Lua-scripting.
Eén sleutel per datapunt (of, erger nog, per datapuntveld) gaat te veel geheugen in beslag nemen. Voor de beste resultaten moet u het in kleine lijsten/hashes groeperen (zie http://redis.io/topics/memory-optimization). Redis staat slechts één niveau van nesten toe in zijn gegevensstructuren:als uw gegevens meerdere velden hebben en u meer dan één item per sleutel wilt opslaan, moet u deze op de een of andere manier zelf coderen. Gelukkig bevat de standaard Redis Lua-omgeving msgpack-ondersteuning, wat een zeer efficiënt binair JSON-achtig formaat is. JSON-vermeldingen in uw voorbeeld gecodeerd met msgpack "as is" zullen 52-53 bytes lang zijn. Ik stel voor te groeperen op tijd, zodat je 100-1000 items per sleutel hebt. Stel dat een interval van één minuut aan deze eis voldoet. Het sleutelschema ziet er dan als volgt uit:
YYmmddHHMMSS
— een hash van tid
naar msgpack-gecodeerde datapunten voor de opgegeven minuut.5m:YYmmddHHMM
, 1h:YYmmddHH
, 1d:YYmmdd
— venstergegevenshashes die min
. bevatten , max
, sum
velden.
Laten we eens kijken naar een voorbeeld van een Lua-script dat één gegevenspunt accepteert en waar nodig alle sleutels bijwerkt. Vanwege de manier waarop Redis-scripting werkt, moeten we expliciet de namen doorgeven van alle sleutels die door het script worden gebruikt, d.w.z. de live gegevens en alle drie de venstersleutels. Redis Lua heeft ook een JSON-parseerbibliotheek beschikbaar, dus laten we omwille van de eenvoud aannemen dat we het JSON-woordenboek doorgeven. Dat betekent dat we gegevens twee keer moeten ontleden:aan de kant van de applicatie en aan de kant van Redis, maar de prestatie-effecten ervan zijn niet duidelijk.
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)
Deze configuratie kan duizenden updates per seconde uitvoeren, heeft niet veel geheugen nodig en venstergegevens kunnen direct worden opgehaald.
UPDATE:Op het geheugengedeelte is 50-60 bytes per punt nog steeds veel als je meer een paar miljoen wilt opslaan. Met dit soort gegevens denk ik dat je zo laag als 2-3 bytes per punt kunt krijgen met behulp van een aangepast binair formaat, deltacodering en daaropvolgende compressie van chunks met zoiets als pittig. Het hangt af van uw vereisten of het de moeite waard is om dit te doen.