Quiero almacenar una carga útil JSON en redis. Realmente hay 2 formas en que puedo hacer esto:
Uno usando una cadena simple de claves y valores.
clave: usuario, valor: carga útil (el blob JSON completo que puede ser de 100-200 KB)SET user:1 payload
Usando hashes
HSET user:1 username "someone"
HSET user:1 location "NY"
HSET user:1 bio "STRING WITH OVER 100 lines"
Tenga en cuenta que si uso un hash, la longitud del valor no es predecible. No todos son cortos, como el ejemplo biográfico anterior.
¿Cuál es más eficiente en memoria? ¿Usando cadenas y valores, o usando un hash?
Respuestas:
Depende de cómo acceda a los datos:
Ir a la opción 1:
Ir a la opción 2:
PD: Como regla general, elija la opción que requiere menos consultas en la mayoría de sus casos de uso.
fuente
JSON
carga útil (un problema clásico de no atómicoread-modify-write
).Este artículo puede proporcionar mucha información aquí: http://redis.io/topics/memory-optimization
Hay muchas formas de almacenar una matriz de objetos en Redis ( spoiler : me gusta la opción 1 para la mayoría de los casos de uso):
Almacene todo el objeto como una cadena codificada con JSON en una sola clave y realice un seguimiento de todos los objetos utilizando un conjunto (o una lista, si es más apropiado). Por ejemplo:
En términos generales, este es probablemente el mejor método en la mayoría de los casos. Si hay muchos campos en el Objeto, sus Objetos no están anidados con otros Objetos y tiende a acceder solo a un pequeño subconjunto de campos a la vez, podría ser mejor ir con la opción 2.
Ventajas : considerada una "buena práctica". Cada objeto es una clave Redis completa. El análisis JSON es rápido, especialmente cuando necesita acceder a muchos campos para este Objeto a la vez. Desventajas : más lento cuando solo necesita acceder a un solo campo.
Almacene las propiedades de cada Objeto en un hash Redis.
Ventajas : considerada una "buena práctica". Cada objeto es una clave Redis completa. No es necesario analizar cadenas JSON. Desventajas : posiblemente más lento cuando necesita acceder a todos / la mayoría de los campos en un Objeto. Además, los objetos anidados (objetos dentro de objetos) no se pueden almacenar fácilmente.
Almacene cada objeto como una cadena JSON en un hash de Redis.
Esto le permite consolidar un poco y solo usar dos claves en lugar de muchas claves. La desventaja obvia es que no puede establecer el TTL (y otras cosas) en cada Objeto de usuario, ya que es simplemente un campo en el hash de Redis y no una clave Redis completa.
Ventajas : el análisis JSON es rápido, especialmente cuando necesita acceder a muchos campos para este Objeto a la vez. Menos "contaminante" del espacio de nombres de la clave principal. Desventajas : aproximadamente el mismo uso de memoria que el n. ° 1 cuando tiene muchos objetos. Más lento que el n. ° 2 cuando solo necesita acceder a un solo campo. Probablemente no se considere una "buena práctica".
Almacene cada propiedad de cada Objeto en una clave dedicada.
De acuerdo con el artículo anterior, esta opción casi nunca se prefiere (a menos que la propiedad del Objeto deba tener TTL específico o algo así).
Ventajas : las propiedades de los objetos son teclas Redis completas, que pueden no ser excesivas para su aplicación. Desventajas : lento, usa más memoria y no se considera "mejor práctica". Mucha contaminación del espacio de nombres de la clave principal.
Resumen total
La opción 4 generalmente no se prefiere. Las opciones 1 y 2 son muy similares, y ambas son bastante comunes. Prefiero la opción 1 (en términos generales) porque le permite almacenar objetos más complicados (con múltiples capas de anidamiento, etc.) La opción 3 se usa cuando realmente le importa no contaminar el espacio de nombres de la clave principal (es decir, no quiere allí ser muchas claves en su base de datos y no le importan cosas como TTL, fragmentación de claves o lo que sea).
Si tengo algo mal aquí, considere dejar un comentario y permitirme revisar la respuesta antes de votar. ¡Gracias! :)
fuente
obj
y almacenamos campos como vistas, votos y votantes con claves separadas. De esta manera, con una sola consulta READ, obtiene todo el objeto y aún puede actualizar rápidamente partes dinámicas de su objeto. Las actualizaciones relativamente poco frecuentes de los campos en la cadena JSON se pueden hacer leyendo y escribiendo todo el objeto en una transacción.Algunas adiciones a un conjunto dado de respuestas:
En primer lugar, si va a usar Redis hash de manera eficiente, debe saber el número máximo de claves y el tamaño máximo de los valores; de lo contrario, si rompen hash-max-ziplist-value o hash-max-ziplist-entries Redis lo convertirá prácticamente pares clave / valor habituales debajo de un capó. (vea hash-max-ziplist-value, hash-max-ziplist-ingreses) Y romper bajo un capó de las opciones hash ES REALMENTE MALO, porque cada par clave / valor habitual dentro de Redis usa +90 bytes por par.
¡Esto significa que si comienza con la opción dos y sale accidentalmente de max-hash-ziplist-value obtendrá +90 bytes por CADA ATRIBUTO que tenga dentro del modelo de usuario! (en realidad no es el +90 sino el +70 ver la salida de la consola a continuación)
Para la respuesta de TheHippo, los comentarios sobre la Opción uno son engañosos:
hgetall / hmset / hmget al rescate si necesita todos los campos o múltiples operaciones get / set.
Para respuesta BMiner.
La tercera opción es realmente divertida, para el conjunto de datos con max (id) <has-max-ziplist-value, esta solución tiene complejidad O (N), porque, sorpresa, Reddis almacena pequeños hashes como contenedores de longitud / clave / valor ¡objetos!
Pero no debe preocuparse, romperá las entradas de hash-max-ziplist muy rápido y allí está, en realidad, ahora está en la solución número 1.
La segunda opción probablemente irá a la cuarta solución bajo una capucha porque, como dice la pregunta:
Y como ya dijo: la cuarta solución es el byte +70 más caro por cada atributo seguro.
Mi sugerencia de cómo optimizar dicho conjunto de datos:
Tienes dos opciones:
Si no puede garantizar el tamaño máximo de algunos atributos del usuario, busque la primera solución y si la memoria es crucial, comprima el usuario json antes de almacenarlo en redis.
Si puede forzar el tamaño máximo de todos los atributos. Luego, puede establecer hash-max-ziplist-entries / value y usar hash como un hash por representación de usuario O como optimización de memoria hash de este tema de una guía de Redis: https://redis.io/topics/memory-optimization y almacenar usuario como cadena json. De cualquier manera, también puede comprimir atributos de usuario largos.
fuente