O assassino de OOM no Linux causa estragos em vários aplicativos de vez em quando, e parece que pouco é realmente feito no lado do desenvolvimento do kernel para melhorar isso. Não seria melhor, como prática recomendada ao configurar um novo servidor , reverter o padrão na confirmação excessiva de memória, ou seja, desativá-lo ( vm.overcommit_memory=2
) a menos que você saiba que deseja usá-lo para seu uso específico? E quais seriam esses casos de uso em que você sabe que deseja supercomprometimento?
Como um bônus, como o comportamento em caso de vm.overcommit_memory=2
depende vm.overcommit_ratio
e troca de espaço, qual seria uma boa regra para dimensionar os dois últimos para que toda essa configuração continue funcionando razoavelmente?
O assassino do OOM só causa estragos se você sobrecarregou o sistema. Troque o suficiente e não execute aplicativos que de repente decidam consumir grandes quantidades de RAM, e você não terá problemas.
Para responder especificamente às suas perguntas:
brk
(2) (e os wrappers que o utilizam, comomalloc
(3)) retornando um erro. Quando experimentei isso no meu trabalho anterior, considerou-se um incômodo obter tudo capaz de lidar com erros de falta de memória do que apenas lidar com as consequências de uma OOM (que, no nosso caso, era muito pior do que ter que reiniciar o serviço ocasional se um OOM ocorresse - tivemos que reiniciar um cluster inteiro, porque o GFS é uma pilha de fezes fumegante).Basicamente, minha experiência é que desativar o overcommit é um bom experimento que raramente funciona tão bem na prática quanto parece na teoria. Isso corresponde muito bem às minhas experiências com outros ajustes no kernel - os desenvolvedores do kernel Linux são quase sempre mais inteligentes que você, e os padrões funcionam melhor para a vasta e vasta maioria dos casos. Deixe-os em paz e, em vez disso, procure qual processo tem o vazamento e corrija-o.
fonte
Hmm, eu não estou totalmente convencido por argumentos a favor do overcommit e do OOM killer ... Quando o womble escreve,
"O assassino do OOM só causa estragos se você sobrecarregou o sistema. Faça uma troca suficiente e não execute aplicativos que de repente decidam consumir grandes quantidades de RAM, e você não terá problemas".
Ele descreve um cenário de ambiente em que a supercomprometimento e o OOM killer não são impostos ou não agem realmente (se todos os aplicativos alocassem memória conforme necessário e houvesse memória virtual suficiente para ser alocada, as gravações seguiriam de perto as alocações de memória sem erros, por isso não podíamos falar sobre um sistema supercomitido, mesmo que uma estratégia de supercomprometimento estivesse ativada). Trata-se de uma admissão implícita de que o supercomprometimento e o assassino da OOM funcionam melhor quando sua intervenção não é necessária, o que é de alguma forma compartilhado pela maioria dos apoiadores dessa estratégia, tanto quanto eu posso dizer (e admito que não posso dizer muito ...). Além disso, referir-me a aplicativos com comportamentos específicos ao pré-alocar memória me faz pensar que um tratamento específico pode ser ajustado em um nível de distribuição, em vez de ter um padrão,
Para a JVM, bem, é uma máquina virtual, até certo ponto, ela precisa alocar todos os recursos necessários na inicialização, para criar seu ambiente 'falso' para seus aplicativos e manter seu recurso disponível separado do host ambiente, tanto quanto possível. Portanto, pode ser preferível que falhe na inicialização, em vez de decorrido um tempo como consequência de uma condição OOM 'externa' (causada por supercomprometimento / morte de OOM / qualquer que seja), ou mesmo assim sofra por essa condição interferir na sua própria estratégias internas de manipulação de OOM (em geral, uma VM deve obter todos os recursos necessários desde o início e o sistema host deve "ignorá-los" até o final, da mesma forma que qualquer quantidade de memória RAM compartilhada com uma placa gráfica nunca - e não pode ser - tocado pelo sistema operacional).
Sobre o Apache, duvido que ter todo o servidor ocasionalmente morto e reiniciado seja melhor do que permitir que um único filho, juntamente com uma única conexão, falhe desde o início (= da criança / da conexão) (como se fosse uma instância totalmente nova de a JVM criada após outra instância é executada por um tempo). Eu acho que a melhor 'solução' pode depender de um contexto específico. Por exemplo, considerando um serviço de comércio eletrônico, pode ser muito preferível que algumas vezes algumas conexões com o gráfico de compras falhem aleatoriamente, em vez de perder todo o serviço, com o risco, por exemplo, de interromper uma finalização em andamento do pedido, ou (talvez pior) um processo de pagamento, com todas as consequências do caso (talvez inofensivo, mas talvez prejudicial - e com certeza, quando surgirem problemas,
Da mesma forma, em uma estação de trabalho, o processo que consome mais recursos e, portanto, a primeira escolha para o assassino de OOM, pode ser um aplicativo com muita memória, como um transcodificador de vídeo ou um software de renderização, provavelmente o único aplicativo o usuário quer ser intocado. Essas considerações sugerem que a política padrão do OOM killer é muito agressiva. Ele usa uma abordagem de "pior ajuste", que é de alguma forma semelhante à de alguns sistemas de arquivos (o OOMK tenta e libera o máximo de memória possível, enquanto reduz o número de subprocessos mortos, a fim de impedir qualquer intervenção adicional em curto espaço de tempo, como bem como um fs pode alocar mais espaço em disco do que o necessário para um determinado arquivo, para impedir qualquer alocação adicional se o arquivo crescer e, assim, impedir a fragmentação).
No entanto, acho que uma política oposta, como uma abordagem de "melhor ajuste", poderia ser preferível, de modo a liberar a memória exata necessária em um determinado ponto e não se incomodar com processos "grandes", que podem estar desperdiçando memória, mas também pode não ser, e o kernel não pode saber disso (hmm, eu posso imaginar que manter o rastreamento dos acessos à página conte e tempo poderia sugerir que, se um processo está alocando memória, ele não precisa mais, portanto, para adivinhar se um processo está desperdiçando memória ou apenas usando muito, mas os atrasos de acesso devem ser ponderados nos ciclos da CPU para distinguir uma perda de memória de um aplicativo intensivo em memória e CPU, mas, embora potencialmente imprecisos, essas heurísticas podem ter uma sobrecarga excessiva).
Além disso, pode não ser verdade que matar o menor número possível de processos seja sempre uma boa escolha. Por exemplo, em um ambiente de área de trabalho (vamos pensar em um nettop ou um netbook com recursos limitados, por exemplo), um usuário pode estar executando um navegador com várias guias (portanto, consumindo memória - vamos assumir que essa é a primeira escolha para o OOMK) , além de alguns outros aplicativos (um processador de texto com dados não salvos, um cliente de email, um leitor de pdf, um media player, ...), além de alguns daemons (do sistema), além de algumas instâncias do gerenciador de arquivos. Agora, ocorre um erro do OOM, e o OOMK opta por matar o navegador enquanto o usuário está fazendo algo considerado "importante" na rede ... o usuário ficaria desapontado. Por outro lado, fechando os poucos gerenciadores de arquivos '
De qualquer forma, acho que o usuário deve ter a capacidade de tomar uma decisão por conta própria sobre o que fazer. Em um sistema de desktop (= interativo), isso deve ser relativamente fácil, desde que sejam reservados recursos suficientes para solicitar ao usuário que feche qualquer aplicativo (mas até fechar algumas guias pode ser suficiente) e lidar com sua escolha (uma opção pode consiste em criar um arquivo de troca adicional, se houver espaço suficiente). Para serviços (e em geral), eu também consideraria dois aprimoramentos possíveis: um é registrar os intervalos do OOM killer, além de processar falhas de início / bifurcação, de forma que a falha possa ser facilmente depurada (por exemplo, uma API pode informe o processo que está emitindo a nova criação ou bifurcação do processo - assim, um servidor como o Apache, com um patch adequado, poderia fornecer um registro melhor para certos erros); isso pode ser feito independentemente da supercomissão / OOMK estar se esforçando; em segundo lugar, mas não por importância, um mecanismo poderia ser estabelecido para ajustar o algoritmo OOMK - eu sei que é possível, até certo ponto, definir uma política específica em um processo por processo, mas eu gostaria de mecanismo de configuração 'centralizado', baseado em uma ou mais listas de nomes de aplicativos (ou IDs) para identificar processos relevantes e dar a eles um certo grau de importância (conforme os atributos listados); esse mecanismo deve (ou pelo menos poderia) também ser em camadas, para que possa haver uma lista definida pelo usuário de nível superior, uma lista definida pelo sistema (distribuição) e entradas definidas pelo aplicativo (de nível inferior) , por exemplo, um gerenciador de arquivos DE pode instruir o OOMK a matar com segurança qualquer instância,
Além disso, uma API pode ser fornecida para permitir que os aplicativos aumentem ou diminuam seu nível de 'importância' no tempo de execução (com relação aos objetivos de gerenciamento de memória e independentemente da prioridade de execução), para que, por exemplo, um processador de Word possa começar com uma 'importância' baixa, mas aumente-a, pois alguns dados são mantidos antes da liberação para um arquivo ou uma operação de gravação está sendo executada e diminua a importância novamente assim que essa operação terminar (analogamente, um gerenciador de arquivos pode mudar de nível quando passar de apenas litar arquivos para lidar com dados e vice-versa, em vez de usar processos separados, e o Apache poderia dar diferentes níveis de importância a crianças diferentes ou alterar um estado filho de acordo com alguma política decidida por administradores de sistemas e exposta através do Apache - ou qualquer outro tipo de servidor - configurações). Claro, essa API poderia e seria abusada / mal utilizada, mas acho que essa é uma preocupação menor em comparação com o kernel arbitrariamente matar processos para liberar memória sem nenhuma informação relevante sobre o que está acontecendo no sistema (e consumo de memória / tempo de criação ou similares) é relevante ou validar o suficiente para mim) - somente usuários, administradores e gravadores de programas podem realmente determinar se um processo ainda é necessário por algum motivo, qual é o motivo e / ou se o aplicativo está em um estado líder perda de dados ou outros danos / problemas se mortos; no entanto, alguma suposição ainda pode ser feita, por exemplo, procurando recursos de um determinado tipo (descritores de arquivo, soquetes de rede etc.) adquiridos por um processo e com operações pendentes poderiam dizer se um processo deveria estar em um 'estado' mais alto do que o único conjunto,
Ou, evite o excesso de confirmação e deixe o kernel fazer exatamente o que um kernel deve fazer, alocando recursos (mas não os resgatando arbitrariamente como o assassino do OOM), agendando processos, prevenindo fome e deadlocks (ou resgatando-os), garantindo total preempção e separação de espaços de memória e assim por diante ...
Também gastaria mais algumas palavras sobre abordagens de supercomprometimento. Em outras discussões, criei a idéia de que uma das principais preocupações com a supercomprometimento (tanto como motivo para querer isso quanto como fonte de possíveis problemas) consiste no manuseio dos garfos: honestamente, não sei exatamente como A estratégia on-write é implementada, mas acho que qualquer política agressiva (ou otimista) pode ser mitigada por uma estratégia de localidade de troca semelhante. Ou seja, em vez de apenas clonar (e ajustar) as páginas de código do processo bifurcado e as estruturas de agendamento, algumas outras páginas de dados podem ser copiadas antes de uma gravação real, escolhendo entre as páginas que o processo pai acessou para gravar com mais frequência (ou seja, usando um contador para operações de gravação).
Tudo, é claro, IMHO.
fonte
/proc/$PID/oom_adj
./proc/$PID/oom_score_adj
Crédito: - O kernel do Linux está iniciando o killer do OOM
fonte