Script Bash que mata automaticamente processos quando o uso da CPU / memória fica muito alto

11

Eu criei um script que mata processos se o uso de CPU e / ou memória atingir 80%. Cria uma lista de processos mortos quando isso acontece. O que posso fazer para melhorar isso?

while [ 1 ];
do 
echo
echo checking for run-away process ...

CPU_USAGE=$(uptime | cut -d"," -f4 | cut -d":" -f2 | cut -d" " -f2 | sed -e "s/\.//g")
CPU_USAGE_THRESHOLD=800
PROCESS=$(ps aux r)
TOPPROCESS=$(ps -eo pid -eo pcpu -eo command | sort -k 2 -r | grep -v PID | head -n 1)

if [ $CPU_USAGE -gt $CPU_USAGE_THRESHOLD] ; then
  kill -9 $(ps -eo pid | sort -k 1 -r | grep -v PID | head -n 1) #original
  kill -9 $(ps -eo pcpu | sort -k 1 -r | grep -v %CPU | head -n 1)
  kill -9 $TOPPROCESS
  echo system overloading!
  echo Top-most process killed $TOPPROCESS
      echo CPU USAGE is at $CPU_LOAD

else
    fi
    exit 0
    sleep 1;
    done
    
por Ketan Patel 04.03.2013 / 08:45

4 respostas

11

Estou adivinhando que o problema que você quer resolver é que você tem algum processo sendo executado em sua caixa, que às vezes se comporta mal, e fica para sempre identificando um núcleo.

A primeira coisa que você quer fazer é tentar consertar o programa que enlouquece. Essa é de longe a melhor solução. Eu vou assumir que isso não é possível, ou você precisa de um kluge rápido para manter sua caixa funcionando até que seja consertado.

Você, no mínimo, deseja limitar seu script a apenas atingir o único programa com o qual está preocupado. Seria melhor se as permissões limitassem seu script assim (por exemplo, seu script é executado como usuário X, a única outra coisa sendo executada como X é o programa).

Melhor ainda seria usar algo como ulimit -t para limitar a quantidade de tempo total de CPU que o programa pode usar. Da mesma forma, se consumir toda a memória, verifique ulimit -v . O kernel impõe esses limites; veja o bash manpage (é um shell embutido) e o setrlimit(2) manpage para detalhes.

Se o problema não for um processo em execução, mas apenas muitos processos em execução, implemente alguma forma de bloqueio para impedir que mais de X seja executado (ou - isso deve estar familiarizado - ulimit -u ). Você também pode considerar a alteração da prioridade do agendador desses processos (usando nice ou renice ), ou para ainda mais drástico, usando sched_setscheduler para alterar a política para SCHED_IDLE .

Se você precisar de mais controle, dê uma olhada nos grupos de controle (cgroups). Dependendo do kernel que você está executando, você pode realmente limitar a quantidade de tempo de CPU, memória, E / S, etc. que um grupo inteiro de processos juntos consome. Grupos de controle são bastante flexíveis; eles provavelmente podem fazer o que você estiver tentando fazer, sem quaisquer kluges frágeis. O Wiki do Arch Linux tem uma introdução aos cgroups que vale a pena ler, assim como A série de cgroups de Neil Brown na LWN.

    
por 04.03.2013 / 20:56
3

Problemas:

  • Ao classificar campos numéricos, você provavelmente desejará usar a opção -n : sort -nrk 2 . Caso contrário, uma linha com um valor %CPU de 5.0 será maior que uma com um valor de 12,0.
  • Dependendo da implementação do ps , talvez você queira usar a opção --no-headers para se livrar do grep -v . Isso evita que você descarte comandos que contenham PID .
  • Em vez de echo CPU USAGE is at $CPU_LOAD , você quis dizer echo CPU USAGE is at $CPU_USAGE .
  • Eu acho que você esqueceu de remover o exit 0 que você inseriu durante a depuração (?).

Estilo:

  • Você pode querer mover a linha CPU_USAGE_THRESHOLD=800 para o início do arquivo, já que isso é a coisa mais informativa e é mais provável que seja alterada mesmo depois que o script estiver estável.
  • Você está repetindo a opção -e : ps -eo pid -eo pcpu -eo command é o mesmo que ps -eo pid -o pcpu -o command (como é ps -eo pid,pcpu,command ).
  • Existe uma cláusula else vazia. Isso sempre parece que deve ser tratado, mas não foi por alguma razão desconhecida.
por 14.05.2014 / 22:02
2

Eliminar processos que estão usando a maioria da CPU / memória está causando problemas: Apenas observe o que eles estão agora em sua máquina (aqui atualmente firefox, systemd (init), Xorg, gnome-terminal, um conjunto de encadeamentos do kernel , xemacs; nenhum dos quais é dispensável). Veja como ajustar o OOM-killer do Linux, por exemplo aqui .

Observe também que "memória usada pelo processo" é um conceito nebuloso, pois há bibliotecas compartilhadas, executáveis compartilhados e até partes de áreas de dados. Pode-se chegar a um certo número cobrando cada usuário com uma fração do espaço usado, mas mesmo acrescentando que realmente não dá "memória usada" (ainda menos "memória liberada se o processo desaparece", as peças compartilhadas ficar atrás).

    
por 04.03.2013 / 18:28
1

Eu criei um script, kill-process , que mata alguns processos listados em uma matriz, se o uso da CPU for maior que XX% por YY segundos ou processos de eliminação que estão executando mais de ZZ segundos.

  • Você pode definir XX, YY, ZZ na parte superior do arquivo.
  • Você pode usar um ps ou top para processos de verificação.
  • Também há um modo de execução a seco para verificar, mas não para matar.
  • No final, o script envia um email se alguns processos foram eliminados.

OBSERVAÇÃO: aqui está meu repo no Github: link

Aqui está uma captura de tela:

Referências

  • Origem da captura de tela original

Parte essencial do script (um resumo de código para o comando principal):

#!/usr/bin/env bash

#max cpu % load
MAX_CPU=90
#max execution time for CPU percentage > MAX_CPU (in seconds 7200s=2h)
MAX_SEC=1800
#sort by cpu
SORTBY=9

#define a processes command name to check
declare -a KILLLIST
KILLLIST=("/usr/sbin/apache2" "/usr/bin/php5-cgi")

#iterate for each process to check in list
for PROCESS_TOCHECK in ${KILLLIST[*]}
do

    #retrive pid with top command order by SORTBY
    PID=$(top -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $1}')

    CPU=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $9}')
    TIME_STR=$(top -p $PID -bcSH -n 1 | grep $PROCESS_TOCHECK | sort -k $SORTBY -r | head -n 1 | awk '{print $11}')

    # Decode the top CPU time format [dd-]hh:mm.ss.
    TIME_SEC=0
    IFS="-:" read c1 c2 c3 c4 <<< "$TIME_STR"

    #with top command time format is hh:mm.ss, so truncare seconds in c2
    c2=${c2%%.*}

    if [ -n "$c4" ]
    then
      TIME_SEC=$((10#$c4+60*(10#$c3+60*(10#$c2+24*10#$c1))))
    elif [ -n "$c3" ]
    then
      if [ "$CMD" = "ps" ]; then
        TIME_SEC=$((10#$c3+60*(10#$c2+60*10#$c1)))
      else
        TIME_SEC=$(((10#$c3*24)*60*60)+60*(10#$c2+60*10#$c1))             
      fi   
    else
      if [ "$CMD" = "ps" ]; then
        TIME_SEC=$((10#0+(10#$c2+60*10#$c1)))
      else
        TIME_SEC=$((10#0+60*(10#$c2+60*10#$c1)))
      fi
    fi

    #check if need to kill process
    if [ $CPU -gt $MAX_CPU ] && [ $TIME_SEC -gt $MAX_SEC ]; then
        kill -15 $PID
    fi

done
Uso:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]
    
por 06.06.2016 / 11:27