Сценарий Bash, который автоматически убивает процессы, когда загрузка процессора / памяти становится слишком высокой

Я создал сценарий, который убивает процессы, если использование процессора и / или памяти достигает 80%. Он создает список убитых процессов, когда это происходит. Что я могу сделать, чтобы улучшить его?

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 

Я предполагаю, что проблема, которую вы хотите решить, заключается в том, что на вашем ящике есть какой-то процесс, который иногда ошибочно работает и сидит навсегда, привязывая ядро.

Первое, что вы хотите сделать, это попытаться исправить программу, которая сходит с ума. Это, безусловно, лучшее решение. Я собираюсь предположить, что это невозможно, или вам нужно быстрое kluge, чтобы ваша коробка работала до тех пор, пока она не будет исправлена.

Вы, как минимум, хотите ограничить свой сценарий только ударом по одной программе, о которой вы беспокоитесь. Было бы лучше, если бы разрешения ограничивали ваш скрипт таким образом (например, ваш скрипт запускается как пользователь X, единственное, что работает, поскольку X – это программа).

Еще лучше было бы использовать что-то вроде ulimit -t чтобы ограничить количество общего времени процессора, которое может использовать программа. Аналогично, если он потребляет всю память, проверьте ulimit -v . Ядро обеспечивает соблюдение этих ограничений; см. setrlimit(2) bash (это встроенная оболочка) и setrlimit(2) .

Если проблема не является процессом, выполняемым amok, но вместо этого выполняется слишком много процессов, тогда реализуется некоторая форма блокировки, чтобы предотвратить запуск X (или – это должно быть знакомо – ulimit -u ). Вы также можете рассмотреть возможность изменения приоритета планировщика этих процессов (с использованием nice или renice ) или для еще более резкого использования, с помощью sched_setscheduler чтобы изменить политику на SCHED_IDLE .

Если вам нужен еще больший контроль, посмотрите контрольные группы (группы). В зависимости от ядра, которое вы используете, вы можете ограничить количество процессорного времени, памяти, ввода-вывода и т. Д., Которые потребляют целая группа процессов. Контрольные группы довольно гибкие; они могут делать все, что вы пытаетесь сделать, без каких-либо хрупких клише. В Arch Linux Wiki есть вступление к группам, которые стоит прочитать, так же как серия групп Нила Брауна в LWN.

Вопросы:

  • При сортировке числовых полей вы, вероятно, захотите использовать опцию -n : sort -nrk 2 . В противном случае строка с значением %CPU 5.0 будет выше, чем значение со значением 12.0.
  • В зависимости от вашей реализации ps вы можете использовать опцию --no-headers чтобы избавиться от grep -v . Это предотвращает отбрасывание команд, содержащих PID .
  • Я думаю, вместо echo CPU USAGE is at $CPU_LOAD , вы имели в виду echo CPU USAGE is at $CPU_USAGE .
  • Думаю, вы забыли удалить exit 0 который вы вставили во время отладки (?).

Стиль:

  • Возможно, вам захочется переместить CPU_USAGE_THRESHOLD=800 в начало файла, так как это наиболее информативная вещь и, скорее всего, будет изменена даже после того, как ваш скрипт будет стабильным.
  • Вы повторяете параметр -e : ps -eo pid -eo pcpu -eo command такая же, как ps -eo pid -o pcpu -o command (как ps -eo pid,pcpu,command ).
  • Существует пустое предложение else . Это всегда выглядит так, как будто его нужно обрабатывать, но не по какой-то неизвестной причине.

Убивание процессов, использующих большинство процессоров / памяти, вызывает проблемы: просто посмотрите, что они сейчас на вашем компьютере (здесь в настоящее время firefox, systemd (init), Xorg, gnome-terminal, набор потоков ядра, xemacs; ни одна из которых не является приемлемой). Посмотрите, как можно настроить Linux-OOM-killer, например здесь .

Также обратите внимание, что «память, используемая процессом», представляет собой туманную концепцию, так как существуют общие библиотеки, общие исполняемые файлы и даже части областей данных. Можно придумать какое-то количество, зарядив каждого пользователя частью используемого пространства, но даже добавив, что на самом деле не дает «используемой памяти» (даже меньше «освобождается память, если процесс уходит», общее разделение частей за).

Я создал сценарий kill-process , который убивает некоторые процессы, перечисленные в массиве, если использование ЦП превышает XX% за YY секунд или убивает процессы, которые работают больше, чем ZZ секунд.

  • Вы можете установить XX, YY, ZZ в верхней части файла.
  • Вы можете использовать ps или top для проверки процессов.
  • Также есть режим сухого режима, чтобы проверить, но не убить.
  • В конце сценарий отправляет электронное письмо, если некоторые процессы были убиты.

ПРИМЕЧАНИЕ. Вот мое репо на Github: https://github.com/padosoft/kill-process

Вот скриншот:

сс # 1

Рекомендации

  • Исходный источник снимка экрана

Существенная часть скрипта (абзац кода для верхней команды):

 #!/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 

Применение:

 bash killprocess.sh [dry|kill|--help] [top|ps] [cpu|time]