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

Redis nøgledesign til aktieanvendelse i realtid

Mit forslag er at gemme min/max/total for alle intervaller, du er interesseret i, og opdatere det for nuværende med hvert ankommende datapunkt. For at undgå netværksforsinkelse, når du læser tidligere data til sammenligning, kan du gøre det helt inde på Redis-serveren ved hjælp af Lua-scripting.

En nøgle pr. datapunkt (eller endnu værre, pr. datapunktfelt) kommer til at forbruge for meget hukommelse. For de bedste resultater bør du gruppere det i små lister/hashes (se http://redis.io/topics/memory-optimization). Redis tillader kun ét niveau af indlejring i dets datastrukturer:Hvis dine data har flere felter, og du vil gemme mere end ét element pr. nøgle, skal du på en eller anden måde selv kode det. Heldigvis inkluderer standard Redis Lua-miljø msgpack-understøttelse, som er et meget effektivt binært JSON-lignende format. JSON-indgange i dit eksempel kodet med msgpack "som den er" vil være 52-53 bytes lange. Jeg foreslår at gruppere efter tid, så du har 100-1000 poster pr. nøgle. Antag, at et minuts interval passer til dette krav. Så ville nøgleskemaet være sådan her:

YYmmddHHMMSS — en hash fra tid til msgpack-kodede datapunkter for det givne minut.5m:YYmmddHHMM , 1h:YYmmddHH , 1d:YYmmdd — vinduesdatahash, der indeholder min , max , sum felter.

Lad os se på et eksempel på et Lua-script, der accepterer ét datapunkt og opdaterer alle nøgler efter behov. På grund af den måde Redis scripting fungerer på, er vi nødt til eksplicit at videregive navnene på alle nøgler, som scriptet får adgang til, dvs. live-dataene og alle tre vinduesnøgler. Redis Lua har også et JSON-parsing-bibliotek tilgængeligt, så lad os for nemhedens skyld antage, at vi bare videregiver den JSON-ordbog. Det betyder, at vi skal parse data to gange:på applikationssiden og på Redis-siden, men ydeevneeffekterne af det er ikke klare.

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)

Denne opsætning kan udføre tusindvis af opdateringer i sekundet, ikke særlig sulten på hukommelsen, og vinduesdata kan hentes øjeblikkeligt.

OPDATERING:På hukommelsesdelen er 50-60 bytes per punkt stadig meget, hvis du vil gemme mere et par millioner. Med denne slags data tror jeg, at du kan få så lavt som 2-3 bytes pr. punkt ved at bruge brugerdefineret binært format, delta-kodning og efterfølgende komprimering af bidder ved hjælp af noget som snappy. Det afhænger af dine krav, om det er værd at gøre dette.




  1. MongoDB bind_ip virker ikke, medmindre den er sat til 0.0.0.0

  2. Max og min i mongodb

  3. MongoDB via Mongoose JS - Hvad er findByID?

  4. Kryptering af MongoDB Data-at-Rest