Configurando o Out-Of-Memory Killer no Linux para PostgreSQL

Configurando o Out-Of-Memory Killer no Linux para PostgreSQL

Quando um servidor de banco de dados é encerrado inesperadamente no Linux, você precisa descobrir o motivo. Podem existir várias razões. Por exemplo, SIGSEV — falha devido a um bug no servidor backend. Mas isso é raro. Na maioria das vezes, você simplesmente fica sem espaço em disco ou memória. Se você ficar sem espaço em disco, só há uma saída: libere espaço e reinicie o banco de dados.

Assassino sem memória

Quando um servidor ou processo fica sem memória, o Linux oferece 2 soluções: travar todo o sistema ou encerrar o processo (aplicativo) que está consumindo memória. É melhor, claro, encerrar o processo e evitar que o sistema operacional trave. Resumindo, Out-Of-Memory Killer é um processo que mata um aplicativo para evitar que o kernel trave. Ele sacrifica o aplicativo para manter o sistema operacional funcionando. Vamos primeiro discutir como o OOM funciona e como controlá-lo, e depois ver como o OOM Killer decide qual aplicativo encerrar.

Uma das principais tarefas do Linux é alocar memória aos processos quando eles solicitarem. Normalmente, um processo ou aplicativo solicita memória do sistema operacional, mas não a utiliza totalmente. Se o sistema operacional distribuir memória para todos que a solicitarem, mas não tiver planos de usá-la, muito em breve a memória acabará e o sistema falhará. Para evitar isso, o sistema operacional reserva memória para o processo, mas na verdade não a libera. A memória é alocada apenas quando um processo realmente vai utilizá-la. Acontece que o SO não tem memória livre, mas atribui memória a um processo, e quando um processo precisa dela, o SO a aloca se puder. A desvantagem é que às vezes o sistema operacional reserva memória, mas na hora certa não há memória livre e o sistema trava. O OOM desempenha um papel importante neste cenário e encerra processos para evitar que o kernel entre em pânico. Quando um processo PostgreSQL é forçado a encerrar, uma mensagem aparece no log:

Out of Memory: Killed process 12345 (postgres).

Se o sistema estiver com pouca memória e não puder ser liberado, a função será chamada out_of_memory. Nesse estágio, ela só tem uma coisa a fazer: concluir um ou mais processos. O OOM-killer deve encerrar o processo imediatamente ou pode esperar? Obviamente, quando out_of_memory é chamado, é devido à espera por uma operação de E/S ou paginação em disco. Portanto, o assassino OOM deve primeiro realizar verificações e, com base nelas, decidir que o processo precisa ser encerrado. Se todas as verificações abaixo forem positivas, a OOM encerrará o processo.

Seleção de processo

Quando a memória acaba, a função é chamada out_of_memory(). Tem uma função select_bad_process(), que recebe uma avaliação da função badness(). O “pior” processo será o alvo. Função badness() seleciona um processo de acordo com certas regras.

  1. O kernel precisa de um mínimo de memória para si.
  2. Você precisa liberar muita memória.
  3. Não há necessidade de encerrar processos que usam pouca memória.
  4. Processos mínimos precisam ser concluídos.
  5. Algoritmos complexos que aumentam as chances de conclusão dos processos que o próprio usuário deseja concluir.

Depois de concluir todas essas verificações, o OOM examina a pontuação (oom_score). OOM nomeia oom_score cada processo e, em seguida, multiplica esse valor pela quantidade de memória. Processos com valores maiores têm maior probabilidade de serem vítimas do OOM Killer. Os processos associados ao usuário root têm uma pontuação mais baixa e são menos propensos a serem encerrados.

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

O ID do processo Postgres é 3813, então em outro shell é possível obter a pontuação usando este parâmetro do kernel oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

Se você não quiser que o OOM-Killer elimine o processo, existe outra opção de kernel: oom_score_adj. Adicione um grande valor negativo para reduzir as chances de concluir um processo que você valoriza.

sudo echo -100 > /proc/3813/oom_score_adj

Para definir um valor oom_score_adj, defina OOMScoreAdjust no bloco de serviço:

[Service]
OOMScoreAdjust=-1000

ou usar oomprotect em um time rcctl.

rcctl set <i>servicename</i> oomprotect -1000

Forçar o encerramento de um processo

Quando um ou mais processos já estão selecionados, o OOM-Killer chama a função oom_kill_task(). Esta função envia um sinal de encerramento ao processo. Em caso de falta de memória oom_kill() Chama essa função para enviar um sinal SIGKILL ao processo. Uma mensagem é gravada no log do kernel.

Out of Memory: Killed process [pid] [name].

Como controlar o OOM-Killer

No Linux, você pode ativar ou desativar o OOM-Killer (embora o último não seja recomendado). Para ativar ou desativar use o parâmetro vm.oom-kill. Para habilitar o OOM-Killer em tempo de execução, execute o comando sysctl.

sudo -s sysctl -w vm.oom-kill = 1

Para desabilitar o OOM-Killer, especifique o valor 0 no mesmo comando:

sudo -s sysctl -w vm.oom-kill = 0

O resultado deste comando não será salvo para sempre, mas apenas até a primeira reinicialização. Se precisar de mais persistência, adicione esta linha ao arquivo /etc/sysctl.conf:

echo vm.oom-kill = 1 >>/etc/sysctl.conf

Outra maneira de ativar e desativar é escrever uma variável panic_on_oom. O valor sempre pode ser verificado /proc.

$ cat /proc/sys/vm/panic_on_oom
0

Se você definir o valor como 0, quando a memória acabar, não haverá kernel panic.

$ echo 0 > /proc/sys/vm/panic_on_oom

Se você definir o valor como 1, quando a memória acabar, ocorrerá um kernel panic.

echo 1 > /proc/sys/vm/panic_on_oom

O OOM-Killer não pode apenas ser ligado e desligado. Já dissemos que o Linux pode reservar mais memória para processos do que a disponível sem realmente alocá-la, e esse comportamento é controlado por um parâmetro do kernel do Linux. A variável é responsável por isso vm.overcommit_memory.

Você pode especificar os seguintes valores para ele:

0: O próprio kernel decide se reserva muita memória. Este é o padrão na maioria das versões do Linux.
1: O kernel sempre reservará memória extra. Isso é arriscado, pois a memória pode acabar, pois, muito provavelmente, um dia os processos irão exigir isso.
2: o kernel não reservará mais memória do que o especificado no parâmetro overcommit_ratio.

Com esse parâmetro, você especifica a porcentagem de memória que pode ser reservada em excesso. Se não houver espaço para isso, nenhuma memória será alocada e a reserva será negada. Esta é a opção mais segura recomendada para PostgreSQL. O OOM-Killer é afetado por outro elemento - a capacidade de troca, que é controlada pela variável cat /proc/sys/vm/swappiness. Esses valores informam ao kernel como lidar com a paginação. Quanto maior o valor, menor a probabilidade de o OOM encerrar o processo, mas devido às operações de E/S isso tem um impacto negativo no banco de dados. E vice-versa - quanto menor o valor, maior a probabilidade de intervenção do OOM-Killer, mas o desempenho do banco de dados também é maior. O valor padrão é 60, mas se todo o banco de dados couber na memória, é melhor definir o valor como 1.

Resultados de

Não deixe o “assassino” do OOM-Killer assustar você. Neste caso, o assassino será o salvador do seu sistema. Ele “mata” os piores processos e evita que o sistema trave. Para evitar ter que usar o OOM-Killer para encerrar o PostgreSQL, defina como vm.overcommit_memory valor 2. Isso não garante que o OOM-Killer não terá que intervir, mas reduzirá a probabilidade de forçar o encerramento do processo PostgreSQL.

Fonte: habr.com

Adicionar um comentário