performance - cache - Redis 10 veces más el uso de memoria que los datos
redis sql (3)
Tengo una pequeña pregunta.
Estoy tratando de almacenar una lista de palabras en redis. El rendimiento es genial.
Mi enfoque es hacer un conjunto llamado "palabras" y agregar cada palabra nueva a través de ''sadd''.
Este es el problema al agregar un archivo de 15.9 mb y que contiene aproximadamente un millón de palabras, el proceso de redis-server consume 160 mb de RAM. ¿Cómo es que estoy usando 10 veces la memoria, hay alguna forma mejor de abordar este problema?
Gracias por adelantado
¿ BGSAVE
persistir en la base de datos (por ejemplo, BGSAVE
), apagando el servidor y volviéndolo a hacer? Debido al comportamiento de la fragmentación, cuando vuelve a aparecer y llena sus datos desde el archivo RDB guardado, puede necesitar menos memoria.
También: ¿Con qué versión de Redis trabajas? Eche un vistazo a esta publicación del blog : dice que la fragmentación se resolvió parcialmente a partir de la versión 2.4.
Bueno, esto se espera de cualquier almacenamiento de datos eficiente: las palabras deben ser indexadas en la memoria en una estructura de datos dinámica de celdas vinculadas por punteros. El tamaño de la estructura de los metadatos, los punteros y la fragmentación interna del asignador de memoria es la razón por la que los datos requieren mucha más memoria que un archivo plano correspondiente.
Un conjunto de Redis se implementa como una tabla hash. Esto incluye:
- una serie de punteros que crecen geométricamente (potencias de dos)
- se puede requerir una segunda matriz cuando el reajuste incremental está activo
- celdas de la lista de un solo enlace que representan las entradas en la tabla hash (3 punteros, 24 bytes por entrada)
- Envoltorios de objetos Redis (uno por valor) (16 bytes por entrada)
- los datos reales en sí (cada uno de ellos con un prefijo de 8 bytes para el tamaño y la capacidad)
Todos los tamaños anteriores se dan para la implementación de 64 bits. Teniendo en cuenta la sobrecarga del asignador de memoria, Redis toma al menos 64 bytes por elemento del conjunto (encima de los datos) para una versión reciente de Redis usando el asignador jemalloc (> = 2.4)
Redis proporciona optimizaciones de memoria para algunos tipos de datos, pero no cubren conjuntos de cadenas. Si realmente necesitas optimizar el consumo de memoria de los conjuntos, hay algunos trucos que puedes usar. No haría esto por solo 160 MB de RAM, pero si tiene datos más grandes, esto es lo que puede hacer.
Si no necesita la unión, intersección, capacidades de diferencia de conjuntos, entonces puede almacenar sus palabras en objetos hash. El beneficio es que los objetos hash pueden ser optimizados automáticamente por Redis usando zipmap si son lo suficientemente pequeños. El mecanismo zipmap ha sido reemplazado por ziplist en Redis> = 2.6, pero la idea es la misma: usar una estructura de datos serializada que pueda caber en los cachés de la CPU para obtener tanto rendimiento como espacio de memoria compacto.
Para garantizar que los objetos hash sean lo suficientemente pequeños, los datos podrían distribuirse de acuerdo con algún mecanismo de hash. Suponiendo que necesita almacenar 1M elementos, agregar una palabra podría implementarse de la siguiente manera:
- hash it modulo 10000 (hecho en el lado del cliente)
- Palabras HMSET: [hashnum] [palabra] 1
En lugar de almacenar:
words => set{ hi, hello, greetings, howdy, bonjour, salut, ... }
usted puede almacenar:
words:H1 => map{ hi:1, greetings:1, bonjour:1, ... }
words:H2 => map{ hello:1, howdy:1, salut:1, ... }
...
Para recuperar o verificar la existencia de una palabra, es lo mismo (tacharla y usar HGET o HEXISTAS).
Con esta estrategia, se puede hacer un ahorro significativo de memoria siempre que el módulo del hash se elija de acuerdo con la configuración de zipmap (o ziplist para Redis> = 2.6):
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
Cuidado: el nombre de estos parámetros ha cambiado con Redis> = 2.6.
Aquí, el módulo 10000 para artículos de 1M significa 100 artículos por objetos hash, lo que garantizará que todos se almacenen como zipmaps / ziplists.
En cuanto a mis experimentos, es mejor almacenar sus datos dentro de una tabla / diccionario hash. el mejor de los casos que he alcanzado después de una gran cantidad de puntos de referencia es almacenar dentro de sus entradas de datos de tabla hash que no superan las 500 teclas.
Probé el conjunto de cadenas estándar / obtener, para 1 millón de claves / valores, el tamaño era de 79 MB. Es muy grande en caso de que tengas grandes números como 100 millones que usarán alrededor de 8 GB.
Intenté hashes para almacenar los mismos datos, para el mismo millón de claves / valores, el tamaño era cada vez más pequeño de 16 MB.
Haga una prueba en caso de que si alguien necesita el código de evaluación comparativa, envíeme un correo.