Bash-Skript, das Prozesse automatisch beendet, wenn die CPU- / Speicherauslastung zu hoch wird

11

Ich habe ein Skript erstellt, das Prozesse abbricht, wenn die CPU- und / oder Speicherauslastung 80% erreicht. In diesem Fall wird eine Liste der abgebrochenen Prozesse erstellt. Was kann ich tun, um es zu verbessern?

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
quelle
3
Haben Sie versucht, das Skript auszuführen? while [ 1 ]Ich frage mich, wie viel CPU dieses Skript alleine verbrauchen wird. Auch 3 Aufrufe kill -9in einem Skript laufen ständig? Dies gibt mir die Schüttelfrost ...
Rahmu
1
Nizza Avatar sowieso @rahmu bekam er sleep 1in der Schleife
Daisy
1
Am ersten Montag des Monats überprüft mein PC ein (langsames) RAID6-Set. Die CPU-Auslastung liegt leicht über 8, da ständig auf Festplatten-E / A von diesem RAID-Satz gewartet wird. Nichts falsches, das System reagiert immer noch sehr schnell. Ihr Skript würde meinen Firefox töten, der nur 3,6% der verfügbaren 400% verwendet. Ich sage nur, dass Sie mit diesem Skript möglicherweise nach Geistern suchen. Übrigens: Ihr System wird aufgrund der hohen Auslastung nicht beschädigt. Wenn der Speicher knapp wird, errät der Kernel, welche Prozesse beendet werden sollen.
Jippie
Dann wird der Kill-Prozess auf Basis der Last in Ordnung sein oder nicht ????
Ketan Patel
In meinem Anwendungsfall ist das Töten nicht erwünscht.
Jippie

Antworten:

11

Ich vermute, das Problem, das Sie lösen möchten, ist, dass auf Ihrer Box ein Prozess ausgeführt wird, der sich manchmal schlecht verhält und für immer einen Kern festhält.

Das erste, was Sie tun möchten, ist zu versuchen, das Programm zu reparieren, das verrückt wird. Das ist bei weitem die beste Lösung. Ich gehe davon aus, dass dies nicht möglich ist, oder Sie benötigen eine schnelle Kluge, um Ihre Box am Laufen zu halten, bis sie repariert ist.

Sie möchten Ihr Skript zumindest so einschränken, dass nur das eine Programm angezeigt wird, um das Sie sich Sorgen machen. Es ist am besten, wenn die Berechtigungen Ihr Skript wie folgt einschränken (z. B. wird Ihr Skript als Benutzer X ausgeführt, das einzige andere, was als X ausgeführt wird, ist das Programm).

Noch besser wäre es, die ulimit -tGesamt-CPU-Zeit zu begrenzen, die das Programm verwenden kann. Überprüfen Sie in ähnlicher Weise, ob der gesamte Speicher belegt ist ulimit -v. Der Kernel erzwingt diese Grenzen. Weitere Informationen finden Sie in der bashManpage (es ist eine integrierte Shell) und in der setrlimit(2)Manpage.

Wenn das Problem nicht ein Amok-Prozess ist, sondern nur zu viele Prozesse ausgeführt werden, implementieren Sie eine Art Sperre, um zu verhindern, dass mehr als X ausgeführt wird (oder - dies sollte bekannt werden ulimit -u). Sie können auch in Betracht ziehen, die Scheduler-Priorität dieser Prozesse zu ändern (mithilfe von niceoder renice) oder noch drastischer, indem Sie sched_setschedulerdie Richtlinie in ändern SCHED_IDLE.

Wenn Sie noch mehr Kontrolle benötigen, schauen Sie sich eine Kontrollgruppe (cgroups) an. Abhängig von dem Kernel, den Sie ausführen, können Sie die CPU-Zeit, den Arbeitsspeicher, die E / A usw., die eine ganze Gruppe von Prozessen zusammen verbraucht, tatsächlich begrenzen. Kontrollgruppen sind sehr flexibel; Sie können wahrscheinlich alles tun, was Sie versuchen, ohne zerbrechliche Klugheiten. Das Arch Linux Wiki bietet eine lesenswerte Einführung in cgroups , ebenso wie Neil Browns cgroups-Reihe bei LWN.

derobert
quelle
3

Probleme:

  • Wenn Sie numerische Felder sortieren, möchten Sie wahrscheinlich die -nOption verwenden : sort -nrk 2. Andernfalls wird eine Zeile mit einem %CPUWert von 5,0 höher als eine Zeile mit einem Wert von 12,0.
  • Abhängig von Ihrer psImplementierung möchten Sie möglicherweise die --no-headersOption verwenden, um die zu entfernen grep -v. Dies verhindert, dass Sie Befehle verwerfen, die enthalten PID.
  • Ich denke statt echo CPU USAGE is at $CPU_LOAD, meintest du echo CPU USAGE is at $CPU_USAGE.
  • Ich denke, Sie haben vergessen, das zu entfernen exit 0, was Sie beim Debuggen eingefügt haben (?).

Stil:

  • Möglicherweise möchten Sie die CPU_USAGE_THRESHOLD=800Zeile an den Anfang der Datei verschieben, da dies die informativste Sache ist und wahrscheinlich auch dann geändert wird, wenn Ihr Skript stabil ist.
  • Sie wiederholen die -eOption: ps -eo pid -eo pcpu -eo commandist dasselbe wie ps -eo pid -o pcpu -o command(wie es ist ps -eo pid,pcpu,command).
  • Es gibt eine leere elseKlausel. Das sieht immer so aus, als ob es gehandhabt werden sollte, war aber nicht aus einem unbekannten Grund.
Yurim
quelle
2

Das Abschalten von Prozessen, die die meiste CPU / den meisten Arbeitsspeicher belegen, ist problematisch: Sehen Sie sich nur an, was sich gerade auf Ihrem Computer befindet (hier derzeit Firefox, Systemd (Init), Xorg, Gnome-Terminal, eine Reihe von Kernel-Threads, Xemacs; keines davon entbehrlich). Sehen Sie sich zum Beispiel hier an, wie Sie den OOM-Killer von Linux optimieren können .

Beachten Sie auch, dass "vom Prozess verwendeter Speicher" ein nebulöses Konzept ist, da es gemeinsam genutzte Bibliotheken, ausführbare Dateien und sogar Teile von Datenbereichen gibt. Man kann sich eine Nummer einfallen lassen, indem man jedem Benutzer einen Bruchteil des genutzten Speicherplatzes in Rechnung stellt, aber selbst wenn man dies addiert, erhält man keinen "verwendeten Speicher" (noch weniger "Speicher wird freigegeben, wenn der Prozess wegfällt", die gemeinsam genutzten Teile bleiben erhalten hinter).

vonbrand
quelle
1

Ich habe ein Skript namens kill-process erstellt , das einige in einem Array aufgelistete Prozesse beendet, wenn die CPU-Auslastung für YY-Sekunden größer als XX% ist, oder Prozesse beendet, die länger als ZZ-Sekunden ausgeführt werden.

  • Sie können XX, YY, ZZ oben in der Datei festlegen.
  • Sie können ein ps oder top für Überprüfungsprozesse verwenden.
  • Es gibt auch einen Trockenlaufmodus, um zu überprüfen, aber nicht zu töten.
  • Am Ende sendet das Skript eine E-Mail, wenn einige Prozesse abgebrochen wurden.

HINWEIS: Hier ist mein Repo auf Github: https://github.com/padosoft/kill-process

Hier ist ein Screenshot:

         ss # 1

Verweise

Wesentlicher Teil des Skripts (eine Code-Zusammenfassung für den obersten Befehl):

#!/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
Verwendung:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]
Lorenzo Padovani
quelle
Scheint sortsollte sein sort -k9nr. Ohne nwird `5.9`> bekommen 29.4.
lk_vc