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

11

Eu criei um script que mata processos se o uso da CPU e / ou memória atingir 80%. Ele 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
Ketan Patel
fonte
3
Você já tentou executar o script? while [ 1 ]me faz pensar em quanto CPU esse script sozinho consumirá. Além disso, três chamadas kill -9em um script em execução constante? Isso me dá arrepios ...
rahmu
1
Agradável avatar de qualquer maneira, @rahmu ele conseguiu um sleep 1no laço
margarida
1
Primeira segunda-feira do mês e meu PC está verificando um conjunto RAID6 (lento). A carga da CPU atinge um pico facilmente acima de 8, pois aguarda constantemente E / S de disco desse conjunto RAID. Nada de errado, o sistema ainda é muito responsivo. Seu script mataria o meu Firefox, que usa apenas 3,6% dos 400% disponíveis. Só estou dizendo que você pode estar procurando fantasmas com esse script. BTW: seu sistema não será danificado devido à alta carga e, quando a memória acabar, o kernel fará um palpite semi-educado sobre quais processos serão eliminados.
jippie
Então, matar o processo com base em carga ficará bom ou não ????
Ketan Patel # 03
No meu caso de uso, a matança não é desejada.
jippie

Respostas:

11

Eu estou supondo que o problema que você quer resolver é que você tem algum processo em execução em sua caixa que às vezes se comporta mal, e senta-se para sempre atrelar um núcleo.

A primeira coisa que você quer fazer é tentar consertar o programa que fica louco. 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 consertada.

Você, no mínimo, deseja limitar seu script para atingir apenas o programa com o qual se preocupa. 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 -tpara limitar a quantidade total de tempo 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 a página de bashmanual (é um shell embutido) e a página de setrlimit(2)manual para obter detalhes.

Se o problema não é um processo que está ficando maluco, mas sim muitos processos em execução, implemente alguma forma de bloqueio para impedir que mais do que o X seja executado (ou - isso deve estar se familiarizando ulimit -u). Você também pode alterar a prioridade do agendador desses processos (usando niceou renice) ou, ainda mais drástico, sched_setschedulerpara alterar a política SCHED_IDLE.

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

derobert
fonte
3

Problemas:

  • Ao classificar os campos numéricos que você provavelmente vai querer usar a -nopção: sort -nrk 2. Caso contrário, uma linha com um %CPUvalor de 5,0 acabará sendo maior que uma com um valor de 12,0.
  • Dependendo da sua psimplementação, convém usar a --no-headersopção para se livrar do grep -v. Isso impede que você descarte comandos que contenham PID.
  • Eu acho que 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 0que você inseriu durante a depuração (?).

Estilo:

  • Você pode mover a CPU_USAGE_THRESHOLD=800linha para o início do arquivo, pois essa é a coisa mais informativa e mais provável de ser alterada, mesmo após a estabilidade do script.
  • Você está repetindo a -eopção: ps -eo pid -eo pcpu -eo commandé o mesmo que ps -eo pid -o pcpu -o command(como está ps -eo pid,pcpu,command).
  • Existe uma elsecláusula vazia . Isso sempre parece que deve ser tratado, mas não foi por algum motivo desconhecido.
Yurim
fonte
2

Eliminar processos que estão usando a maioria da CPU / memória está causando problemas: basta olhar para o que eles estão agora em sua máquina (aqui atualmente firefox, systemd (init), Xorg, gnome-terminal, um conjunto de threads 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 existem bibliotecas compartilhadas, executáveis ​​são compartilhados e até partes de áreas de dados. Pode-se chegar a algum número cobrando a cada usuário uma fração do espaço usado, mas mesmo acrescentando isso não dá "memória usada" (menos ainda "memória liberada se o processo for interrompido", as partes compartilhadas permanecem atrás).

vonbrand
fonte
1

Criei um script, kill-process , que mata alguns processos listados em uma matriz, se o uso da CPU for maior que XX% por segundos YY ou matar processos com 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 existe um modo de funcionamento a seco, para verificar, mas não matar.
  • No final, o script envia um email se alguns processos foram mortos.

NOTA: Aqui está meu repositório no Github: https://github.com/padosoft/kill-process

Aqui está uma captura de tela:

         ss # 1

Referências

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

#!/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]
Lorenzo Padovani
fonte
Parece sortser sort -k9nr. Sem n, receberá `5.9`> 29.4.
Lk_vc 10/03