Redis occupa tutta la memoria e gli arresti anomali


12

Un server redis v2.8.4 è in esecuzione su Ubuntu 14.04 VPS con 8 GB di RAM e 16 GB di spazio di swap (su SSD). Tuttavia htopmostra che redissolo sta occupando la 22.4 Gmemoria!

redis-serveralla fine si è schiantato a causa di fuori memoria. Memed Swpentrambi colpisce il 100%, quindi redis-serverviene ucciso insieme ad altri servizi.

Da 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

Il riavvio redis-serverda un altro arresto anomalo della OOM o service redis-server force-reloadfa sì che l'utilizzo della memoria scenda a <100 MB.

Domanda: Perché redis-serveroccupa sempre più memoria fino a quando non si blocca? Come possiamo prevenirlo?

È vero che l'impostazione maxmemorynon funzionerà perché una volta raggiunto il maxmemorylimite, inizierà a rimuovere i dati?

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Dopo aver riavviato redis-server

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

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


Aggiornare

Quando viene htopsegnalato che l'utilizzo della memoria redis-serverdeve essere 4.4G RAM e 22.6G Swap, la quantità di spazio occupato da tutte le chiavi in ​​redis è solo 60.59636307 MB, come riportato da rdbtools . Questa è anche la quantità di RAM occupata da redis-serversubito dopo il riavvio.

INFO ALLquando redis-serversta occupando tonnellate di 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

Risposte:


8
  1. Utilizzare il maxmemoryper impostare un limite alla crescita del database Redis. In caso contrario, Redis crescerà fino a quando il sistema operativo non lo ucciderà una volta che la memoria è esaurita (secondo l'esperienza corrente).
  2. L'uso di maxmemorydovrebbe essere abbinato a maxmemory-policy: puoi scegliere tra diverse politiche di sfratto a seconda delle esigenze del tuo caso d'uso. Ad esempio, se si utilizza la allkeys-lrupolitica di sfratto, Redis inizierà effettivamente a sfrattare i dati (utilizzati meno di recente) una volta maxmemoryraggiunti. In alternativa, è possibile indicare a Redis di eliminare solo i dati in scadenza con i criteri volatile-lruo volatile-random. Infine, è possibile impostare la politica su noevictionma ciò significherebbe che una volta che la memoria è stata esaurita, Redis negherà ulteriori scritture con un messaggio OOM.

Modificare:

Innanzitutto disabilita lo swap - Redis e swap non si mescolano facilmente e questo può certamente causare lentezza.

Inoltre, fai free -minvece di top per il quadro completo dello stato della tua RAM ( http://www.linuxatemyram.com/ ).


Grazie, sono confuso sul motivo per cui l'utilizzo della memoria continua a crescere, ma fare bgsavee riavviare redis-serverfa scendere l'utilizzo della memoria a un valore più ragionevole di 70 MB. Potrebbe essere una perdita di memoria?
Nyxynyx,

Possibile ma improbabile (o altre persone lo avrebbero segnalato) ... Più probabilmente un problema di frammentazione. La prossima volta che succede, pubblica l'output del tuo Redis ' INFO ALL. Se la mia ipotesi è corretta, la mem_fragmentation_ratiovolontà sarà alle stelle.
Itamar Haber,

redis-servercarica tutta la memoria e si blocca ogni giorno. Sta per esaurire tutta la memoria ora, quindi ho acquisito l'output INFO ALLe aggiunto all'OP. mem_fragmentation_ratio:0.19
Nyxynyx,

Se i set di dati redis non superano i 250 MB ed maxmemoryè impostato su 1 GB, significa che quando l'utilizzo di mem di redis raggiunge 1 GB, lo sfratto rimuoverà comunque i dati? Dal momento che Redis mem_fragmentation_ratioè 0.19, significa che c'è troppa frammentazione, o troppo è memorizzato in swap, o entrambi? Un modo per ridurre la frammentazione?
Nyxynyx,

Quando redis-server sta per arrestarsi a causa di OOM, rdbtools mostra che le chiavi in ​​redis occupano solo 60 MB. Sembra una frammentazione estremamente seria? Considerando che occupa 4,4 GB di RAM e 22,4 G di scambio.
Nyxynyx,

5

Questa è quasi sicuramente una frammentazione della memoria, poiché redis è ben noto e amato nella produzione e probabilmente non hai trovato una perdita di memoria.

I consigli sull'impostazione delle dimensioni del pool non aiuteranno la frammentazione. Dovrai ridurre in modo specifico la dimensione di Redis - inferiore alla dimensione della memoria effettiva - perché Redis non può tenere conto della frammentazione - ma, in termini di una risposta breve, dovrai farlo e iniziare a pianificare il riavvio del tuo server frequentemente.

La mia regola empirica lavorando con una varietà di sistemi operativi e database in memoria è che hai bisogno di 2x la tua memoria effettiva e la dimensione della memoria si stabilizzerà in circa 2 settimane.

Tuttavia, ciò dipende dai modelli di allocazione effettivi e dall'allocatore di memoria che si sta utilizzando.

In questo momento, il miglior allocatore di memoria che ho trovato per i server è JEMalloc. Lo usiamo ora su Aerospike per ridurre (quasi rimuovere) la frammentazione della memoria a lungo termine. JEMalloc ha una funzione che ti consente di creare una "arena" di memoria (pool) e, su qualsiasi allocazione, scegliere quale pool, dandoti così allocazioni di dimensioni simili e gestire allocazioni di durata della memoria simili. È stata una grande vittoria per noi nel tipo di casi di cui stai discutendo.

Il motore Zend PHP è sofisticato in questo senso, perché tutte le allocazioni all'interno del motore sono nella memoria per transazione o nella memoria globale. La memoria per transazione viene liberata in un colpo solo alla fine della transazione e quindi può essere molto efficiente.

Se sei su Linux, l'allocatore di memoria del kernel (Clib) ha preso una serie di colpi di scena, e quale versione stai determinando in modo drammatico la quantità di frammentazione, così come il modello di applicazione reale. Ad esempio, alcuni allocatori sono molto meglio quando si stanno leggermente crescendo oggetti, altri sono molto peggio. Purtroppo, anche discutere con altri utenti Redis significa parlare di quale sistema operativo e quale versione del sistema operativo si sta utilizzando.

Il fatto che sia possibile riavviare il server (dalla persistenza) e recuperare la memoria potrebbe significare una perdita, ma più probabilmente punta alla frammentazione.

  1. Non consentire lo scambio (è meglio OOM che scambiare, per redis)
  2. Riduci le dimensioni della memoria di Redis
  3. Riavvia secondo un programma

Come ridurre la dimensione della memoria, regolando maxmemory?
Nyxynyx,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.