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

Предположение от хинду Wiki, редактируя NTPD_OPTS в /etc/conf.d/ntpd вероятно, добивается цели (независимо от вопроса, если -g желательно, никакая идея).

11
24.08.2015, 20:18
4 ответа

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

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

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

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

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

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

11
27.01.2020, 19:58

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

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

2
27.01.2020, 19:58

Проблемы:

  • При сортировке числовых полей вы, вероятно, захотите чтобы использовать параметр -n : sort -nrk 2 . В противном случае строка со значением 5,0 % CPU окажется выше, чем строка со значением 12,0.
  • В зависимости от реализации ps вы можете использовать параметр - no-headers , чтобы избавиться от grep -v . Это не позволяет вам отбрасывать команды, содержащие PID .
  • Я полагаю, вместо echo ИСПОЛЬЗОВАНИЕ ЦП находится в $ CPU_LOAD , вы имели в виду echo ИСПОЛЬЗОВАНИЕ ЦП в $ 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 . Это всегда выглядит так, как будто с этим нужно справиться, но не по какой-то неизвестной причине.
3
27.01.2020, 19:58

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

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

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

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

ss#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]
1
27.01.2020, 19:58

Теги

Похожие вопросы