monit: проверить процесс без файла pid

Вопрос или проблема

Я ищу способ убить все процессы с заданным именем, которые работают более 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 в комбинации с скриптами позволяет легко адаптировать мониторинг под ваши специфические требования и избегать долгих процессов, занимающих ресурсы системы.

Оцените материал
Добавить комментарий

Капча загружается...