Redis ocupa toda a memória e falhas

12

Um servidor redis v2.8.4 está sendo executado em um Ubuntu 14.04 VPS com 8 GB de RAM e 16 GB de espaço de troca (em SSDs). No entanto, htopmostra que redissozinho está ocupando 22.4 Gmemória!

redis-servereventualmente travou devido a falta de memória. Meme os Swpdois hits 100% redis-serversão mortos juntamente com outros serviços.

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 a redis-serverpartir de uma falha no OOM ou service redis-server force-reloadfaz com que o uso da memória caia para <100MB.

Pergunta: Por que redis-serverocupa mais e mais memória até travar? Como podemos evitar isso?

É verdade que a configuração maxmemorynão funcionará porque, quando o redis atingir o maxmemorylimite, ele começará a remover os dados?

insira a descrição da imagem aqui insira a descrição da imagem aqui

Depois de reiniciar o redis-server

insira a descrição da imagem aqui insira a descrição da imagem aqui

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


Atualizar

Quando htoprelata que o uso da memória redis-serveré de 4.4G RAM e 22.6G Swap, a quantidade de espaço ocupada por todas as chaves em redis é apenas 60.59636307 MB, conforme relatado pelo rdbtools . Essa também é a quantidade de RAM consumida redis-serverlogo após a reinicialização.

INFO ALLquando redis-serverestá ocupando toneladas de memória

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
fonte

Respostas:

8
  1. Use maxmemorypara definir um limite de quanto o banco de dados Redis também pode crescer. Caso contrário, o Redis aumentará até que o sistema operacional o mate quando a memória estiver esgotada (de acordo com sua experiência atual).
  2. O uso de maxmemorydeve ser associado maxmemory-policy- você pode escolher entre diferentes políticas de remoção, dependendo dos requisitos do seu caso de uso. Por exemplo, se você usar a allkeys-lrupolítica de despejo, o Redis realmente começará a despejar (o menos usado recentemente) dados uma vez maxmemoryatingidos. Como alternativa, você pode instruir o Redis a remover apenas dados expiráveis ​​com as políticas volatile-lruou volatile-random. Por fim, você pode definir a política como, noevictionmas isso significaria que, uma vez esgotada a memória, o Redis negará outras gravações com uma mensagem OOM.

Editar:

Primeiro desabilite a troca - Redis e troca não se misturam facilmente e isso certamente pode causar lentidão.

Faça também, em free -mvez de top, a imagem completa do estado da sua RAM ( http://www.linuxatemyram.com/ ).

Itamar Haber
fonte
Obrigado, estou confuso sobre o motivo pelo qual o uso da memória continua aumentando, mas fazer um bgsavee reiniciar redis-serverfaz com que o uso da memória caia para um valor mais razoável de 70 MB. Isso poderia ser um vazamento de memória?
Nyxynyx
Possível, mas improvável (ou outras pessoas teriam relatado isso) ... Provavelmente, um problema de fragmentação. Da próxima vez que isso acontecer, publique a saída do seu Redis ' INFO ALL. Se meu palpite estiver correto, a mem_fragmentation_ratiovontade estará no céu.
Itamar Haber
redis-servermonopoliza toda a memória e trava todos os dias. Está prestes a usar toda a memória agora, então eu capturei a saída INFO ALLe a adicionei ao OP. mem_fragmentation_ratio:0.19
Nyxynyx
Se os conjuntos de dados redis não excederem 250 MB e maxmemoryestiver definido como 1 GB, isso significa que quando o uso de mem do redis atingir 1 GB, a remoção ainda removerá os dados? Como o redis mem_fragmentation_ratioé 0.19, isso significa que há muita fragmentação ou muito armazenamento em swap, ou ambos? Alguma maneira de reduzir a fragmentação?
Nyxynyx
Quando o redis-server está prestes a falhar devido ao OOM, o rdbtools mostra que as chaves no redis ocupam apenas 60 MB. Parece fragmentação extremamente séria? Considerando a utilização de 4.4GB de RAM e 22.4G de Swap.
Nyxynyx
5

É quase certamente uma fragmentação da memória, pois o redis é bem conhecido e amado na produção e você provavelmente não encontrou um vazamento de memória.

As recomendações sobre como definir o tamanho do pool não ajudarão na fragmentação. Você precisará diminuir especificamente o tamanho do Redis - menor que o tamanho real da memória - porque os Redis não podem explicar a fragmentação - mas, em termos de uma resposta curta, você precisará fazer isso e iniciar o plano de reiniciar o seu servidores com freqüência.

Minha regra prática ao trabalhar com uma variedade de sistemas operacionais e bancos de dados na memória é que você precisa de 2x a sua memória real e o tamanho da memória estabilizará em cerca de duas semanas.

No entanto, isso depende dos seus padrões de alocação reais e do alocador de memória que você está usando.

No momento, o melhor alocador de memória que encontrei para servidores é o JEMalloc. Agora o usamos no Aerospike para reduzir (quase remover) a fragmentação de memória de longo prazo. O JEMalloc possui um recurso que permite criar uma "arena" de memória (pool) e, em qualquer alocação, escolher qual pool, fornecendo alocações de tamanho semelhante e gerenciar alocações de duração da memória semelhantes. Tem sido uma grande vitória para nós no tipo de casos que você está discutindo.

O mecanismo Zend PHP é sofisticado nesse aspecto, porque todas as alocações dentro do mecanismo estão na memória por transação ou na memória global. A memória por transação é liberada de uma só vez no final da transação e, portanto, pode ser muito eficiente.

Se você estiver no Linux, o alocador de memória do kernel (Clib) sofreu várias reviravoltas, e em qual versão você está determinará dramaticamente a quantidade de fragmentação, assim como o padrão real do aplicativo. Por exemplo, alguns alocadores são muito melhores quando você cresce objetos levemente, outros são muito piores. Lamentavelmente, até discutir com outros usuários Redis significa falar sobre qual SO e qual versão do SO você está usando.

O fato de você poder reiniciar o servidor (por persistência) e recuperar a memória pode significar um vazamento, mas é mais provável que aponte para fragmentação.

  1. Proibir troca (é melhor para OOM do que trocar, para redis)
  2. Diminuir o tamanho da memória dos redis
  3. Reiniciar em uma programação
Brian Bulkowski
fonte
Como você diminuiria o tamanho da memória, ajustando maxmemory?
Nyxynyx