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)
# 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 client v4.0.1 for redis://127.0.0.1:6379/0>
> 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{ |i| redis.me_set( "t:#{i}", txt[rand(50000), 63] ) } }; :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.times{ |i| redis.me_set( "t:#{i}", txt[rand(50000), i % 512 == 0 ? 65 : 63] ) } }; :done
> ap redis.info(:memory)
{
"used_memory" => "1876064",
"used_memory_human" => "1.79M", # ~ 134 bytes per pair
....
}
redis.pipelined{ 10000.times{ |i| 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 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 muchas veces los hashes contienen solo unos pocos campos. Cuando los hashes son pequeños, podemos codificarlos en una estructura de datos O (N), como una matriz lineal con pares de valores de clave con prefijo de longitud. 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 el número de elementos que contiene crezca demasiado
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:
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.
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.