Script bash qui tue automatiquement les processus lorsque l'utilisation CPU / mémoire devient trop élevée

11

J'ai créé un script qui tue les processus si l'utilisation du processeur et / ou de la mémoire atteint 80%. Il crée une liste de processus tués lorsque cela se produit. Que puis-je faire pour l'améliorer?

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
la source
3
Avez-vous essayé d'exécuter le script? while [ 1 ]me fait me demander combien de CPU ce script seul va consommer. De plus, 3 appels à kill -9un script s'exécutant en permanence? Cela me donne des frissons ...
rahmu
1
Nice avatar de toute façon, @rahmu, il a obtenu sleep 1dans la boucle
marguerite
1
Le premier lundi du mois et mon PC vérifie un ensemble RAID6 (lent). La charge du processeur culmine facilement au-dessus de 8 car elle attend constamment les E / S disque de cet ensemble RAID. Rien à redire, le système est toujours très réactif. Votre script tuerait mon firefox qui n'utilise que 3,6% des 400% disponibles. Je dis juste que vous cherchez peut-être des fantômes avec ce script. BTW: votre système ne sera pas endommagé à cause d'une charge élevée et lorsque la mémoire sera épuisée, le noyau fera une supposition semi-éclairée sur le ou les processus à tuer.
jippie
Ensuite, le processus de mise à mort sur la charge basée sera bien ou pas ????
Ketan Patel
Dans mon cas d'utilisation, la mise à mort n'est pas souhaitée.
jippie

Réponses:

11

Je devine que le problème que vous voulez résoudre est que vous avez un processus en cours d'exécution sur votre boîte qui parfois se comporte mal, et se repose toujours un noyau chevillage.

La première chose que vous voulez faire est d'essayer de réparer le programme qui devient fou. C'est de loin la meilleure solution. Je vais supposer que ce n'est pas possible, ou vous avez besoin d'un kluge rapide pour faire fonctionner votre boîte jusqu'à ce qu'elle soit réparée.

Vous voulez, au minimum, limiter votre script pour ne frapper que le seul programme qui vous préoccupe. Il serait préférable que les autorisations limitent votre script comme ceci (par exemple, votre script s'exécute en tant qu'utilisateur X, la seule autre chose qui s'exécute en tant que X est le programme).

Encore mieux serait d'utiliser quelque chose comme ulimit -tpour limiter la quantité totale de temps CPU que le programme peut utiliser. De même, s'il consomme toute la mémoire, vérifiez ulimit -v. Le noyau applique ces limites; voir la bashpage de manuel (c'est un shell intégré) et la setrlimit(2)page de manuel pour plus de détails.

Si le problème n'est pas un processus en cours d'exécution, mais plutôt un trop grand nombre de processus en cours d'exécution, alors implémentez une forme de verrouillage pour empêcher plus de X de s'exécuter (ou — cela devrait devenir familier— ulimit -u). Vous pouvez également envisager de modifier la priorité du planificateur de ces processus (à l'aide de niceou renice), ou, encore plus radicalement, à l'aide sched_setschedulerde la modification de la stratégie en SCHED_IDLE.

Si vous avez besoin d'encore plus de contrôle, jetez un oeil à des groupes de contrôle (cgroups). En fonction du noyau que vous exécutez, vous pouvez réellement limiter la quantité de temps CPU, de mémoire, d'E / S, etc. qu'un ensemble de processus consomme ensemble. Les groupes de contrôle sont assez flexibles; ils peuvent probablement faire tout ce que vous essayez de faire, sans kluges fragiles. Le Wiki Arch Linux a une introduction aux groupes de discussion qui vaut la peine d'être lue, tout comme la série de groupes de Neil Brown au LWN.

derobert
la source
3

Problèmes:

  • Lorsque les champs numériques de tri que vous voulez probablement utiliser l' -noption de : sort -nrk 2. Sinon, une ligne avec une %CPUvaleur de 5,0 se retrouvera supérieure à une avec une valeur de 12,0.
  • Selon votre psimplémentation, vous souhaiterez peut-être utiliser l' --no-headersoption pour vous débarrasser de grep -v. Cela vous empêche de rejeter les commandes qui contiennent PID.
  • Je suppose qu'au lieu de echo CPU USAGE is at $CPU_LOAD, tu voulais dire echo CPU USAGE is at $CPU_USAGE.
  • Je suppose que vous avez oublié de supprimer le fichier exit 0que vous avez inséré lors du débogage (?).

Style:

  • Vous voudrez peut-être déplacer la CPU_USAGE_THRESHOLD=800ligne au début du fichier, car c'est la chose la plus informative et la plus susceptible d'être modifiée même après la stabilité de votre script.
  • Vous répétez l' -eoption: ps -eo pid -eo pcpu -eo commandest identique à ps -eo pid -o pcpu -o command(tel quel ps -eo pid,pcpu,command).
  • Il y a une elseclause vide . Cela semble toujours devoir être géré, mais ce n'était pas pour une raison inconnue.
Yurim
la source
2

Tuer les processus qui utilisent le plus de CPU / mémoire demande des ennuis: regardez simplement ce qu'ils sont en ce moment sur votre machine (ici actuellement firefox, systemd (init), Xorg, gnome-terminal, un ensemble de threads du noyau, xemacs; dont aucun n'est dispensable). Regardez comment tordre OOM-killer de Linux, par exemple ici .

Notez également que la «mémoire utilisée par le processus» est un concept nébuleux, car il existe des bibliothèques partagées, des exécutables partagés et même des parties de zones de données. On peut trouver un certain nombre en chargeant chaque utilisateur d'une fraction de l'espace utilisé, mais même en ajoutant cela ne donne vraiment pas de "mémoire utilisée" (encore moins de "mémoire libérée si le processus disparaît", les parties partagées restent derrière).

vonbrand
la source
1

J'ai créé un script, kill-process , qui tue certains processus répertoriés dans un tableau, si l'utilisation du processeur est supérieure à XX% pendant YY secondes ou les processus kill qui s'exécutent plus de ZZ secondes.

  • Vous pouvez définir XX, YY, ZZ en haut du fichier.
  • Vous pouvez utiliser un ps ou un top pour les processus de vérification.
  • Il existe également un mode de fonctionnement à sec, pour vérifier mais pas tuer.
  • Au final, le script envoie un e-mail si certains processus ont été tués.

REMARQUE: voici mon dépôt sur Github: https://github.com/padosoft/kill-process

Voici une capture d'écran:

         SS # 1

Les références

Partie essentielle du script (un résumé de code pour la commande supérieure):

#!/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
Usage:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]
Lorenzo Padovani
la source
Il semble que ce sortsoit le cas sort -k9nr. Sans n, obtiendra «5,9»> 29.4.
lk_vc