Redis toma toda la memoria y se bloquea

12

Se está ejecutando un servidor redis v2.8.4 en un Ubuntu 14.04 VPS con 8 GB de RAM y 16 GB de espacio de intercambio (en SSD). Sin embargo, htopmuestra que redissolo está ocupando 22.4 Gmemoria!

redis-serverfinalmente se estrelló por falta de memoria. Memy Swpambos alcanzan el 100% y luego redis-serverse mata junto con otros servicios.

De dmesg:

[165578.047682] Out of memory: Kill process 10155 (redis-server) score 834 or sacrifice child
[165578.047896] Killed process 10155 (redis-server) total-vm:31038376kB, anon-rss:5636092kB, file-rss:0kB

Reiniciar redis-serverdesde etiher un bloqueo de OOM o service redis-server force-reloadcausa que el uso de memoria caiga a <100 MB.

Pregunta: ¿Por qué redis-serverocupa más y más memoria hasta que se bloquea? como podemos prevenir esto?

¿Es cierto que la configuración maxmemoryno funcionará porque una vez que redis alcance el maxmemorylímite, comenzará a eliminar datos?

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Después de reiniciar redis-server

ingrese la descripción de la imagen aquí ingrese la descripción de la imagen aquí

Versión Redis: Redis server v=2.8.4 sha=00000000:0 malloc=jemalloc-3.4.1 bits=64 build=a44a05d76f06a5d9


Actualizar

Cuando se htopinforma que el uso de memoria redis-serverdebe ser 4.4G RAM y 22.6G Swap, la cantidad de espacio ocupado por todas las teclas en redis es solo 60.59636307 MB, según lo informado por rdbtools . Esta es también la cantidad de RAM que ocupa redis-serverinmediatamente después de reiniciarse.

INFO ALLcuando redis-serverestá tomando toneladas de memoria

mem_fragmentation_ratio:0.19

127.0.0.1:6379> INFO all

# Server
redis_version:2.8.4
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:a44a05d76f06a5d9
redis_mode:standalone
os:Linux 3.13.0-24-generic x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.2
process_id:26858
run_id:4d4a507b325e567d5ada203a0c65891bcf4d02de
tcp_port:6379
uptime_in_seconds:100011
uptime_in_days:1
hz:10
lru_clock:165668
config_file:/etc/redis/redis.conf

# Clients
connected_clients:60
client_longest_output_list:768774
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:23973468008
used_memory_human:22.33G
used_memory_rss:4563857408
used_memory_peak:24083474760
used_memory_peak_human:22.43G
used_memory_lua:33792
mem_fragmentation_ratio:0.19
mem_allocator:jemalloc-3.4.1

# Persistence
loading:0
rdb_changes_since_last_save:127835154
rdb_bgsave_in_progress:0
rdb_last_save_time:1406716479
rdb_last_bgsave_status:err
rdb_last_bgsave_time_sec:1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok

# Stats
total_connections_received:110
total_commands_processed:386765263
instantaneous_ops_per_sec:3002
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:1385878
keyspace_misses:23655
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:82

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:10547.48
used_cpu_user:8240.36
used_cpu_sys_children:201.83
used_cpu_user_children:914.86

# Commandstats
cmdstat_del:calls=136,usec=1407,usec_per_call=10.35
cmdstat_exists:calls=161428,usec=1391252,usec_per_call=8.62
cmdstat_zadd:calls=64149642,usec=936323882,usec_per_call=14.60
cmdstat_zrem:calls=137,usec=2131,usec_per_call=15.55
cmdstat_zremrangebyscore:calls=2293,usec=111905082,usec_per_call=48802.91
cmdstat_zrange:calls=7925,usec=285907448,usec_per_call=36076.65
cmdstat_zrangebyscore:calls=921434,usec=292731002,usec_per_call=317.69
cmdstat_zcount:calls=8,usec=172,usec_per_call=21.50
cmdstat_zrevrange:calls=191184,usec=965447,usec_per_call=5.05
cmdstat_zcard:calls=5180,usec=13502,usec_per_call=2.61
cmdstat_zscore:calls=29856,usec=576044,usec_per_call=19.29
cmdstat_hset:calls=64145124,usec=199407095,usec_per_call=3.11
cmdstat_hget:calls=248487,usec=501220,usec_per_call=2.02
cmdstat_hincrby:calls=128339355,usec=2071112929,usec_per_call=16.14
cmdstat_hgetall:calls=193747,usec=1608260,usec_per_call=8.30
cmdstat_select:calls=1,usec=5,usec_per_call=5.00
cmdstat_rename:calls=134,usec=1090,usec_per_call=8.13
cmdstat_keys:calls=4503,usec=4997628,usec_per_call=1109.84
cmdstat_bgsave:calls=2,usec=20012,usec_per_call=10006.00
cmdstat_type:calls=603,usec=2736,usec_per_call=4.54
cmdstat_multi:calls=64181979,usec=383633610,usec_per_call=5.98
cmdstat_exec:calls=64181979,usec=4403181204,usec_per_call=68.60
cmdstat_info:calls=126,usec=28675,usec_per_call=227.58

# Keyspace
db0:keys=2109,expires=0,avg_ttl=0
Nyxynyx
fuente

Respuestas:

8
  1. Use maxmemorypara establecer un límite de cuánto puede crecer también su base de datos Redis. De lo contrario, Redis crecerá hasta que el sistema operativo lo mate una vez que se agote la memoria (según su experiencia actual).
  2. El uso de maxmemorydebe combinarse con maxmemory-policy: puede elegir entre diferentes políticas de desalojo según los requisitos de su caso de uso. Por ejemplo, si utiliza la allkeys-lrupolítica de desalojo, Redis comenzará a desalojar los datos (los menos utilizados recientemente) una vez que maxmemoryse haya alcanzado. Alternativamente, puede indicarle a Redis que desaloje solo los datos caducables con las políticas volatile-lruo volatile-random. Por último, puede configurar la política noevictionpero eso significaría que una vez que se haya agotado la memoria, Redis negará más escrituras con un mensaje OOM.

Editar:

Primero deshabilite el intercambio: Redis e intercambio no se mezclan fácilmente y esto ciertamente puede causar lentitud.

También haga en free -mlugar de arriba para obtener una imagen completa del estado de su RAM ( http://www.linuxatemyram.com/ ).

Itamar Haber
fuente
Gracias, estoy confundido en cuanto a por qué el uso de la memoria sigue creciendo, pero hacer bgsavey reiniciar redis-serverhace que el uso de la memoria caiga a un valor más razonable de 70 MB. ¿Podría ser esto una pérdida de memoria?
Nyxynyx
Posible pero poco probable (u otras personas lo habrían informado) ... Más probablemente un problema de fragmentación. La próxima vez que eso suceda, publique el resultado de su Redis INFO ALL. Si mi suposición es correcta, la mem_fragmentation_ratiovoluntad se disparará.
Itamar Haber
redis-serveracumula toda la memoria y se cuelga todos los días. Está a punto de usar toda la memoria ahora, así que capturé la salida INFO ALLy la agregué al OP. mem_fragmentation_ratio:0.19
Nyxynyx
Si los conjuntos de datos de redis no superan los 250 MB y maxmemoryse configuran en 1 GB, ¿significa esto que cuando el uso de memoria de redis llegue a 1 GB, el desalojo aún eliminará los datos? Dado que redis mem_fragmentation_ratioes 0.19, ¿significa que hay demasiada fragmentación, o demasiado almacenado en el intercambio, o ambos? ¿Alguna forma de reducir la fragmentación?
Nyxynyx
Cuando redis-server está a punto de bloquearse debido a OOM, rdbtools muestra que las claves en redis solo ocupan 60MB. Esto parece una fragmentación extremadamente grave? Teniendo en cuenta que ocupa 4.4GB de RAM y 22.4G de intercambio.
Nyxynyx
5

Es casi seguro que es fragmentación de la memoria, ya que redis es bien conocido y amado en la producción y probablemente no haya encontrado una pérdida de memoria.

Las recomendaciones sobre cómo establecer el tamaño del grupo no ayudarán a la fragmentación. Tendrá que reducir específicamente el tamaño de Redis, más bajo que el tamaño real de su memoria, porque Redis no puede explicar la fragmentación, pero, en términos de una respuesta breve, tendrá que hacerlo y comenzar a planear reiniciar su servidores con frecuencia.

Mi regla general para trabajar con una variedad de sistemas operativos y bases de datos en memoria es que necesita 2 veces su memoria real, y el tamaño de la memoria se estabilizará en aproximadamente 2 semanas.

Sin embargo, eso depende de sus patrones de asignación reales y del asignador de memoria que esté utilizando.

En este momento, el mejor asignador de memoria que he encontrado para servidores es JEMalloc. Lo usamos en Aerospike ahora para reducir (casi eliminar) la fragmentación de la memoria a largo plazo. JEMalloc tiene una función que le permite crear una "arena" (grupo) de memoria y, en cualquier asignación, elegir qué grupo, lo que le brinda asignaciones de tamaño similar y administrar asignaciones de vida útil de memoria similares. Ha sido una gran victoria para nosotros en el tipo de casos que está discutiendo.

El motor PHP de Zend es sofisticado a este respecto, porque todas las asignaciones dentro del motor están en la memoria por transacción o en la memoria global. La memoria por transacción se libera de una sola vez al final de la transacción y, por lo tanto, puede ser muy eficiente.

Si está en Linux, el asignador de memoria del núcleo (Clib) ha dado varios giros y vueltas, y la versión en la que se encuentre determinará drásticamente la cantidad de fragmentación, al igual que el patrón de aplicación real. Por ejemplo, algunos asignadores son mucho mejores cuando crecen objetos ligeramente, algunos son mucho peores. Lamentablemente, incluso discutir con otros usuarios de Redis significa hablar sobre qué sistema operativo y qué versión de sistema operativo está utilizando.

El hecho de que pueda reiniciar el servidor (desde la persistencia) y recuperar su memoria podría significar una fuga, pero lo más probable es que se trate de fragmentación.

  1. No permitir el intercambio (es mejor para OOM que intercambiar, para redis)
  2. Disminuya el tamaño de la memoria de redis
  3. Reiniciar en un horario
Brian Bulkowski
fuente
¿Cómo disminuiría el tamaño de la memoria al ajustar maxmemory?
Nyxynyx