Como configurar o matador de processos por memória insuficiente (OOM Killer) no Linux

Por Robert Chase
Postado em Novembro 2015

Sobre o OOM killer
Quando um servidor que hospeda uma base de dados ou aplicativo se detém, costuma ser necessário trabalhar vertiginosamente para restabelecer os serviços críticos, especialmente em se tratando de sistemas de produção importantes. Quando tentamos determinar a causa do problema, já superado o desespero inicial, é comum não compreender por que o aplicativo ou base de dados se deteve repentinamente. Em algumas situações, a interrupção se produz porque o sistema percebe que não tem memória suficiente e cancela um processo importante para continuar funcionando.

O kernel do Linux aloca memória em função da demanda dos aplicativos rodados no sistema. Como no caso de muitos aplicativos a memória é alocada quando começam a ser rodados, mesmo que depois não seja utilizada, o kernel foi projetado para superalocar memória e assim tornar seu uso mais eficiente. O modelo de superalocação permite que o kernel aloque mais memória da que está disponível nos componentes físicos. Se um processo utiliza toda a memória que lhe foi alocada, o kernel fornece recursos adicionais ao aplicativo. Quando são muitos os aplicativos que utilizam toda a memória alocada, o modelo de superalocação pode se tornar um problema, e o kernel deve deter processos para continuar operando. O mecanismo usado pelo kernel para recuperar memória do sistema é conhecido como matador de processos por memória insuficiente (out-of-memory killer) ou, de forma abreviada, matador OOM (OOM Killer).

Como conhecer o motivo pelo qual um processo foi detido
Quando procuramos solucionar um problema no qual o matador OOM deteve um aplicativo, é possível seguir diversos sinais que poderiam esclarecer como e por que o processo foi parado. No exemplo a seguir, vamos dar uma olhada no syslog para ver se podemos localizar a origem do problema. O processo oracle foi detido pelo matador OOM pois a memória é insuficiente. O K maiúsculo de Killed [matou] se refere a que o processo foi detido com um sinal -9, indicando com bastante certeza que o matador OOM poderia ser o culpado.

grep -i kill /var/log/messages*  
host kernel: Out of Memory: Killed process 2592 (oracle).


Também é possível examinar o estado de utilização da memória baixa e alta do sistema. É importante notar que, como esses valores informam em tempo real e mudam em função da carga de trabalho do sistema, deveriam ser observados com frequência antes de ocorrer uma sobrecarga. Observá-los após a parada de um processo não trará muita informação nem contribuirá ao esclarecimento de problemas relacionados com o matador OOM.

[root@test-sys1 ~]# free -lm               
                total       used       free     shared    buffers     cached  
Mem:              498         93        405          0         15         32  
Low:              498         93        405  
High:               0          0          0  
-/+ buffers/cache:            44        453  
Swap:            1023          0       1023


Nesta máquina virtual de teste, temos 498 MB de memória baixa livres. O sistema não usou o espaço de swap. O parâmetro -l mostra valores estatísticos das memórias alta e baixa e o parâmetro -m expressa a saída em megabytes para facilitar a leitura.

[root@test-sys1 ~]# egrep 'High|Low' /proc/meminfo  
HighTotal:             0 kB  
HighFree:              0 kB  
LowTotal:         510444 kB  
LowFree:          414768 kB


A mesma informação pode ser acessada analisando /proc/memory e observando especialmente os valores altos e baixos. Mesmo assim, com esse último método não se obtém informação sobre a saída em relação ao espaço de swap, e a saída é expressa em kilobytes.

A memória baixa é aquela a que o kernel tem acesso físico direto. A memória alta é aquela para a qual o kernel não tem um endereço físico direto, portanto, a associação ou mapeamento é realizado mediante um endereço virtual. Nos antigos sistemas de 32 bits, a memória baixa e a memória alta são visíveis devido ao modo em que a memória é associada a um endereço virtual. Nas plataformas de 64 bits, espaço com endereço virtual não é mais necessário, por isso, toda a memória do sistema é mostrada como memória baixa.

Embora a analise de /proc/memory e o uso do comando free sejam úteis para conhecer o uso da memória em determinado momento, às vezes é necessário conhecer esse uso ao longo de um período de tempo. O comando vmstat é bastante útil nesse sentido.

No exemplo, na Sequência 1, é usado o comando vmstat para observar os recursos a cada 45 segundos 10 vezes. O parâmetro -s mostra valores em uma tabela e o parâmetro -M expressa a saída em megabytes para facilitar a leitura. Como pode se observar no exemplo, há alguma coisa que está consumindo a memória livre, mas ainda o espaço de swap não está sendo usado.

[root@localhost ~]# vmstat -SM 45 10  
procs -----------memory-------- ---swap-- -----io-- --system-- ----cpu---------   
r  b   swpd  free  buff  cache  si   so   bi   bo   in    cs us  sy  id  wa st   
1  0      0   221   125     42   0    0    0    0   70     4  0   0  100  0  0   
2  0      0   192   133     43   0    0  192   78  432  1809  1  15   81   2 0   
2  1      0    85   161     43   0    0  624  418 1456  8407  7  73    0  21 0   
0  0      0    65   168     43   0    0  158  237  648  5655  3  28   65   4 0   
3  0      0    64   168     43   0    0    0    2 1115 13178  9  69   22   0 0   
7  0      0    60   168     43   0    0    0    5 1319 15509 13  87    0   0 0   
4  0      0    60   168     43   0    0    0    1 1387 15613 14  86    0   0 0   
7  0      0    61   168     43   0    0    0    0 1375 15574 14  86    0   0 0   
2  0      0    64   168     43   0    0    0    0 1355 15722 13  87    0   0 0   
0  0      0    71   168     43   0    0    0    6  215  1895  1   8   91   0 0

Sequência 1

A saída de vmstat pode ser redirecionada para um arquivo usando o comando a seguir. Podemos ainda ajustar a duração e a quantidade de vezes para monitorar os recursos por mais tempo. Enquanto o comando está sendo executado, é possível consultar o arquivo de saída para ver os resultados.

No exemplo abaixo, a memória é monitorada a cada 120 segundos 1000 vezes. O & no final da linha permite executar o comando como processo e recuperar o terminal.

vmstat  -SM 120 1000 > memoryusage.out &


Para referência, na Sequência 2 mostramos uma seção da página do manual sobre vmstat que oferece informações adicionais sobre a saída fornecida pelo comando. Trata-se apenas das informações referidas à memória; o comando também fornece informações sobre as entradas e saídas do disco e sobre o uso da CPU.

Memory         
  swpd: the amount of virtual memory used.         
  free: the amount of idle memory.         
  buff: the amount of memory used as buffers.         
  cache: the amount of memory used as cache.         
  inact: the amount of inactive memory. (-a option)         
  active: the amount of active memory. (-a option)       

Swap         
  si: Amount of memory swapped in from disk (/s).         
  so: Amount of memory swapped to disk (/s).

Sequência 2

Há outras ferramentas para monitoramento da memória e desempenho do sistema que visam investigar problemas deste tipo. Ferramentas como sar, System Activity Reporter (informador de atividade do sistema), e dtrace, Dynamic Tracing (acompanhamento dinâmico), são muito úteis para coletar dados específicos sobre o desempenho do sistema ao longo do tempo. Para ter ainda maior visibilidade, as sondas de estabilidade dtrace e de estabilidade de dados também têm um gatilho de condições OOM que irá disparar se o kernel mata um processo causado por OOM. Na seção "Informações adicionais" deste artigo são incluídos outros dados sobre os comandos dtrace e sar.

Diversas situações podem provocar um evento OOM, além do esgotamento da memória RAM e do espaço de swap disponível devido à carga de trabalho do sistema.  Poderia acontecer que o kernel não utilize o espaço de swap de maneira ótima devido ao tipo de carga de trabalho do sistema. Nos aplicativos que usam chamadas mlock() ou páginas HugePages não é possível recorrer ao disco quando a memória física começa a esgotar. Pode acontecer que as estruturas de dados do kernel também usem muito espaço e consumam a memória do sistema até provocar um evento OOM.  Muitos sistemas baseados na arquitetura NUMA podem apresentar eventos OOM devido à memória insuficiente em um nó e desencadear um processo OOM no kernel, quando, na verdade, há muita memória disponível nos nós restantes. Na seção "Informações adicionais" deste artigo são incluídos outros dados sobre os estados OOM de máquinas com arquitetura NUMA.

Configuração do matador OOM
O matador OOM do Linux oferece diversas opções de configuração fornecendo aos desenvolvedores alternativas relacionadas a como o sistema deve se comportar diante de um estado OOM.  Os parâmetros e valores escolhidos vão depender do ambiente e dos aplicativos configurados no sistema para esse ambiente.

Nota: Sugere-se que testes e ajustes sejam realizados em um ambiente de desenvolvimento antes de fazer alterações nos sistemas de produção importantes.

Em alguns ambientes, quando um sistema executa uma tarefa crítica única, reiniciar o sistema quando se apresenta uma condição OOM pode ser uma alternativa viável para restabelecer o funcionamento normal rapidamente e sem intervenção do administrador.  Embora esta não seja uma abordagem ideal, a lógica por trás é que, se o aplicativo não consegue operar por ser interrompido pelo matador OOM, a reinicialização do sistema irá restaurar o aplicativo caso este comece a rodar junto com o sistema durante a reinicialização. Se o administrador tiver que rodar o aplicativo manualmente, esta opção não terá os resultados desejados.

Os valores abaixo farão com que o sistema entre em pânico, levando à reinicialização por causa da memória insuficiente. Os comandos sysctl alocarão os valores em tempo real e, se essas alocações forem adicionadas a sysctl.conf, a configuração não se perderá após novas reinicializações. O valor X para kernel.panic indica os segundos que deverão passar antes da reinicialização do sistema. Essa configuração deve ser ajustada em função das necessidades do ambiente particular.

sysctl vm.panic_on_oom=1  
sysctl kernel.panic=X  
echo "vm.panic_on_oom=1" >> /etc/sysctl.conf  
echo "kernel.panic=X" >> /etc/sysctl.conf


Além disso, aplicando determinados processos, é possível ajustar a forma em que o matador OOM reage ante condições OOM.  Vamos considerar, por exemplo, o processo oracle 2592 cancelado anteriormente. Se quisermos reduzir as probabilidades de que o processo oracle seja interrompido pelo matador OOM, podemos usar a instrução abaixo:

echo -15 > /proc/2592/oom_adj


Já se quisermos aumentar as probabilidades de que o matador OOM interrompa o processo oracle, podemos fazer o seguinte:

echo 10 > /proc/2592/oom_adj


Se quisermos excluir completamente o processo oracle do escopo do matador OOM, podemos usar a instrução abaixo. É importante frisar que a instrução indicada pode provocar um comportamento inesperado em função dos recursos e da configuração do sistema. Se o kernel não conseguir interromper um processo que usa uma grande quantidade de memória, outros processos disponíveis serão ocupados. Pode acontecer que alguns desses processos sejam essenciais para o sistema operacional e que sua interrupção afete o funcionamento completo do sistema.

echo -17 > /proc/2592/oom_adj


É possível alocar valores válidos entre -16 e +15 a oom_adj; alocando o valor -17, o processo será totalmente excluído do escopo do matador OOM. Quanto mais alto for o valor, maiores serão as probabilidades de que o matador decida interromper o processo diante de uma condição OOM do sistema. Também é possível ver o conteúdo de /proc/2592/oom_score para determinar o grau de probabilidades de o matador OOM interromper um processo. O valor 0 indica que o processo está fora do escopo do matador OOM. Quanto mais alto for o valor de oom_score, maiores serão as probabilidades de o processo ser interrompido diante de uma condição OOM do sistema.

O matador OOM pode ser completamente desativado usando o código abaixo. Seu uso não é recomendável em ambientes de produção, pois, se uma condição OOM se apresentar, poderiam ocorrer comportamentos inesperados em função dos recursos disponíveis e das configurações do sistema. Os comportamentos inesperados podem incluir de uma situação de pânico do kernel até o travamento do sistema, dependendo dos recursos disponíveis no kernel quando a condição OOM surgir.

sysctl vm.overcommit_memory=2  
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf


Em alguns ambientes, as opções de configuração mencionadas não são ideais e novos ajustes podem ser necessários. A configuração de páginas HugePages para o kernel pode ajudar a enfrentar eventos OOM em função das necessidades dos aplicativos rodados no sistema.

Informações adicionais
A seguir, apresentamos recursos adicionais relacionados a HugePages, dtrace, sar e OOM para arquiteturas NUMA:

 


Robert Chase faz parte da equipe de gestão de produtos Oracle Linux. Trabalha com Linux e software de código aberto desde 1996. Também trabalhou com sistemas muito pequenos, como dispositivos embutidos e com grandes supercomputadores.

Este artigo foi revisto pela equipe de produtos Oracle e está em conformidade com as normas e práticas para o uso de produtos Oracle.