Скрипт мониторинга увеличения нагрузки на сервер load averge c оповещением по email hugin.sh

Однажды в студёную зимнюю пору один из продакшн серверов стал вести себя, мягко говоря, странно. Простейшие операции типа aptitude update и freshclam стали занимать до 5 минут времени и вызывать повышения load average до 5.0.

Тревожным сигналом стало и увеличение количества рабочих процессов mysql до 30-40 (с 1-2 инстансов майскл в нормальном режиме), а также появление в slow query log запросов с временем выполнения в 5 минут! При этом даже без кеширования нормальное выполнение такого запроса происходит за 0.04 секунды максимум..

Чтобы диагностировать источник проблем были предприняты попытки найти и внедрить систему оповещений по электронной почте. Использующийся на сервере munin достаточной детализированности информации не обеспечивал.

За основу был взят скрипт nixCraft project, так как он уже обладал базовым функционалом – умел определять load average (la) и сравнивать его с граничным значением, при пересечении которого направлять электронное письмо администратору.

Оригинальный скрипт, конечно же, оказался неработоспособен, потому что его съел хитропопый парсер, поэтому пришлось долго выяснять в чём причина неработоспособности и некоторые вещи переписать с нуля.

Возможности

Итак, скрипт hugin.sh позволяет

  • Посылать email-оповещение при пересечении системой значения load average, указанного администратором
  • Указывать в отчёте информацию о свободном месте на дисках
  • Указывать в отчёте информацию об iowait системы
  • Указывать в отчёте информацию об интенсивности сетефого трафика в килобайтах и пакетах
  • Указывать в отчёте 5 самых активных потребителей ресурсов процессора
  • Указывать в отчёте 5 самых активных потребителей оперативной памяти
  • Указывать в отчёте количество активных соединений к порту 80
  • Указывать в отчёте количество открытых дескрипторов файлов веб-сервером nginx
  • Указывать в отчёте количество открытых дескрипторов файлов базой данных mysql
  • Указывать в отчёте открытые сервером порты с указанием процессов, которых их слушают
  • Указывать в отчёте подробный список обрабатываемых mysql запросов в данный момент (processlist)
  • Указывать в отчёте вывод top для анализа вручную

Исходный код

Собственно сам скрипт:

#!/bin/bash
# 
# hugin.sh is simple bash script to notify admin by email if load crossed certain limit
# version 1.2
#
# Copyright (C) 2005 nixCraft project
# Copyright (C) 2012 farmal.in
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
# Set up limit below
NOTIFY="4.0"
 
# admin user email id
EMAIL="admins"
 
# Subject for email
SUBJECT="Alert $(hostname) load average"
 
# -----------------------------------------------------------------
# Os Specifc tweaks do not change anything below ;)
OS="$(uname)"
TRUE="1"
if [ "$OS" == "FreeBSD" ]; then
        TEMPFILE="$(mktemp /tmp/$(basename $0).tmp.XXX)"
        FTEXT='load averages:'
elif [ "$OS" == "Linux" ]; then
        TEMPFILE="$(mktemp)"
        FTEXT='load average:'
fi
 
# get first 5 min load
F5M="$(uptime | awk -F "$FTEXT" '{ print $2 }' | cut -d, -f1 | sed 's/ //g')"
# 10 min
F10M="$(uptime | awk -F "$FTEXT" '{ print $2 }' | cut -d, -f2 | sed 's/ //g')"
# 15 min
F15M="$(uptime | awk -F "$FTEXT" '{ print $2 }' | cut -d, -f3 | sed 's/ //g')"
 
# mail message
# keep it short coz we may send it to page or as an short message (SMS)
echo "Load average Crossed allowed limit $NOTIFY (is now $F15M)." >> $TEMPFILE
echo "Hostname: $(hostname)" >> $TEMPFILE
echo "Local Date & Time : $(date)" >> $TEMPFILE
 
# Look if it crossed limit
# compare it with last 15 min load average
RESULT=$(echo "$F15M > $NOTIFY" | bc)
 
# if so send an email
if [ "$RESULT" == "$TRUE" ]; then
        echo "----------------FREE-----------------------" >> $TEMPFILE
        free -mt >> $TEMPFILE
        echo "----------------IOSTAT---------------------" >> $TEMPFILE
        # input/output statistics to monitor wheather problem is in NIC, RAM or HDD
        iostat >> $TEMPFILE
        echo "---------------NETWORK---------------------" >> $TEMPFILE
        # display network statistics (transfer rates in pakets and kilobytes)
        sar -n DEV 1 3 >> $TEMPFILE
        echo "---------------CPU-------------------------" >> $TEMPFILE
        # display the top CPU consumers
        ps aux | sort -nk +3 | tail -5 >> $TEMPFILE
        echo "---------------RAM-------------------------" >> $TEMPFILE
        # display the top memory consumers
        ps aux | sort -nk +4 | tail -5 >> $TEMPFILE
        echo "----------NUMBER of 80 port connections----" >> $TEMPFILE
        # how many are there connections to 80 port
        netstat -an |grep :80 |wc -l >> $TEMPFILE
        echo "---------------NGINX OPEN FILES------------" >> $TEMPFILE
        ulimit -n >> $TEMPFILE
        for pid in `pidof nginx`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done >> $TEMPFILE
        echo "---------------NETSTAT---------------------" >> $TEMPFILE
        # display open ports (server only)
        netstat -lnpt >> $TEMPFILE
        echo "---------------MYSQL OPEN FILES------------" >> $TEMPFILE
        ulimit -n >> $TEMPFILE
        for pid in `pidof mysqld`; do echo "$(< /proc/$pid/cmdline)"; egrep 'files|Limit' /proc/$pid/limits; echo "Currently open files: $(ls -1 /proc/$pid/fd | wc -l)"; echo; done >> $TEMPFILE
        echo "---------------MYSQL-PROCESSLIST-----------" >> $TEMPFILE
        mysqladmin -v processlist extended-status -u root -pMYSQLPASSWORD >> $TEMPFILE
        echo "---------------TOP-------------------------" >> $TEMPFILE
        # full top listing
        top -b -n1 >> $TEMPFILE
        mail -s "$SUBJECT" "$EMAIL" < $TEMPFILE
fi
 
# remove file
rm -f $TEMPFILE

Установка

cd /usr/local
wget http://farmal.in/scripts/hugin.sh
chmod +x hugin.sh

Заносим скрипт в планировщик крон, чтобы он выполнялся каждые 10 минут с высоким приоритетом:

crontab -e
2,12,22,32,42,52  * * * * nice -n -5 /usr/local/hugin.sh

Добавляем элиасы для sendmail:

vim /etc/aliases
admins: root, ваш@email.com

В самом скрипте заменяем MYSQLPASSWORD на пароль root’а mysql, либо создаём корректный .my.cnf с эти данными в домашней папке пользователя, от имени которого будет запускаться скрипт.

Системные требования

Для работы hugin.sh кроме стандартных программ понадобятся:

  • bc
  • sar
  • iowait

Мне скрипт помог определить, что проблема была в винчестере сервера, отчего происходили затыки (mysql активно работает с диском). Надеюсь, он поможет и вам! Если кто-нибудь доработает под свои нужды – буду рад опубликовать исправленную и доработанную версию.

3 thoughts on “Скрипт мониторинга увеличения нагрузки на сервер load averge c оповещением по email hugin.sh

  1. major12

    Зачем писать про FreeBSD
    if [ “$OS” == “FreeBSD” ]; then
    и потом использовать
    free
    pidof
    /proc/$pid
    і т.д.

    Лучше сразу
    if [ “$OS” == “FreeBSD” ]; then
    echo “This OS is not supported”
    exit 1
    fi

    :)

    Reply
    1. anonymous Post author

      да, возможно так и стоит сделать :) это как раз та часть, которая осталась от первоначальной версии скрипта, а с БСД семейством я знаком только по книжкам в детстве из которых вынес насколько и почему бсд круче линуксов.. а на практике приходится работать с debian и centos :)

      Reply
  2. вут

    Ловите:

    hugin.sh: 35: [: Linux: unexpected operator
    hugin.sh: 38: [: Linux: unexpected operator
    hugin.sh: 52: hugin.sh: cannot create : Directory nonexistent
    hugin.sh: 53: hugin.sh: cannot create : Directory nonexistent
    hugin.sh: 54: hugin.sh: cannot create : Directory nonexistent
    hugin.sh: 61: [: 1: unexpected operator

    Reply

Leave a Reply to major12 Cancel reply

Your email address will not be published. Required fields are marked *