Efeitos da configuração de vm.overcommit_memory

41

Meu servidor Web VPS em execução no CentOS 5.4 (kernel Linux 2.6.16.33-xenU) de forma irregular (como uma vez por mês durante algumas semanas) deixa de responder devido à ativação do oom-killer. O monitoramento do servidor mostra que ele não funciona. normalmente ficam sem memória, de vez em quando.

Eu li alguns blogs que apontam para esta página que discutem a configuração do kernel para gerenciar melhor a supercomprometimento usando as seguintes configurações do sysctl:

vm.overcommit_memory = 2
vm.overcommit_ratio = 80

Meu entendimento disso (que pode estar errado, mas não consigo encontrar uma definição canônica para esclarecer) é que isso impede que o kernel superaloque a memória além da troca + 80% da memória física.

No entanto, eu também li algumas outras fontes sugerindo que essas configurações não são uma boa idéia - embora os críticos dessa abordagem pareçam estar dizendo "não faça coisas para danificar seu sistema, em vez de tentar esse argumento", supondo que a causação é sempre conhecida.

Então, minha pergunta é: quais são os prós e os contras dessa abordagem , no contexto de um servidor Apache2 que hospeda cerca de 10 sites de baixo tráfego? No meu caso específico, o servidor da Web possui 512 MB de RAM, com 1024 MB de espaço de troca. Isso parece adequado para a grande maioria das vezes.

dunxd
fonte

Respostas:

32

Ajustar overcommit_ratiopara 80 provavelmente não é a ação correta. Definir o valor para algo menor que 100 quase sempre está incorreto.

A razão para isso é que os aplicativos Linux alocam mais do que realmente precisam. Digamos que eles alocam 8kb para armazenar uma sequência de caracteres com dois caracteres. Bem, isso é vários KB não utilizados ali. Os aplicativos fazem muito isso, e é para isso que a supercomissão é projetada.

Então, basicamente, com a confirmação excessiva de 100, o kernel não permitirá que os aplicativos aloquem mais memória do que você possui (swap + ram). Configurá-lo para menos de 100 significa que você nunca usará toda a sua memória. Se você deseja definir essa configuração, defina-a como superior a 100 por causa do cenário mencionado anteriormente, o que é bastante comum.

Agora, quanto ao seu problema com o disparo do OOM killer, a configuração manual de confirmação excessiva provavelmente não corrigirá isso. A configuração padrão (determinação heurística) é bastante inteligente.

Se você deseja ver se essa é realmente a causa do problema, observe /proc/meminfoquando o assassino do OOM é executado. Se você perceber que Committed_ASestá próximo CommitLimit, mas freeainda está mostrando a memória livre disponível, sim, você pode ajustar manualmente a confirmação excessiva para o seu cenário. Definir esse valor muito baixo fará com que o killer do OOM comece a matar os aplicativos quando você ainda tiver muita memória livre. Definir um valor muito alto pode fazer com que aplicativos aleatórios desapareçam quando tentam usar a memória que foi alocada, mas não está realmente disponível (quando toda a memória realmente é usada).

Patrick
fonte
1
Obrigado - Estou tentando coisas com overcommit_ratio definido como 100 para ver o que acontece. O principal problema que tenho é que, quando o oom-killer é iniciado, ele invariavelmente mata o sshd, impedindo-me de acessar o servidor e ver o que está acontecendo. Eu acho que o que eu realmente preciso é parar o Oom-killer de executar e alguns meios de registrar o que acontece quando ele seria executado, para que eu possa encontrar a causa do problema.
23412 dunxd
4
@dunxd você pode usar /proc/<PID>/oom_score_adjpara esse fim. Por exemplo, se você definir oom_score_adj como -1000 para sshd, o oom killer nunca terá como alvo o sshd quando quiser matar alguma coisa. Interromper completamente o assassino não é uma boa ideia, pois seus programas não serão capazes de prejudicar a memória e eles morrerão de qualquer maneira.
24412 Patrick
4
@dunxd é herdado. faça com que o script init o defina por si próprio e tudo o que for iniciado pelo script init o herda.
253 Patrick
4
Seu exemplo de 4 KB está errado. A memória virtual é usada com páginas e o tamanho (menor) de uma página no Linux é de 4 KB. Isso significa que o armazenamento de alguns caracteres requer que 4 KB sejam mapeados em algum lugar, independentemente das configurações de comprometimento excessivo. Um exemplo adequado de memória excedente seria, por exemplo, você alocar 10 KB e usar apenas os primeiros 4100 bytes. Isso significa que duas páginas de 4 KB precisam armazenar os dados e uma página extra não é usada. Os sistemas sem comprometimento excessivo sempre terão a terceira página pronta para armazenar dados, caso a demanda chegue; os sistemas comprometidos com excesso não o farão cumprir.
Jlliagre
2
/ proc / self aponta para o processo atual, portanto / proc / self / oom_score_adj pode ser usado para alterar oom_score_adj do processo atual.
r_2
23

A Seção 9.6 "Confirmação excessiva e OOM" no documento mencionado pelo @dunxd é particularmente gráfica sobre os perigos de permitir a confirmação excessiva. No entanto, 80parecia interessante para mim, então realizei alguns testes.

O que descobri é que isso overcommit_ratioafeta a RAM total disponível para TODOS os processos. Os processos raiz não parecem ser tratados de maneira diferente dos processos normais do usuário.

Definir a proporção como 100ou menos deve fornecer a semântica clássica da qual os valores de retorno malloc/sbrksão confiáveis. Definir taxas mais baixas do que 100pode ser uma maneira de reservar mais RAM para atividades não relacionadas ao processo, como cache e assim por diante.

Então, no meu computador com 24 GiB de RAM, com swap desativado, 9 GiB em uso, topmostrando

Mem:  24683652k total,  9207532k used, 15476120k free,    19668k buffers
Swap:        0k total,        0k used,        0k free,   241804k cached

Aqui estão algumas overcommit_ratioconfigurações e quanta RAM meu programa consumidor de memória ram poderia pegar (tocando em cada página) - em cada caso, o programa saiu de forma limpa uma vez que mallocfalhou.

 50    ~680 MiB
 60   ~2900 MiB
 70   ~5200 MiB
100  ~12000 MiB

A execução de vários de uma só vez, mesmo com alguns como usuário root, não alterou a quantidade total que consumiram juntos. É interessante que não foi possível consumir os últimos 3 ou mais GiB; o freenão caiu muito abaixo do que é mostrado aqui:

Mem:  24683652k total, 20968212k used,  3715440k free,    20828k buffers

Os experimentos foram confusos - qualquer coisa que use malloc no momento em que toda a RAM está em uso tende a falhar, já que muitos programadores são péssimos em verificar falhas de malloc em C, algumas bibliotecas populares de coleções o ignoram completamente e C ++ e várias outras linguagens são até pior.

A maioria das implementações iniciais da RAM imaginária que vi foram para lidar com um caso muito específico, em que um único processo grande - digamos 51% + de memória disponível - era necessário fork()para exec()um programa de suporte, geralmente um muito, muito menor. Sistemas operacionais com semântica de copiar na gravação permitiriam fork(), mas com a condição de que, se o processo bifurcado realmente tentasse modificar muitas páginas de memória (cada uma das quais teria que ser instanciada como uma nova página independente do enorme processo inicial) acabaria sendo morto. O processo pai só estava em perigo se alocasse mais memória e poderia se esgotar, em alguns casos, apenas esperando um pouco para que outro processo morresse e continuando. O processo filho geralmente apenas se substitui por um programa (geralmente menor) viaexec() e foi então livre da condição.

O conceito de supercomprometimento do Linux é uma abordagem extrema para permitir que ambos fork()ocorram, bem como permitir que processos únicos sejam generalizados em massa. Mortes OOM-causou-assassinas acontecer de forma assíncrona, até programas que fazer alocação de memória alça de forma responsável. Pessoalmente, odeio o comprometimento excessivo em todo o sistema em geral e o assassino em particular - ele promove uma abordagem demolidora para o gerenciamento de memória que infecta bibliotecas e, por meio deles, todos os aplicativos que os usam.

Eu sugeriria definir a proporção para 100 e ter uma partição de troca que geralmente acabaria sendo usada por processos enormes - que geralmente usam apenas uma pequena fração da parte de si que é armazenada na troca e, portanto, proteja a grande maioria dos processos das falhas de funcionalidade do OOM killer. Isso deve manter seu servidor da web protegido contra morte aleatória e, se ele foi escrito para lidar com mallocresponsabilidade, pode até se matar (mas não aposte nesse último).

Isso significa que estou usando isso no /etc/sysctl.d/10-no-overcommit.conf

vm.overcommit_memory = 2
vm.overcommit_ratio = 100
Alex North-Keys
fonte
E você recomendaria manter vm.overcommit_memory em 2?
Ut xD
1
Boa nota - é isso que estou usando; Eu acho que eu omiti-lo na minha resposta, porque ele já está na pergunta
Alex norte-Keys