Como fazer com que o killer do Linux OOM não mate meu processo?

28

Como faço para que o killer do Linux OOM não mate meus processos quando a memória física está baixa, mas há bastante espaço de troca?

Desativei o OOM e supercomprometi com sysctl vm.overcommit_memory = 2.

A VM tem 3 GB de troca sem fragmentação totalmente gratuita e os processos que estão sendo mortos por OOM têm um uso máximo de memória menor que 200 MB.

Eu sei que a troca a longo prazo será horrível para o desempenho, mas eu preciso usar a troca agora mesmo para fazer testes funcionais sob valgrind, onde os requisitos de memória são muito maiores.

Mar  7 02:43:11 myhost kernel: memcheck-amd64- invoked oom-killer: gfp_mask=0x24002c2, order=0, oom_score_adj=0
Mar  7 02:43:11 myhost kernel: memcheck-amd64- cpuset=/ mems_allowed=0
Mar  7 02:43:11 myhost kernel: CPU: 0 PID: 3841 Comm: memcheck-amd64- Not tainted 4.4.0-x86_64-linode63 #2
Mar  7 02:43:11 myhost kernel: Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.8.2-0-g33fbe13 by qemu-project.org 04/01/2014
Mar  7 02:43:11 myhost kernel: 0000000000000000 0000000000000000 ffffffff8158cbcc ffff880032d7bc18
Mar  7 02:43:11 myhost kernel: ffffffff811c6a55 00000015118e701d ffffffff81044a8d 00000000000003e2
Mar  7 02:43:11 myhost kernel: ffffffff8110f5a1 0000000000000000 00000000000003e2 ffffffff81cf15cc
Mar  7 02:43:11 myhost kernel: Call Trace:
Mar  7 02:43:11 myhost kernel: [<ffffffff8158cbcc>] ? dump_stack+0x40/0x50
Mar  7 02:43:11 myhost kernel: [<ffffffff811c6a55>] ? dump_header+0x59/0x1dd
Mar  7 02:43:11 myhost kernel: [<ffffffff81044a8d>] ? kvm_clock_read+0x1b/0x1d
Mar  7 02:43:11 myhost kernel: [<ffffffff8110f5a1>] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x1e
Mar  7 02:43:11 myhost kernel: [<ffffffff81183316>] ? oom_kill_process+0xc0/0x34f
Mar  7 02:43:11 myhost kernel: [<ffffffff811839b2>] ? out_of_memory+0x3bf/0x406
Mar  7 02:43:11 myhost kernel: [<ffffffff81187bbd>] ? __alloc_pages_nodemask+0x8ba/0x9d8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b82e8>] ? alloc_pages_current+0xbc/0xe0
Mar  7 02:43:11 myhost kernel: [<ffffffff811b096c>] ? __vmalloc_node_range+0x12d/0x20a
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b0a83>] ? __vmalloc_node+0x3a/0x3f
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811b0ab0>] ? vmalloc+0x28/0x2a
Mar  7 02:43:11 myhost kernel: [<ffffffff811e0e62>] ? alloc_fdtable+0x6a/0xd8
Mar  7 02:43:11 myhost kernel: [<ffffffff811e1338>] ? dup_fd+0x103/0x1f0
Mar  7 02:43:11 myhost kernel: [<ffffffff810dd143>] ? copy_process+0x5aa/0x160d
Mar  7 02:43:11 myhost kernel: [<ffffffff8110f5a1>] ? __raw_callee_save___pv_queued_spin_unlock+0x11/0x1e
Mar  7 02:43:11 myhost kernel: [<ffffffff810de2fc>] ? _do_fork+0x7d/0x291
Mar  7 02:43:11 myhost kernel: [<ffffffff810ea186>] ? __set_current_blocked+0x47/0x52
Mar  7 02:43:11 myhost kernel: [<ffffffff810ea1f2>] ? sigprocmask+0x61/0x6a
Mar  7 02:43:11 myhost kernel: [<ffffffff81998eae>] ? entry_SYSCALL_64_fastpath+0x12/0x71
Mar  7 02:43:11 myhost kernel: Mem-Info:
Mar  7 02:43:11 myhost kernel: active_anon:15 inactive_anon:18 isolated_anon:0
Mar  7 02:43:11 myhost kernel: active_file:7 inactive_file:8 isolated_file:0
Mar  7 02:43:11 myhost kernel: unevictable:0 dirty:3 writeback:26 unstable:0
Mar  7 02:43:11 myhost kernel: slab_reclaimable:1798 slab_unreclaimable:3674
Mar  7 02:43:11 myhost kernel: mapped:8 shmem:1 pagetables:752 bounce:0
Mar  7 02:43:11 myhost kernel: free:1973 free_pcp:0 free_cma:0
Mar  7 02:43:11 myhost kernel: Node 0 DMA free:3944kB min:60kB low:72kB high:88kB active_anon:0kB inactive_anon:0kB active_file:28kB inactive_file:32kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB
 mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:72kB slab_unreclaimable:236kB kernel_stack:48kB pagetables:60kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:36
0 all_unreclaimable? yes
Mar  7 02:43:11 myhost kernel: lowmem_reserve[]: 0 972 972 972
Mar  7 02:43:11 myhost kernel: Node 0 DMA32 free:3948kB min:3956kB low:4944kB high:5932kB active_anon:60kB inactive_anon:72kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:1032064kB manag
ed:999552kB mlocked:0kB dirty:12kB writeback:104kB mapped:32kB shmem:4kB slab_reclaimable:7120kB slab_unreclaimable:14460kB kernel_stack:2112kB pagetables:2948kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_t
mp:0kB pages_scanned:792 all_unreclaimable? yes
Mar  7 02:43:11 myhost kernel: lowmem_reserve[]: 0 0 0 0
Mar  7 02:43:11 myhost kernel: Node 0 DMA: 20*4kB (UM) 17*8kB (UM) 13*16kB (M) 14*32kB (UM) 8*64kB (UM) 4*128kB (M) 4*256kB (M) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 3944kB
Mar  7 02:43:11 myhost kernel: Node 0 DMA32: 934*4kB (UM) 28*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3960kB
Mar  7 02:43:11 myhost kernel: 71 total pagecache pages
Mar  7 02:43:11 myhost kernel: 42 pages in swap cache
Mar  7 02:43:11 myhost kernel: Swap cache stats: add 245190, delete 245148, find 77026/136093
Mar  7 02:43:11 myhost kernel: Free swap  = 3118172kB
Mar  7 02:43:11 myhost kernel: Total swap = 3334140kB
Mar  7 02:43:11 myhost kernel: 262014 pages RAM
Mar  7 02:43:11 myhost kernel: 0 pages HighMem/MovableOnly
Mar  7 02:43:11 myhost kernel: 8149 pages reserved
Mar  7 02:43:11 myhost kernel: [ pid ]   uid  tgid total_vm      rss nr_ptes nr_pmds swapents oom_score_adj name
Mar  7 02:43:11 myhost kernel: [ 2054]     0  2054     5101        1      15       4      283             0 upstart-udev-br
Mar  7 02:43:11 myhost kernel: [ 2063]     0  2063    12362        1      28       4      184         -1000 systemd-udevd
Mar  7 02:43:11 myhost kernel: [ 3342]   102  3342     9780        1      23       3       89             0 dbus-daemon
Mar  7 02:43:11 myhost kernel: [ 3423]     0  3423    10864        1      26       3       85             0 systemd-logind
Mar  7 02:43:11 myhost kernel: [ 3441]     0  3441    15344        0      34       3      184         -1000 sshd
Mar  7 02:43:11 myhost kernel: [ 3450]     0  3450     4786        0      14       3       43             0 atd
Mar  7 02:43:11 myhost kernel: [ 3451]     0  3451     5915        0      17       4       65             0 cron
Mar  7 02:43:11 myhost kernel: [ 3457]   101  3457    63962        0      28       3      202             0 rsyslogd
Mar  7 02:43:11 myhost kernel: [ 3516]     0  3516     3919        1      13       3      156             0 upstart-file-br
Mar  7 02:43:11 myhost kernel: [ 3518]     0  3518     4014        0      13       3      265             0 upstart-socket-
Mar  7 02:43:11 myhost kernel: [ 3557]     0  3557    66396        0      32       3     1802             0 fail2ban-server
Mar  7 02:43:11 myhost kernel: [ 3600]     0  3600     3956        1      13       3       39             0 getty
Mar  7 02:43:11 myhost kernel: [ 3601]     0  3601     3198        1      12       3       37             0 getty
Mar  7 02:43:11 myhost kernel: [ 3673]     0  3673    26411        1      55       3      252             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3740]  1000  3740    26411        1      52       3      253             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3741]  1000  3741     5561        0      16       3      431             0 bash
Mar  7 02:43:11 myhost kernel: [ 3820]   103  3820     7863        1      21       3      152             0 ntpd
Mar  7 02:43:11 myhost kernel: [ 3837]  1000  3837    31990        0      58       4    12664             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3841]  1000  3841    32006        0      59       4    12812             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3844]  1000  3844    31950        0      57       4    12035             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3849]  1000  3849    31902        0      56       4    11482             0 memcheck-amd64-
Mar  7 02:43:11 myhost kernel: [ 3853]  1000  3853     1087        0       7       3       27             0 lsof
Mar  7 02:43:11 myhost kernel: [ 3854]     0  3854    26140        5      55       3      230             0 sshd
Mar  7 02:43:11 myhost kernel: [ 3855]   104  3855    15699        0      33       3      202             0 sshd
Mar  7 02:43:11 myhost kernel: Out of memory: Kill process 3841 (memcheck-amd64-) score 11 or sacrifice child
Mar  7 02:43:11 myhost kernel: Killed process 3841 (memcheck-amd64-) total-vm:128024kB, anon-rss:0kB, file-rss:0kB

Isto é / proc / meminfo

MemTotal:        1015460 kB
MemFree:          277508 kB
MemAvailable:     322032 kB
Buffers:            8336 kB
Cached:            42208 kB
SwapCached:        46088 kB
Active:            58844 kB
Inactive:         116100 kB
Active(anon):      34784 kB
Inactive(anon):    89620 kB
Active(file):      24060 kB
Inactive(file):    26480 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       3334140 kB
SwapFree:        3215756 kB
Dirty:                16 kB
Writeback:             0 kB
AnonPages:        121128 kB
Mapped:            15072 kB
Shmem:                 4 kB
Slab:              22668 kB
SReclaimable:       8028 kB
SUnreclaim:        14640 kB
KernelStack:        2016 kB
PageTables:         2532 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     3841868 kB
Committed_AS:     380460 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
DirectMap4k:       14208 kB
DirectMap2M:     1034240 kB
DirectMap1G:           0 kB
    
por Coder 07.03.2016 / 09:00

6 respostas

34

Isso parece ser um problema na combinação de dois fatores:

  • Usando uma máquina virtual.
  • Um possível erro no kernel.

Esta é, em parte, uma das linhas que descreve por que isso acontece:

Mar  7 02:43:11 myhost kernel: memcheck-amd64- invoked oom-killer: gfp_mask=0x24002c2, order=0, oom_score_adj=0

A outra linha é esta:

Mar  7 02:43:11 myhost kernel: 0 pages HighMem/MovableOnly

| A primeira linha é a máscara GFP atribuída para a alocação. Basicamente descreve o que o kernel é permitido / não permitido fazer para satificar este pedido. A máscara indica um monte de sinalizadores padrão. O último bit, '2', no entanto, indica que a alocação de memória deve vir da HighMem zone.

Se você observar atentamente a saída do OOM, verá que a HighMem/Normal zone realmente existe.

Mar  7 02:43:11 myhost kernel: Node 0 DMA: 20*4kB (UM) 17*8kB (UM) 13*16kB (M) 14*32kB (UM) 8*64kB (UM) 4*128kB (M) 4*256kB (M) 0*512kB 1*1024kB (M) 0*2048kB 0*4096kB = 3944kB
Mar  7 02:43:11 myhost kernel: Node 0 DMA32: 934*4kB (UM) 28*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3960kB

HighMem (geralmente também chamado de Normal on x86_64) tende a mapear memória para regiões fora dos intervalos padrão de 896 MiB diretamente do kernel em sistemas de 32 bits. Em x86_64 HighMem/Normal parece cobrir todas as páginas acima do tamanho 3GiB.

DMA32 contém uma zona usada para memória que seria acessível em dispositivos DMA de 32 bits, ou seja, você pode endereçá-los com ponteiros de 4 bytes. Eu acredito que DMA é para dispositivos DMA de 16 bits.

Em geral, em sistemas com pouca memória Normal não existiria, já que DMA32 abrange todos os endereços virtuais disponíveis.

A razão pela qual você OOM mata é porque há uma alocação de memória para uma zona HighMem com 0 páginas disponíveis. Dado o manipulador de falta de memória não tem absolutamente nenhuma maneira de satisfazer fazendo esta zona ter páginas para usar trocando, matando outros processos ou qualquer outro truque, o OOM-killer apenas mata.

Acredito que isso seja causado pelo balão VM da VM durante a inicialização. Nos sistemas KVM, existem dois valores que você pode definir.

  • A memória atual.
  • A memória disponível.

A maneira como isso funciona é que você pode adicionar memória ao seu servidor até a memória disponível. Seu sistema, no entanto, recebe a memória atual.

Quando uma VM KVM é inicializada, ela começa com a quantidade máxima de memória possível (a memória disponível). Gradualmente, durante a fase de inicialização do sistema, o KVM recupera essa memória usando seu balão, deixando você com a configuração de memória atual que você possui.

É minha crença que é o que aconteceu aqui. Linode permite expandir a memória, dando muito mais no início do sistema.

Isso significa que há uma Normal/HighMem zone no início da vida útil do sistema. Quando o hypervisor o libera, a zona normal desaparece corretamente do gerenciador de memória. Mas, eu suspeito que o sinalizador definindo se a dita zona está disponível para alocar não é não desmarcada quando deveria. Isso leva o kernel a tentar alocar de uma região que não existe.

Em termos de resolver isso, você tem duas opções.

  1. Traga isso para as listas de discussão do kernel para ver se isso realmente é um bug, comportamento esperado ou nada a ver com o que estou dizendo.

  2. Solicite que o linode defina a 'memória disponível' no sistema para ser a mesma atribuição de 1GiB que a 'memória atual'. Assim, o sistema nunca faz balões e nunca recebe uma zona Normal na inicialização, mantendo a sinalização clara. Boa sorte para eles fazerem isso!

Você deve ser capaz de testar se este é o caso configurando sua própria VM na configuração KVM disponível para 6GiB, atual para 1GiB e executando seu teste usando o mesmo kernel para ver se esse comportamento que você vê acima ocorre. Se isso acontecer, altere a configuração 'disponível' para igualar a corrente de 1GiB e repita o teste.

Estou fazendo um monte de suposições aqui e lendo as linhas entre as linhas para chegar a essa resposta, mas o que estou dizendo parece se encaixar nos fatos já descritos.

Sugiro testar minha hipótese e deixar que todos saibam o resultado.

    
por 08.03.2016 / 12:35
31

Para responder sua pergunta, use oom_score_adj (kernel > = 2.6.36) ou para kernels anteriores (> = 2.6.11) oom_adj , veja man proc

/proc/[pid]/oom_score_adj (since Linux 2.6.36) This file can be used to adjust the badness heuristic used to select which process gets killed in out-of-memory conditions...

/proc/[pid]/oom_adj (since Linux 2.6.11) This file can be used to adjust the score used to select which process should be killed in an out-of-memory (OOM) situation...

Há muito mais para ler, mas definir oom_score_adj como -1000 ou oom_adj como -17 vai conseguir o que você deseja.

O problema é que alguma outra coisa será morta. Talvez seja melhor determinar por que a OOM está sendo invocada e lidar com isso.

    
por 07.03.2016 / 09:21
12

Vários pensamentos (dos meus comentários acima) e links para interresting leem sobre sua situação:

  • Eu recomendo que você verifique se 1) você pode endereçar mais de 3Gb com seu kernel atual & config (& cpu) [porque se 3Gb for um limite para o seu sistema & os, você está excedendo isto]. 2) que você permite a troca e o subsistema de troca está no lugar e funcionando. boa sorte (não vou explicar como, dependendo de suas configurações e especificidades. Os mecanismos de pesquisa ajudarão). E que você não está transbordando uma tabela de kernel (nb de pids? Ou qualquer outra coisa (alguns podem talvez ser configurados no tempo de compilação do kernel).

  • Verifique se a coisa toda (hardware, ou hardware simulado da vm, etc) é 64bits. (veja, por exemplo: link ). A cpu & sistema operacional host & subsistema vm & vm OS deve estar habilitado para 64 bits, caso contrário você não terá uma vm real de 64 bits

  • Algumas boas leituras:

    • Como diagnosticar causas de processos de assassinato de matadores de oom : neste mesmo site. Dá um bom link, link , e outro usuário introduz a ferramenta de topo, que poderia ajudar a diagnosticar o que acontece
    • link : 3.12 mostra a árvore de decisão para o OOM (de uma versão mais antiga, então ymmv Leia a fonte ^^)
    • link : "Domar o assassino da OOM" mostra, entre outras coisas, como criar um grupo "invencível" e colocar seu processo em
    • link : mostra alguns limites de kernel comuns
    • link : é uma boa leitura (espaço desperdiçado com alguns métodos de alocação, etc), embora seja realmente datado (e portanto, endereça apenas arquiteturas de 32 bits ...)
    • O link mostra algumas razões pelas quais "O assassino da OOM pode ser chamado mesmo quando ainda há bastante memória disponível"
    • link : permite verificar como seu sistema aloca memória
    • link : excelente resposta dando uma forma detalhada de saber realmente o que aconteceu (mas ... direcionado a uma pergunta de 32 bits, então ymmv. Ainda uma leitura e resposta incríveis, no entanto).
  • e finalmente: link mostra um maneira de evitar que o processo seja alvo do assassino! ( echo -17 > /proc/PROCESSPID/oom_adj ). Poderia ser propenso a mudanças, e poderia ser uma coisa ruim (causar outro tipo de falhas, como o sistema agora não pode simplesmente matar o infrator principal ...) Use com cautela. @iain note que "oom_adj" é para kernels mais antigos, e deve ser substituído por "oom_score_adj" nos mais novos. Obrigado, Iain)

por 07.03.2016 / 13:00
6

ao lado mencionado oom_score_adj aumentando para o processo em questão (o que provavelmente não ajudará muito - seria menos provável que esse processo fosse morto PRIMEIRO, mas como isso é apenas um sistema de processamento intensivo de memória provavelmente ganhou ” t recuperar até que seja finalmente morto), aqui estão algumas idéias para ajustar:

  • se você definir vm.overcommit_memory=2 , altere também vm.overcommit_ratio para talvez 90 (alternativamente, defina vm.overcommit_memory=0 - consulte documentação de supercomprometimento do kernel )
  • aumenta vm.min_free_kbytes para manter sempre alguma RAM física livre e assim reduz as chances de OOM precisar matar alguma coisa (mas não exagere, já que a OOM será instantaneamente).
  • aumenta vm.swappiness para 100 (para fazer com que troca de núcleos mais rapidamente )

Note que se você tiver pouca memória para realizar a tarefa, mesmo se você não tiver OOM, poderá (ou não) se tornar EXTREMAMENTE lento - trabalho de meia hora (no sistema com RAM suficiente) pode facilmente levar várias semanas (quando a RAM é substituída por swap) para completar em casos extremos, ou mesmo travar VM inteira. Isso é especialmente o caso se a troca for em discos rotacionais clássicos (em oposição a SSDs) devido a leituras / gravações aleatórias massivas que são muito caras nelas.

    
por 07.03.2016 / 23:39
3

Eu tentaria ativar o excesso de comprometimento e ver se isso ajuda. Seu processo parece falhar dentro de uma chamada fork , que requer tanta memória virtual quanto o processo inicial. overcommit_memory=2 não torna seu processo imune ao OOM killer, apenas impede que seu processo o acione atribuindo demais. Outros processos podem produzir erros de alocação não relacionados (por exemplo, obter um bloco de memória contíguo), que ainda acionam o killer da OOM e descartam seu processo.

Alternativamente (e mais ao ponto), como vários comentários sugerem, compre mais RAM.

    
por 07.03.2016 / 15:02
0

História curta - experimente uma versão diferente do kernel. Eu tenho um sistema que mostrou erros OOM com kernels 4.2.0-xe 4.4.0-x, mas não com 3.19.0-x.

Longa história: (não muito tempo!) Eu tenho um Compaq DC5000 ainda em serviço aqui - atualmente com 512MB de RAM (e uma parte disso, como 32-128MB, sendo dada para o vídeo onboard ..) Servindo principalmente NFS, eu tenho um monitor ligado para isso, então, ocasionalmente, eu vou entrar nele (Ubuntu Classic, não Unity.)

Via Ubuntu HWE Eu estava rodando o kernel 3.19.x por um bom tempo; acabaria trocando 200-300MB de material, mas aparentemente era coisa não usada, não haveria nenhuma atividade de swap tendo que trocá-lo mais tarde, tanto quanto eu poderia dizer.

4.2.0-x kernel e agora 4.4.0-x kernel, eu posso começar um robusto NFS, apenas 220MB no swap (isto é, 1.3GB livre), e ele vai começar a matar coisas. Eu não vou reclamar se é um bug do kernel ou "problema de ajuste" (como uma reserva de 64MB que normalmente é boa, mas muito alta em um sistema de ~ 400MB ou mais?)

Nenhum desrespeito para aqueles que estão dizendo que está de alguma forma quebrando só porque ele espera usar swap; com todo o respeito, você está errado. Não vai ser rápido, mas eu costumava ir 1 ou 2GB na troca em alguns sistemas de 512MB-1GB. É claro que alguns tipos de software do mlock são um monte de RAM, mas no meu caso (já que estou executando o mesmo software apenas em um kernel diferente) isso claramente não é o caso.

    
por 30.07.2016 / 05:05

Tags