Um script de linha para verificar e reagir ao uso de memória

3

Gostaria de ter uma linha de shell / bash que faça algo ao longo destas linhas:

test "'free | grep | awk | whatever' -gt 80" && any_command

Onde a porcentagem total de RAM sendo usada por todo o sistema é comparada com um número codificado (80 no meu caso). test não importa, desde que o any_command seja executado se o RAM for maior que a porcentagem dada.

  • bytes / megabytes exatos em vez de porcentagens é ok
  • isso deve funcionar no típico ubuntu 14.04
  • destinado para uso como um trabalho cron
  • bônus: one-liner que faz a mesma coisa, mas verifica a ram de um processo específico

Atualizar

Existem respostas sobre como este é um problema que os gostos de monit / bluepill / god são construídos para resolver. Eu concordo 100% e você provavelmente deve seguir o conselho nessas respostas. No entanto, essa questão é especificamente sobre a linha exata que descrevi, por quaisquer razões que possam ser, assumindo todas as advertências e problemas que isso possa envolver.

    
por Max Chernyak 04.12.2014 / 01:54

3 respostas

5

Que tal:

[ $(free -m| grep  Mem | awk '{ print int($3/$2*100) }') -gt "80" ] && echo "greater " || echo "lesser"

E para o consumo do processo, aqui está uma parte possível de uma solução:

for p in $(pgrep bash); do total=$(($total + $(awk '/VmSize/ { print $2 }' /proc/$p/status))); done ; echo "Total memory usage: $total kb" ; unset total

A combinação de ambos é deixada como um exercício para o leitor.

    
por 04.12.2014 / 02:14
5

Não reinvente a roda:)

O utilitário Monit é construído especificamente para lidar com esse tipo de situação. Ele é bem documentado e tem muitas exemplos aqui no ServerFault .

  check system kale.GreenLeaf.com
    if loadavg (5min) > 16 for 15 cycles then alert
    if memory usage > 92% then alert
    if swap usage > 10% then alert

ou para um processo:

check process cups
    with pidfile "/var/run/cupsd.pid"
    start program = "/sbin/service cups start"
    stop program = "/sbin/service cups stop"
    if 10 restarts within 11 cycles then timeout
    if total memory > 1000.0 MB for 5 cycles then alert
    if total memory > 2000.0 MB for 5 cycles then restart
    if cpu usage > 95% for 11 cycles then restart

Em vez de um alerta ou ação de início / parada / reinicialização, você pode configurar um EXEC:

EXEC can be used to execute an arbitrary program and send an alert. If you choose this action you must state the program to be executed and if the program require arguments you must enclose the program and its arguments in a quoted string. You may optionally specify the uid and gid the executed program should switch to upon start...

if total memory > 2000.0 MB for 5 cycles then exec "/sbin/service sidekiq restart"
    
por 04.12.2014 / 02:38
2

O que exatamente você está tentando realizar? Você provavelmente está tentando fazer isso errado.

[ $(free | perl -nE 'if (/Mem/) { (undef,$total,$used) = split; say int(100*$used/$total) }') -gt 80 ] && echo foo

Mas note que tudo o que você está tentando realizar com isso é quase certamente inútil (e provavelmente até prejudicial). Não existe algo como "porcentagem de RAM sendo usada". Sim, free mostrará quanta memória é "free", mas isso provavelmente não significa o que você acha que significa (esse campo seria melhor chamado de "desperdiçado" ou "quantidade de memória que você nunca deveria ter comprado").

Por exemplo, o kernel não "carrega" programas na memória, mapeia-os, portanto, alguns programas de exemplo de centenas de MB poderão ser executados, não importa em apenas 12 KB. Além disso, todos os arquivos acessados serão armazenados em cache nessa mesma memória (chamada de cache de páginas) - não há diferença entre programas executados no passado (portanto, seus arquivos são armazenados em cache se forem executados novamente) ou arquivos de dados que foram lidos / gravados em o passado (então, se eles forem acessados novamente, eles serão mais rápidos)

Então, se você tiver mais disco do que memória (um caso bastante comum), sua memória "livre" (AKA "desperdiçada") irá rapidamente convergir próximo a 100% (na verdade mais como 80-95%, já que o kernel tente manter um pouco livre para que possa acessá-lo rapidamente quando houver pressão de memória). Isso é normal e realmente desejado, pois acelerará muito o seu acesso ao disco (no melhor dos casos), ou apenas será tão bom quanto "memória livre" se nada acessar os mesmos arquivos novamente (no pior dos casos).

Então, você realmente quer evitar ter memória "free" (que acontece de tempos em tempos depois que programas intensivos de memória morrem).

Editar1 : Além disso, o resultado acima é apenas das possíveis (e totalmente diferentes) respostas, pois tal questão é indefinida. Por exemplo, em vez de "Mem usado", você poderia ter usado "Mem usado em cache" (que mostraria quanta memória é usada quando você insere o cache de disco) - o que pode fornecer resultados como "15%" usados em vez de "80% usado"), e pode ser mais preciso - dependendo do que exatamente você está tentando realizar

Quanto ao uso de memória de processo, a mesma coisa - há muitas maneiras de dizer quanta memória um processo usa. É o valor que o programa requer (VSZ em ps output). Ou a quantidade atualmente na RAM (coluna RSS). E quando há várias instâncias com código compartilhado (por exemplo, se você tem 100 processos apache de 50MB RSS cada, eles NÃO usam 100 * 50 = 5000MB RAM, mas mais como 200MB no total), etc. Quando você sabe exatamente o que você quer, só então você pode continuar a calculá-lo (apenas VSZ, ou apenas RSS, ou compartilhado por RSS, ou compartilhado por RSS / numero de compartilhamento de processos, etc)

Observe também que esse tipo de pergunta é mais detalhado no superusuário.com.br

Edit2: quanto ao seu comentário, você está tentando evitar vazamento de memória em algum processo. Verificar se há memória livre é definitivamente errado, pois isso dará falsos positivos. Você deve limitar seu processo para evitar que vazamentos de memória diminuam o sistema (veja help ulimit no bash). O processo pode lidar com isso (bom) ou morrer quando não puder obter a quantidade necessária de memória, para que você possa reiniciá-lo (via monit, supervise, runit ou similar)

Edit3: além disso (ou como alternativa, mas muito melhor além disso) para definir limites de processo, você pode usar algo assim para reiniciar o processo quando o RSS cresce muito.

[ $(awk '/^VmRSS/ { print $2}' /proc/$PID/status) -gt 200 ] && echo killmeplease

em vez de $PID você usaria seu PID, é claro (por exemplo, de PID=$(cat /var/run/something.pid) ou PID=$(pidof somedaemon) etc.

No entanto, note que você provavelmente usaria melhor VmSize (ou VmPeak ) em vez de ( VmRSS ), caso contrário seu processo ainda pode desativar o sistema se ele entrar em swap (então o VmSize será grande, e VmRSS pequeno)

    
por 04.12.2014 / 02:25