Skrypt Bash, który automatycznie zabija procesy, gdy użycie procesora / pamięci staje się zbyt duże


11

Stworzyłem skrypt, który zabija procesy, jeśli użycie procesora i / lub pamięci osiągnie 80%. Gdy tak się dzieje, tworzona jest lista zabitych procesów. Co mogę zrobić, aby to poprawić?

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

3
Czy próbowałeś uruchomić skrypt? while [ 1 ]zastanawiam się, ile procesora sam ten skrypt zużyje. Ponadto 3 połączenia kill -9w skrypcie działającym stale? To daje mi dreszcze ...
rahmu

1
W każdym razie fajny awatar, @rahmu miał sleep 1pętlę
stokrotka

1
Pierwszy poniedziałek miesiąca, a mój komputer sprawdza (powolny) zestaw RAID6. Obciążenie procesora z łatwością osiąga wartości szczytowe powyżej 8, ponieważ stale oczekuje na IO dysku z tego zestawu RAID. Nic złego, system nadal bardzo reaguje. Twój skrypt zabiłby mojego firefoxa, który wykorzystuje tylko 3,6% z dostępnych 400%. Mówiąc tylko, że za pomocą tego skryptu możesz polować na duchy. BTW: twój system nie ulegnie uszkodzeniu z powodu dużego obciążenia, a gdy skończy się pamięć, jądro będzie na wpół wykształcone zgadywać, które procesy należy zabić.
jippie

Wtedy proces zabijania na podstawie obciążenia będzie w porządku czy nie ????
Ketan Patel

W moim przypadku zabijanie nie jest pożądane.
jippie

Odpowiedzi:


11

Jestem zgadywania problem chcesz rozwiązać to, że masz jakiś proces uruchomiony na polu, które czasami niegrzeczne i siedzi na zawsze pegging rdzeń.

Pierwszą rzeczą, którą chcesz zrobić, to spróbować naprawić zwariowany program. To zdecydowanie najlepsze rozwiązanie. Zakładam, że nie jest to możliwe, albo potrzebujesz szybkiego kluge, aby utrzymać swoje pudełko do czasu jego naprawy.

Przynajmniej chcesz ograniczyć swój skrypt, aby uderzył tylko w jeden program, którego dotyczysz. Byłoby najlepiej, gdyby uprawnienia ograniczały twój skrypt w ten sposób (np. Twój skrypt działa jako użytkownik X, jedyną inną rzeczą działającą jako X jest program).

Jeszcze lepiej byłoby użyć czegoś takiego jak ulimit -tograniczenie całkowitego czasu procesora, który program może wykorzystać. Podobnie, jeśli zużywa całą pamięć, sprawdź ulimit -v. Jądro wymusza te ograniczenia; zobacz stronę bashpodręcznika (jest to wbudowana powłoka) i stronę, setrlimit(2)aby uzyskać szczegółowe informacje.

Jeśli problemem nie jest uruchomiony proces amokowy, ale zamiast tego działa po prostu zbyt wiele procesów, to zaimplementuj jakąś formę blokowania, aby zapobiec uruchomieniu więcej niż X (lub - to powinno się zaznajomić - ulimit -u). Możesz także rozważyć zmianę priorytetu harmonogramu tych procesów (za pomocą nicelub renice), lub jeszcze bardziej drastycznego, za pomocą sched_setschedulerzmiany polityki na SCHED_IDLE.

Jeśli potrzebujesz jeszcze większej kontroli, spójrz na grupy kontrolne (cgroups). W zależności od uruchomionego jądra możesz faktycznie ograniczyć czas procesora, pamięć, operacje we / wy itp., Które pochłania cała grupa procesów. Grupy kontrolne są dość elastyczne; prawdopodobnie zrobią wszystko, co chcesz, bez żadnych kruchych ćwiartek. Arch Arch Wiki ma wprowadzenie do grup, które warto przeczytać, podobnie jak seria cgroups Neila Browna w LWN.


3

Zagadnienia:

  • Przy sortowaniu pól numerycznych prawdopodobnie chcesz skorzystać z -nopcji: sort -nrk 2. W przeciwnym razie linia o %CPUwartości 5,0 skończy się wyżej niż jedna o wartości 12,0.
  • W zależności od psimplementacji możesz chcieć skorzystać z --no-headersopcji, aby się go pozbyć grep -v. Zapobiega to odrzucaniu poleceń zawierających PID.
  • Chyba zamiast tego echo CPU USAGE is at $CPU_LOADmiałeś na myśli echo CPU USAGE is at $CPU_USAGE.
  • Chyba zapomniałeś usunąć to exit 0, co wstawiłeś podczas debugowania (?).

Styl:

  • Możesz przenieść CPU_USAGE_THRESHOLD=800linię na początek pliku, ponieważ jest to najbardziej pouczająca rzecz i najprawdopodobniej ulegnie zmianie nawet po stabilnym skrypcie.
  • Powtarzasz -eopcję: ps -eo pid -eo pcpu -eo commandjest taka sama jak ps -eo pid -o pcpu -o command(jak jest ps -eo pid,pcpu,command).
  • Jest pusta elseklauzula. To zawsze wygląda na to, że należy sobie z tym poradzić, ale nie z jakiegoś nieznanego powodu.

2

Zabicie procesów, które wykorzystują najwięcej procesora / pamięci, wymaga problemów: wystarczy spojrzeć na to, jakie są teraz na twoim komputerze (tutaj obecnie firefox, systemd (init), Xorg, gnome-terminal, zestaw wątków jądra, xemacs; z których żaden nie jest zbędny). Zobacz, jak na przykład ulepszyć OOM-zabójcę Linuksa, na przykład tutaj .

Zauważ też, że „pamięć używana przez proces” jest mglistym pojęciem, ponieważ istnieją wspólne biblioteki, pliki wykonywalne są wspólne, a nawet części obszarów danych. Można wymyślić pewną liczbę, obciążając każdego użytkownika ułamkiem zużytej przestrzeni, ale nawet dodanie tego w rzeczywistości nie daje „zużytej pamięci” (nawet mniej „zwolnionej pamięci, jeśli proces zniknie”, dzielone części pozostają za).


1

Stworzyłem skrypt, kill-process , który zabija niektóre procesy wymienione w tablicy, jeśli użycie procesora jest większe niż XX% przez YY sekund lub zabija procesy, które działają dłużej niż ZZ sekundy.

  • Możesz ustawić XX, YY, ZZ w górnej części pliku.
  • Do sprawdzania możesz użyć ps lub top.
  • Dostępny jest również tryb próbny, aby sprawdzić, ale nie zabić.
  • Ostatecznie skrypt wysyła wiadomość e-mail, jeśli niektóre procesy zostały zabite.

UWAGA: Oto moje repozytorium na Github: https://github.com/padosoft/kill-process

Oto zrzut ekranu:

         ss # 1

Bibliografia

Zasadnicza część skryptu (streszczenie kodu dla najwyższej komendy):

#!/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
Stosowanie:
bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]

Wydaje się, że sortpowinno być sort -k9nr. Bez notrzyma „5.9”> 29.4.
lk_vc,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.