Redis
 sql >> Database >  >> NoSQL >> Redis

Design della chiave Redis per l'applicazione delle scorte in tempo reale

Il mio suggerimento è di memorizzare min/max/totale per tutti gli intervalli che ti interessano e aggiornarlo per quelli attuali con ogni punto dati in arrivo. Per evitare la latenza di rete durante la lettura dei dati precedenti per il confronto, puoi farlo interamente all'interno del server Redis utilizzando lo scripting Lua.

Una chiave per punto dati (o, peggio ancora, per campo punto dati) consumerà troppa memoria. Per ottenere i migliori risultati, dovresti raggrupparlo in piccoli elenchi/hash (vedi http://redis.io/topics/memory-optimization). Redis consente un solo livello di annidamento nelle sue strutture dati:se i tuoi dati hanno più campi e vuoi memorizzare più di un elemento per chiave, devi in ​​qualche modo codificarli tu stesso. Fortunatamente, l'ambiente Redis Lua standard include il supporto per msgpack che è un formato binario simile a JSON molto efficiente. Le voci JSON nel tuo esempio codificate con msgpack "così com'è" saranno lunghe 52-53 byte. Suggerisco di raggruppare per tempo in modo da avere 100-1000 voci per chiave. Supponiamo che l'intervallo di un minuto soddisfi questo requisito. Quindi lo schema di codifica sarebbe questo:

YYmmddHHMMSS — un hash da tid ai punti dati con codifica msgpack per il minuto specificato.5m:YYmmddHHMM , 1h:YYmmddHH , 1d:YYmmdd — hash dei dati della finestra che contengono min , max , sum campi.

Diamo un'occhiata a uno script Lua di esempio che accetterà un punto dati e aggiornerà tutte le chiavi se necessario. A causa del modo in cui funziona lo scripting Redis, dobbiamo passare in modo esplicito i nomi di tutte le chiavi a cui accederà lo script, ovvero i dati in tempo reale e tutte e tre le chiavi della finestra. Redis Lua ha anche una libreria di analisi JSON disponibile, quindi per semplicità supponiamo di passare semplicemente al dizionario JSON. Ciò significa che dobbiamo analizzare i dati due volte:sul lato dell'applicazione e sul lato Redis, ma gli effetti sulle prestazioni non sono chiari.

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)

Questa configurazione può eseguire migliaia di aggiornamenti al secondo, non molto affamato di memoria e i dati della finestra possono essere recuperati all'istante.

AGGIORNAMENTO:Per quanto riguarda la parte di memoria, 50-60 byte per punto sono ancora molti se vuoi archiviare più di qualche milione. Con questo tipo di dati penso che tu possa ottenere un minimo di 2-3 byte per punto usando il formato binario personalizzato, la codifica delta e la successiva compressione di blocchi usando qualcosa come snappy. Dipende dalle tue esigenze, se vale la pena farlo.