Redis
 sql >> Base de données >  >> NoSQL >> Redis

Conception de clé Redis pour une application de stock en temps réel

Ma suggestion est de stocker min/max/total pour tous les intervalles qui vous intéressent et de le mettre à jour pour les intervalles actuels avec chaque point de données arrivant. Pour éviter la latence du réseau lors de la lecture des données précédentes à des fins de comparaison, vous pouvez le faire entièrement à l'intérieur du serveur Redis à l'aide de scripts Lua.

Une clé par point de données (ou, pire encore, par champ de point de données) va consommer trop de mémoire. Pour de meilleurs résultats, vous devez le regrouper en petites listes/hachages (voir http://redis.io/topics/memory-optimization). Redis n'autorise qu'un seul niveau d'imbrication dans ses structures de données :si vos données comportent plusieurs champs et que vous souhaitez stocker plus d'un élément par clé, vous devez en quelque sorte l'encoder vous-même. Heureusement, l'environnement Redis Lua standard inclut la prise en charge de msgpack qui est un format binaire très efficace de type JSON. Les entrées JSON dans votre exemple encodées avec msgpack "tel quel" auront une longueur de 52 à 53 octets. Je suggère de regrouper par heure afin d'avoir 100 à 1000 entrées par clé. Supposons qu'un intervalle d'une minute réponde à cette exigence. Alors le schéma de clé serait le suivant :

YYmmddHHMMSS — un hachage de tid aux points de données encodés par msgpack pour la minute donnée.5m:YYmmddHHMM , 1h:YYmmddHH , 1d:YYmmdd - hachages de données de fenêtre contenant min , max , sum champs.

Regardons un exemple de script Lua qui acceptera un point de données et mettra à jour toutes les clés si nécessaire. En raison du fonctionnement des scripts Redis, nous devons transmettre explicitement les noms de toutes les clés auxquelles le script accédera, c'est-à-dire les données en direct et les trois clés de fenêtre. Redis Lua dispose également d'une bibliothèque d'analyse JSON, donc par souci de simplicité, supposons que nous lui passons simplement le dictionnaire JSON. Cela signifie que nous devons analyser les données deux fois :du côté de l'application et du côté de Redis, mais les effets sur les performances ne sont pas clairs.

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)

Cette configuration peut effectuer des milliers de mises à jour par seconde, peu gourmande en mémoire, et les données de la fenêtre peuvent être récupérées instantanément.

UPDATE :Sur la partie mémoire, 50-60 octets par point c'est quand même beaucoup si on veut stocker plus quelques millions. Avec ce type de données, je pense que vous pouvez obtenir aussi peu que 2-3 octets par point en utilisant un format binaire personnalisé, un codage delta et une compression ultérieure des morceaux en utilisant quelque chose comme Snappy. Cela dépend de vos besoins, si cela vaut la peine de le faire.