bash скрипт слежения за зависшими процессами
На одном из серверов был перенесен веб-сайт, из-за которого периодически подвисал дочерний httpd (apache2) процесс. Необходимо было временное решение на время отладки кода и решения проблемы на уровне сайта, которое отслеживало бы зависшие процессы.
Было решено написать bash скрипт, который отслеживает время жизни процесса, затраченное время процессора (CPU time) и нагрузку на процессов. В случае, если все 3 параметра достигают определенное пиковое конфигурируемое значение — процесс убивается.
Использование
1 2 3 4 | ./checker.sh param1 param2 #Пример: ./checker.sh httpd www-data |
param1 — поисковая строка для вывода команды ps
param2 — опционально, вторая поисковая строка для уточнения результатов
Код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | #!/bin/bash cpuLimit=5000 # cpu * 100 timeLimit=600 # process time limit in seconds cpuTimelimit=400 # process cpu time limit in seconds killSignal="HUP" # kill signal debug=0 # 1 - not kill | 0 - kill verbose=1 # 1 - print info | 1 - without output ##### END CONFIG ##### declare -i cpuLimit declare -i timeLimit declare -i cpuTimelimit declare -i debug declare -i verbose declare -A pidTime declare -A pidCpuTime declare -A pidCpu declare -A pidUser declare -A pidApp appName=$1 #"httpd" appName=${appName:=httpd} grep2=$2 #"plsm.ru" grep2=${grep2:=$appName} if [[ -z $grep2 ]];then grep2=$appName fi { declare $( ps -eo pid,user,pcpu,etimes,comm | grep $appName | grep $grep2 | grep -v grep | sed -e 's/^[[:space:]]*//' | awk {'print "pidCpu["$1 "]=" $3*100'} ) declare $( ps -eo pid,cputime,user,pcpu,etimes,comm | grep $appName | grep $grep2 | grep -v grep | sed -e 's/^[[:space:]]*//' | awk -F'[: ]+' '/:/ {t=$4+60*($3+60*$2); print "pidCpuTime["$1 "]="t}' ) declare $( ps -eo pid,user,pcpu,etimes,comm | grep $appName | grep $grep2 | grep -v grep | sed -e 's/^[[:space:]]*//' | awk {'print "pidTime["$1 "]=" $4'} ) declare $( ps -eo pid,user,pcpu,etimes,comm | grep $appName | grep $grep2 | grep -v grep | sed -e 's/^[[:space:]]*//' | awk {'print "pidUser["$1 "]=" $2'} ) declare $( ps -eo pid,user,pcpu,etimes,comm | grep $appName | grep $grep2 | grep -v grep | sed -e 's/^[[:space:]]*//' | awk {'print "pidApp["$1 "]=" $5'} ) } &> /dev/null arrSize=${#pidCpu[@]} if [[ $arrSize -eq 0 ]];then if [[ $verbose -eq 1 ]];then echo "Required processes are not found" fi else for i in "${!pidCpu[@]}";do if [[ $verbose -eq 1 ]];then echo "----------------" echo "pid: $i" echo "user: ${pidUser[$i]}" echo "cpu: ${pidCpu[$i]}" echo "time: ${pidTime[$i]}" echo "cpu time: ${pidCpuTime[$i]}" echo "app: ${pidApp[$i]}" if [[ ${pidCpu[$i]} -gt $cpuLimit ]] ;then echo "CPU WARNING" fi if [[ ${pidTime[$i]} -gt $timeLimit ]];then echo "TIME WARNING" fi if [[ ${pidCpuTime[$i]} -gt $cpuTimelimit ]];then echo "CPU TIME WARNING" fi fi if [[ ${pidCpu[$i]} -gt $cpuLimit ]] && [[ ${pidTime[$i]} -gt $timeLimit ]] && [[ ${pidCpuTime[$i]} -gt $cpuTimelimit ]];then if [[ $debug -ne 1 ]];then kill -$killSignal $i if [[ $verbose -eq 1 ]];then echo "PID $i KILLED. Result code $?" fi fi fi done fi exit 0; |
Скрипт имеет ряд параметров:
- cpuLimit=5000 — задает лимит потребления CPU умноженного на 100 (5000 — потребление 50% процессора)
- timeLimit=600 — задает лимит времени работы процесса в секундах
- cpuTimeLimit=400 — задает лимит потребления процессорного времени
- killSignal — сигнал, который передается утилите kill. Я выставил HUP, что делает безопасное завершение процесса. Если процесс остается, то можно попробовать KILL, но это чревато проблемами
- verbose=1 — выводить информация о найденных процессах или нет
- debug=1 — 1 — не убивать процесс (включив verbose — можно протестировать), 0 — убивать процесс
Скрипт анализирует вывод команды ps с указанием специальных флагов. Далее идет двойная фильтрация вывода. Двойная фильтрация сделана из-за специфики сервера — стоит httpd (apache2) с модулем mpm-itk, который дает возможность запускать httpd сервер от имени отдельных пользователей, следовательно, необходимо было отслеживать процессы только одного сайта/пользователя. В итоге, команда
Решение протестировано на ОС CentOS Linux release 7.2.1511 (Core)