Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

Design de chave Redis para aplicação de estoque em tempo real


Minha sugestão é armazenar min/max/total para todos os intervalos em que você está interessado e atualizá-lo para os atuais com cada ponto de dados que chega. Para evitar latência de rede ao ler dados anteriores para comparação, você pode fazer isso inteiramente dentro do servidor Redis usando script Lua.

Uma chave por ponto de dados (ou, pior ainda, por campo de ponto de dados) consumirá muita memória. Para obter os melhores resultados, você deve agrupá-lo em pequenas listas/hashes (consulte http://redis.io/topics/memory-optimization). O Redis permite apenas um nível de aninhamento em suas estruturas de dados:se seus dados tiverem vários campos e você quiser armazenar mais de um item por chave, precisará codificá-lo de alguma forma. Felizmente, o ambiente Redis Lua padrão inclui suporte a msgpack, que é um formato binário semelhante ao JSON muito eficiente. As entradas JSON em seu exemplo codificadas com msgpack "como estão" terão de 52 a 53 bytes. Sugiro agrupar por tempo para que você tenha 100-1000 entradas por chave. Suponha que o intervalo de um minuto atenda a esse requisito. Então o esquema de chaveamento seria assim:

YYmmddHHMMSS — um hash de tid para pontos de dados codificados em msgpack para um determinado minuto.5m:YYmmddHHMM , 1h:YYmmddHH , 1d:YYmmdd — hashes de dados de janela que contêm min , max , sum Campos.

Vejamos um exemplo de script Lua que aceitará um ponto de dados e atualizará todas as chaves conforme necessário. Devido à maneira como o script Redis funciona, precisamos passar explicitamente os nomes de todas as chaves que serão acessadas pelo script, ou seja, os dados ativos e todas as três chaves da janela. O Redis Lua também tem uma biblioteca de análise JSON disponível, portanto, para simplificar, vamos supor que apenas passamos o dicionário JSON. Isso significa que temos que analisar os dados duas vezes:no lado do aplicativo e no lado do Redis, mas os efeitos de desempenho não são claros.
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)

Essa configuração pode fazer milhares de atualizações por segundo, sem muita memória, e os dados da janela podem ser recuperados instantaneamente.

ATUALIZAÇÃO:Na parte da memória, 50-60 bytes por ponto ainda é muito se você quiser armazenar mais alguns milhões. Com esse tipo de dados, acho que você pode obter apenas 2-3 bytes por ponto usando formato binário personalizado, codificação delta e compactação subsequente de pedaços usando algo como snappy. Depende de suas necessidades, se vale a pena fazer isso.