Вопрос или проблема
Я ищу способ убить все процессы с заданным именем, которые работают более X времени. Я запускаю много экземпляров этого конкретного исполняемого файла, и иногда он попадает в плохое состояние и работает бесконечно, забирая много CPU.
Я уже использую monit, но я не знаю, как проверить процесс без pid файла. Правило будет что-то вроде этого:
убить все процессы с именем xxxx, которые работают более 2 минут
Как бы вы это выразили в monit?
В monit вы можете использовать строку соответствия для процессов, у которых нет PID. Используя пример процесса с именем “myprocessname”,
check process myprocessname
matching "myprocessname"
start program = "/etc/init.d/myproccessname start"
stop program = "/usr/bin/killall myprocessname"
if cpu usage > 95% for 10 cycles then restart
Может быть, если вы проверите, загружен ли CPU на определенном уровне в течение 10 циклов мониторинга (по 30 секунд каждый), то перезапустите или убейте, это может быть вариантом. Или вы могли бы использовать тестирование временных меток monit на файле, связанном с процессом.
Нет готового инструмента с такой функциональностью. Допустим, вы хотите убить php-cgi скрипты, которые работают дольше минуты. Сделайте это:
pgrep php-cgi | xargs ps -o pid,time | perl -ne 'print "$1 " if /^\s*([0-9]+) ([0-9]+:[0-9]+:[0-9]+)/ && $2 gt "00:01:00"' | xargs kill
pgrep
выберет процессы по имени, ps -o pid,time
выводит время выполнения для каждого pid, а затем анализирует строку, извлекает время из нее и выводит pid, если время сравнивается с заданным. результат передается в kill.
Я решил эту проблему с помощью ps-watcher и писал об этом на linux.com несколько лет назад. ps-watcher позволяет вам мониторить процессы и убивать их на основе накопленного времени выполнения. Вот соответствующая конфигурация ps-watcher, предполагая, что ваш процесс называется ‘foo’:
[foo]
occurs = every
trigger = elapsed2secs('$time') > 1*HOURS && $ppid != 1
action = <<EOT
echo "$command накопил слишком много времени процессора" | /bin/mail user\@host
kill -TERM $pid
EOT
[foo?]
occurs = none
action = /usr/local/etc/foo restart
Ключевое значение — это строка
trigger = elapsed2secs('$time') > 1*HOURS && $ppid != 1`
которая говорит: ‘если накопленное время процесса > 1 час И Я не родительский процесс, перезапустите меня.
Так что я понимаю, что ответ не использует monit, но он работает. ps-watcher легковесен и прост в настройке, поэтому нет ничего плохого в том, чтобы запускать его дополнительно к вашей настройке monit.
Monit может это делать начиная с версии 5.4:
if uptime > 3 days then restart
Смотрите: файл CHANGES проекта
Вы можете встроить это в monit как оператор exec.
if [[ "$(uname)" = "Linux" ]];then killall --older-than 2m someprocessname;fi
Ответ или решение
Чтобы реализовать задачу контроля за процессами без использования PID-файлов в Monit, необходимо использовать комбинацию правил Monit и встроенных скриптов Linux. Вы уже упомянули, что вам нужно убивать процессы по имени, которые работают дольше определенного времени (например, 2 минуты). В Monit существует несколько способов достичь этой цели.
Шаг 1: Создание правила для Monit
Сначала нужно настроить Monit для отслеживания процесса. Для этого вы можете использовать команду exec
, которая позволит вам выполнить кастомный скрипт для проверки состояния процессов.
Пример конфигурации Monit может выглядеть следующим образом:
check process myprocessname
matching "myprocessname"
start program = "/etc/init.d/myprocessname start"
stop program = "/usr/bin/killall myprocessname"
if status != 0 then exec "/usr/local/bin/check_and_kill.sh myprocessname 120"
Шаг 2: Создание скрипта check_and_kill.sh
Создайте файл скрипта, который будет проверять запущенные процессы и убивать их, если они работают дольше 2 минут. Например, скрипт может выглядеть следующим образом:
#!/bin/bash
PROCESS_NAME=$1
THRESHOLD_SECONDS=$2
CURRENT_TIME=$(date +%s)
# Получаем список процессов с указанием времени работы
ps -eo pid,etimes,cmd | grep $PROCESS_NAME | grep -v grep | while read PID ETIMES CMD; do
# Конвертируем время в секунды
if [[ $ETIMES == *-* ]]; then
# Формат: 1-02:30:00
TIME_IN_SECONDS=$(echo "$ETIMES" | awk -F'[-:]' '{ printf("%d", ($1 * 86400) + ($2 * 3600) + ($3 * 60) + $4) }')
else
# Формат: 02:30:00
TIME_IN_SECONDS=$(echo "$ETIMES" | awk -F '[:]' '{ printf("%d", ($1 * 3600) + ($2 * 60) + $3) }')
fi
# Убиваем процесс, если он работает дольше порогового значения
if [ $TIME_IN_SECONDS -gt $THRESHOLD_SECONDS ]; then
kill -TERM $PID
fi
done
Шаг 3: Настройка прав доступа
Не забудьте дать права на выполнение вашему скрипту:
chmod +x /usr/local/bin/check_and_kill.sh
Шаг 4: Проверка и перезапуск Monit
После настройки конфигурации и скрипта, убедитесь, что Monit работает корректно:
monit reload
monit status
Заключение
Данная настройка позволит автоматически контролировать запущенные процессы с заданным именем и завершать их, если они работают дольше указанного времени. Не забывайте следить за журналами Monit для диагностики и корректности работы настроек.
Использование Monit в комбинации с скриптами позволяет легко адаптировать мониторинг под ваши специфические требования и избегать долгих процессов, занимающих ресурсы системы.