Saltar al contenido

Redis strings vs Redis hashes para representar JSON: ¿eficiencia?

Recabamos por diferentes foros para así traerte la solución para tu inquietud, si tienes dudas déjanos tu duda y te respondemos sin falta.

Solución:

Este artículo puede proporcionar mucha información aquí: http://redis.io/topics/memory-optimization

Hay muchas formas de almacenar un array de objetos en Redis (revelación: Me gusta la opción 1 para la mayoría de los casos de uso):

  1. Almacene todo el objeto con codificación JSON string en un solo key y realizar un seguimiento de todos los Objetos utilizando un conjunto (o una lista, si es más apropiado). Por ejemplo:

    INCR id:users
    SET user:id '"name":"Fred","age":25'
    SADD users id
    

    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 optar por la opción 2.

    Ventajas: considerada una “buena práctica”. Cada objeto es un Redis en toda regla key. El análisis de 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.

  2. Almacene las propiedades de cada objeto en un hash de Redis.

    INCR id:users
    HMSET user:id name "Fred" age 25
    SADD users id
    

    Ventajas: considerada una “buena práctica”. Cada objeto es un Redis en toda regla key. No es necesario analizar cadenas JSON. Desventajas: posiblemente más lento cuando necesita acceder a todos / la mayoría de los campos de un objeto. Además, los objetos anidados (objetos dentro de los objetos) no se pueden almacenar fácilmente.

  3. Almacene cada objeto como un JSON string en un hash Redis.

    INCR id:users
    HMSET users id '"name":"Fred","age":25'
    

    Esto le permite consolidar un poco y usar solo dos keys en lugar de muchos keys. La desventaja obvia es que no puede configurar el TTL (y otras cosas) en cada objeto de usuario, ya que es simplemente un campo en el hash de Redis y no un Redis completo. key.

    Ventajas: El análisis de JSON es rápido, especialmente cuando necesita acceder a muchos campos para este objeto a la vez. Menos “contaminante” de los principales key espacio de nombres. 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 campo. Probablemente no se considere una “buena práctica”.

  4. Almacene cada propiedad de cada objeto en un key.

    INCR id:users
    SET user:id:name "Fred"
    SET user:id:age 25
    SADD users id
    

    Según el artículo anterior, esta opción es casi nunca preferido (a menos que la propiedad del Objeto necesite tener TTL específico o algo así).

    Ventajas: Las propiedades del objeto son Redis en toda regla keys, lo que podría no ser excesivo para tu aplicación. Desventajas: lento, utiliza más memoria y no se considera “práctica recomendada”. Gran cantidad de contaminantes de los principales key espacio de nombres.

Resumen total

Generalmente, no se prefiere la opción 4. Las opciones 1 y 2 son muy similares y ambas bastante comunes. Prefiero la opción 1 (en términos generales) porque le permite almacenar objetos más complicados (con múltiples capas de anidación, etc.). La opción 3 se usa cuando con mucho cuidado sobre no contaminar los principales key espacio de nombres (es decir, no quieres que haya muchos keys en su base de datos y no le importan cosas como TTL, key fragmentación, o lo que sea).

Si me equivoqué en algo aquí, considere dejar un comentario y permitirme revisar la respuesta antes de votar en contra. ¡Gracias! 🙂

Depende de cómo acceda a los datos:

Opte por la opción 1:

  • Si utiliza la mayoría de los campos en la mayoría de sus accesos.
  • Si hay variación en la posible keys

Opte por la opción 2:

  • Si usa solo campos individuales en la mayoría de sus accesos.
  • Si siempre sabe qué campos están disponibles

PD: Como regla general, elija la opción que requiere menos consultas en la mayoría de sus casos de uso.

Algunas adiciones a un conjunto dado de respuestas:

En primer lugar, si va a utilizar el hash de Redis de manera eficiente, debe conocer un keys cuente el número máximo y los valores tamaño máximo; de lo contrario, si rompen hash-max-ziplist-value o hash-max-ziplist-entries, Redis lo convertirá en prácticamente lo habitual key/ pares de valores bajo un capó. (ver hash-max-ziplist-value, hash-max-ziplist-entries) Y romper bajo el capó de una opción hash ES REALMENTE MALO, porque cada habitual key/ valor par dentro de Redis usa +90 bytes por par.

Significa que si comienza con la opción dos y accidentalmente se sale del valor 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, vea la salida de la consola a continuación)

 # you need me-redis and awesome-print gems to run exact code
 redis = Redis.include(MeRedis).configure( hash_max_ziplist_value: 64, hash_max_ziplist_entries: 512 ).new 
  => # 
 > redis.flushdb
  => "OK" 
 > ap redis.info(:memory)
    
                "used_memory" => "529512",
          **"used_memory_human" => "517.10K"**,
            ....
    
  => nil 
 # me_set( 't:i' ... ) same as hset( 't:i/512', i % 512 ... )    
 # txt is some english fictionary book around 56K length, 
 # so we just take some random 63-symbols string from it 
 > redis.pipelined 10000.times  ; :done
 => :done 
 > ap redis.info(:memory)
  
               "used_memory" => "1251944",
         **"used_memory_human" => "1.19M"**, # ~ 72b per key/value
            .....
  
  > redis.flushdb
  => "OK" 
  # setting **only one value** +1 byte per hash of 512 values equal to set them all +1 byte 
  > redis.pipelined 10000.timesi ; :done 
  > ap redis.info(:memory)
   
               "used_memory" => "1876064",
         "used_memory_human" => "1.79M",   # ~ 134 bytes per pair  
          ....
   
    redis.pipelined 10000.times redis.set( "t:#i", txt[rand(50000), 65] )  ;
    ap redis.info(:memory)
    
             "used_memory" => "2262312",
          "used_memory_human" => "2.16M", #~155 byte per pair i.e. +90 bytes    
           ....
    

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 la respuesta de BMiner.

La tercera opción es realmente divertida, para el conjunto de datos con max (id)

Pero muchas veces los hash contienen solo unos pocos campos. Cuando los hashes son pequeños, podemos codificarlos en una estructura de datos O (N), como una array con prefijo de longitud key pares de valores. Dado que hacemos esto solo cuando N es pequeño, el tiempo amortizado para los comandos HGET y HSET sigue siendo O (1): el hash se convertirá en una tabla hash real tan pronto como la cantidad de elementos que contiene crezca demasiado

Pero no debe preocuparse, romperá las entradas hash-max-ziplist-muy rápido y listo, ahora se encuentra en la solución número 1.

La segunda opción probablemente irá a la cuarta solución oculta porque, como dice la pregunta:

Tenga en cuenta que si utilizo un hash, la longitud del valor no es predecible. No todos son cortos, como el ejemplo de biografía anterior.

Y como ya dijiste: la cuarta solución es la más cara +70 bytes por cada attribute con seguridad.

Mi sugerencia de cómo optimizar dicho conjunto de datos:

Tienes dos opciones:

  1. Si no puede garantizar el tamaño máximo de algún usuario attributes de lo que busca la primera solución y si la cuestión de la memoria es crucial, comprima el json del usuario antes de almacenarlo en redis.

  2. Si puede forzar el tamaño máximo de todos attributes. Entonces puede establecer hash-max-ziplist-entries / value y usar hashes como un hash por representación de usuario O como optimización de la memoria hash de este tema de una guía de Redis: https://redis.io/topics/memory-optimization y almacenar usuario como json string. De cualquier manera, también puede comprimir un usuario largo attributes.

¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 4)


Tags : / /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *