Поиск на сайте: Расширенный поиск


Новые программы oszone.net Читать ленту новостей RSS
CheckBootSpeed - это диагностический пакет на основе скриптов PowerShell, создающий отчет о скорости загрузки Windows 7 ...
Вы когда-нибудь хотели создать установочный диск Windows, который бы автоматически установил систему, не задавая вопросо...
Если после установки Windows XP у вас перестала загружаться Windows Vista или Windows 7, вам необходимо восстановить заг...
Программа подготовки документов и ведения учетных и отчетных данных по командировкам. Используются формы, утвержденные п...
Red Button – это мощная утилита для оптимизации и очистки всех актуальных клиентских версий операционной системы Windows...
OSzone.net Видео Unix Интернет Apache Разработка скрипта для протоколирования событий и мониторинга MySQL и Apache RSS

Разработка скрипта для протоколирования событий и мониторинга MySQL и Apache

Текущий рейтинг: 3.67 (проголосовало 3)
 Посетителей: 1999 | Просмотров: 2510 (сегодня 0)  Шрифт: - +
 Скрипт протоколирования событий на shell.

   Содержание:
     * Зачем это нужно;
     * Формулируем основные требования;
     * Интерфейс и расположение;
     * Переменные скрипта;
     * Отправка e-mail;
     * Запись в файл протокола и его ротация;
     * Что получилось;
     * Просмотр записей в браузере;
     * Заключение.

Зачем это нужно


   Предположим, что у нас есть UNIX-box или целая ферма серверов,
   возможно, есть набор сервисов у хостинг-провайдера или удаленные
   серверы. Время от времени состояние серверов и демонов изменяется:
   свободное пространство какого-либо раздела может исчерпаться, вслед за
   этим тихо <<валится>> squid, может <<упасть>> web-сервер или
   отключиться репликация баз данных. Предположим, что наступление всех
   критических событий контролируется. Неважно, какими средствами, хотя
   бы и скриптами из cron. Возникает вопрос: как оперативно оповестить
   системного администратора о том или ином событии, не заставляя его
   денно и нощно читать логи?


Формулируем основные требования

   Некоторого представления о скриптинге на shell и настроенного MTA
   (sendmail) оказывается вполне достаточно, чтобы разработать несложную
   и вместе с тем надежную и гибкую систему протоколирования. Итак,
   исходные требования к ней:

     * простота и гибкость - по-моему, проще shell нет ничего и,
       вооружившись руководствами, можно легко добавить скрипту
       дополнительные возможности или же заставить его работать
       по-другому;
     * оперативность оповещения - система будет отправлять почтовые
       сообщения на e-mail системного администратора;
     * надежность - дополнительный протокол, в который не только
       дублируются сами критические события, но и результаты отправки
       почтовых сообщений;
     * безопасность - дело сисадмина закрывать <<дыры>>, но никак не
       обратное;
     * бережное отношение к дисковому пространству - весьма неплохо
       хранить протоколы как можно дольше, чтобы при этом они <<весили>>
       как можно меньше.


Интерфейс и расположение

   Сначала определим местоположение скрипта и директории протоколов нашей
   системы. На мой взгляд, резонно создать
   /root/scripts/ с режимом 500 (r-x) и владельцем root:wheel и
   расположить скрипт там с такими же правами, назовем его
   report.error.sh. К тому же, наверняка, контроль событий ведется от
   имени rootа и у вызывающих программ хватит прав вызывать скрипт.
   Протоколы будут находиться в /var/log/ и называться error.reports.log.
   Такое расположение оптимально, по сравнению, например, с /usr/local/,
   особенно, если в операционной системе есть аккаунты "живых"
   пользователей.

   Положим порядок и значение передаваемых скрипту report.error.sh
   параметров:

    1. имя вызывающей программы;
    2. процедура или проверяемое событие;
    3. код ошибки или завершения (иногда здорово помогает);
    4. поток вывода и/или ошибок вызывающей программы.


Переменные скрипта

   Начнем c инициализации переменных. Иногда, удобно определить даже то,
   что только гипотетически может измениться как переменную и вынести ее
   наверх. Удобство проявляется в громоздком скрипте, который до этого
   был забыт на год-два:

        #!/bin/sh

        recipient=admin\@host.ru
        ccrecipient=admin_ cell_phone\@nwgsm.ru
        log_file=/var/log/error.reports.log
        max_log_file_size=500000 # in bytes
        date=`date`


   Получатель email в recipient, копия направляется ccrecipient,
   <<собака>> в адресах обязательно экранируется "\". Из соображений
   повышения надежности доставки, хост у recipient лучше выбрать с
   наименьшей вероятностью того, что он будет недоступен.
   Сверхоперативное оповещение можно организовать элементарно,
   зарегистрировав почтовый ящик у оператора сотовой связи и отправляя
   копии на него. У <<Мегафона>> такая услуга есть, доставка практически
   моментальная. Имя файла протокола - log_file, max_log_file_size -
   максимальный размер в байтах, при достижении которого будет
   производиться ротация. В переменную date заносится текущее время и
   дата в формате и локали rootа:

        Tue Oct 14 15:31:16 MSD 2003


Отправка e-mail

   Первым делом, пытаемся отправить почтовое сообщение:

        mail -s "Сообщение об ошибке" -c $ccrecipient $recipient <<!
        Время: $date
        Скрипт: $1
        Действие: $2
        Дополнительная информация:
        Код ошибки: $3
        Поток вывода ошибочной команды:
        $4
        !


   Для единственного получателя вызов mail немного иной:

        mail -s "Сообщение об ошибке" $recipient <<!


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

   По коду возврата mail проверяем, ушла ли почта. В условном операторе
   можно расположить и другой полезный код, например, реанимирующий
   sendmail:

        if [ $? -ne 0 ]
               then not_string=" не"
        fi


Запись в файл протокола и его ротация

   Затем, записываем переданные параметры и отчет отправки в наш
   лог-файл. Разделителями полей могут служить любые символы, не только
   табуляции. Все зависит от того, кто будет читать протоколы: человек,
   парсер или все понемногу. По моему мнению, для последней ситуации,
   один символ табуляции как разделитель полей - компромисс: MS Excel
   будет счастлив при импорте, с текстовой консоли лог вполне читаем и
   парсер на Perl написать несложно:

        echo "$date        $1        $2        $3        $4        \
        Уведомление $not_string отправлено ${recipient}, \
        копия ${ccrecipient}." >> $log_file


   Немного белой магии. Если размер файла протокола стал больше
   max_log_file_size, его нужно ротировать, а ротированный - сжать.

   Выясняем размер протокола в байтах и сравниваем с предельным:

        log_file_size=`wc -c $log_file | awk `{print $1}``
        if [ $log_file_size -gt $max_log_file_size ]


   При положительном результате, проверяем наличие в /var/log/ файлов
   error.reports.log.0.gz, потом error.reports.log.1.gz,
   error.reports.log.2.gz и так далее. Это суть ротированные и сжатые до
   этого логи. Последовательный перебор идет до тех пор, пока не найдется
   последний файл или <<окно>> между ними (очевидно, что заглядывать в
   /var/log/ нужно чаще, чем i станет больше MAXINT):

            then
                i=0
                while [ -f $log_file.$i.gz ]
                do
                   i=`expr $i + 1`
                done


   Ротируем, сжимаем и оставляем запись об этом в следующем протоколе:

                mv $log_file $log_file.$i
                gzip $log_file.$i
                echo "`date`: Ротация логов. \
                Предыдущий сохранен с номером $i" >> $log_file
            fi


   Что получилось

   Скрипт целиком выглядит так:

        #!/bin/sh

        recipient=admin\@host.ru
        ccrecipient=admin_ cell_phone\@nwgsm.ru
        log_file=/var/log/error.reports.log
        max_log_file_size=500000 # in bytes
        date=`date`

        ### send mail ###
        mail -s "Сообщение об ошибке" -c $ccrecipient $recipient <<!
        Время: $date
        Скрипт: $1
        Действие: $2
        Дополнительная информация:
                Код ошибки: $3
                Поток вывода ошибочной команды:
                $4
        !

        ### test if mail is sent ###
        if [ $? -ne 0 ]
               then not_string=" не"
        fi

        ### log into file ###
        echo "$date        $1        $2        $3        $4        \
        Уведомление $not_string отправлено ${recipient}, \
        копия ${ccrecipient}." >> $log_file

        ### turn over log file if needed ###
        log_file_size=`wc -c $log_file | awk `{print $1}``
        if [ $log_file_size -gt $max_log_file_size ]
        then
                i=0
                while [ -f $log_file.$i.gz ]
                do
                   i=`expr $i + 1`
                done
                mv $log_file $log_file.$i
                gzip $log_file.$i
                echo "`date`: Ротация логов. \
        Предыдущий сохранен с номером $i" >> $log_file
        fi


   Теперь его можно вызывать из других скриптов или программ мониторинга.
   Вызов из скрипта /root/scripts/monitor.something.sh, запущенного от
   имени rootа делается примерно так:

        #!/bin/sh
        ...
        some_parameters="process"
        ...
        result=`/usr/local/bin/some_program -$some_parameters 2>&1`
        result_code=$?
        if [ $result_code -ne 0 ]
        then
               /root/scripts/report.error.sh $0 "нет ответа \
        от $some_parameters в течение 1 сек." $result_code "$result"
        fi
        ...


   В качестве уведомления на адреса admin@host.ru и admin_
   cell_phone@nwgsm.ru приходит письмо:

        From: Charlie Root
        To: admin@host.ru
        Subject: Сообщение об ошибке


        Время: Tue Oct 14 15:31:16 MSD 2003
        Скрипт: /root/scripts/monitor.something.sh
        Действие: Нет ответа от process в течение 1 сек.
        Дополнительная информация:
                Код ошибки: 1
                Поток вывода ошибочной команды:
                Can`t connect to server (Operation timed out)


Просмотр записей в браузере

   Можно пойти дальше - дополнить нашу систему протоколирования несложным
   парсером для просмотра протоколов с помощью браузера. Для этого
   подойдет web-сервер apache, у которого есть настроенная на
   аутентифицированный доступ (<<закрытая паролем>>, как говорят в
   народе) директория cgi-bin. Вот [30]вполне работоспособный пример
   скрипта парсера на Perl, который помещается в эту самую директорию с
   режимом 500 (r-x) и владельцем www:www (или тем, который прописан в
   конфигурации web-сервера):

        #!/usr/bin/perl

        my $logfile="/var/log/error.reports.log";

        print "Content-type:text/html\n\n";
        print "<html><title> Статистика ошибок</title>\n";
        print "<table border=1>\n";
        print "<td>дата</td><td>время</td><td>скрипт</td>
        <td>действие/описание ошибки</td><td>код ошибки</td>
        <td>поток вывода</td><td>получатель уведомления</td>\n";

        open(LOGHANDLE,"<$logfile");
        flock(LOGHANDLE,2);
        readline(*LOGHANDLE);
        while(my $stat_line=readline(*LOGHANDLE))
        {
                my @stat_strings=split(/\t/,$stat_line);
                if ($stat_strings[0]=~s/(\d\d:\d\d:\d\d)//)
                {
                        print "</td><tr><td>$stat_strings[0]</td>\n";
                        print "<td>$1</td>\n";
                        print "<td>$stat_strings[1]</td>\n";
                        print "<td>$stat_strings[2]</td>\n";
                        print "<td>$stat_strings[3]</td>\n";
                        print "<td>$stat_strings[4]\n";
                }
                else
                {
                        print "$stat_line<br>\n";
                }
                if ($stat_line=~/Уведомление\s+отправлено\s+(\S+)\./)
                {
                        print "</td><td>$1</td>\n";
                }

        }
        flock(LOGHANDLE,8);
        close(LOGHANDLE);
        print "</td></table>\n";
        print "</body></html>\n";

        exit 0;


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


Заключение

   Основная цель данной статьи заключается в том, чтобы создать фундамент
   для размышлений и дальнейшего развития и совершенствования скрипта,
   поделиться накопленным опытом, но никак не дать готовые решения для
   бездумного, слепого копирования или же научить принципам
   программирования. Как говаривал агент Малдер о своем автомобиле:
   <<Руль где-то рядом>>.



Скрипт мониторинга web-сервера Содержание: * Жизненные ситуации; * Формулируем основные требования; * Расположение скрипта и взаимодействие с другим ПО; * Приступаем к разработке; * Собираем все вместе; * Запуск скрипта из cron; * Подведение итогов; * Заключение. Жизненные ситуации
Иногда требуется уверенность в том, что web-сервер доступен для клиентов. Конфигурации web-серверов могут быть очень и очень разные, да и всегда есть место человеческому фактору - все мы время от времени ошибаемся, забываем что-то. В моей практике частенько встречаются подобные вещи, особенно это касается виртуального хостинга и программирования динамических сайтов - отладили на локальном сервере, <<залили>> к хостинг-провайдеру - не работает. Другая ситуация: старались люди, программировали - обновил администратор хостинг-провайдера версию PHP, а в ней какая-то команда или код ее возврата поменялся; результат - сайт <<лег>>. В общем, ситуаций, когда нужно периодически проверять работоспособность web-сервера, много, и в этой статье автор поделился опытом в решении этой проблемы. Возможно, кому-то проще решить проблему <<в лоб>> - ps ax | grep httpd для локального хоста или специально нанять сотрудника и усадить его за Internet Explorer. Формулируем основные требования
Дабы не изобретать велосипед (хотя бы в этот раз), скрипт мониторинга будет пользоваться для оповещения и протоколирования другим скриптом /root/scripts/report.error.sh, разработка которого детально описана в статье <<Скрипт протоколирования событий на shell>>. Итак, сформулируем требования к скрипту мониторинга: * простота - язык скриптинга shell; * генерация минимального трафика - платить за лишний трафик ни к чему; * надежность оповещения - скрипт будет вызывать протоколирующий и отсылающий сообщение на e-mail скрипт; * оперативность оповещения - разумный компромисс между объемом генерируемого трафика и частотой запуска скрипта из cron; * безопасность - куда ж без нее; * возможность модернизации - допустим, в будущем неплохо было бы вести статистику времени ответа сервера. Расположение скрипта и взаимодействие с другим ПО Определим местоположение скрипта. Доводы в пользу /root/scripts/ с режимом 500 (r-x) и владельцем root:wheel приведены в статье <<Скрипт протоколирования событий на shell>>, поэтому не буду повторяться. Скрипт мониторинга, назовем его monitor.websites.sh, будет иметь режим 500 (r-x) и владельца root:wheel. Этим обеспечиваются требования информационной безопасности. В принципе, можно ограничиться банальным запуском telnet по 80-му порту. Есть более интересный, к тому же отвечающий требованиям расширяемости, вариант - малюсенькая, но очень функциональная программа echoping, разработанная Stephane Bortzmeyer (bortz@users.sourceforge.net, bortzmeyer@nic.fr). В коллекции портов FreeBSD она находится в /usr/ports/net/echoping, в исходниках ее можно взять с ftp://ftp.internatif.org/pub/unix/echoping . Кроме очень толкового man и readme, есть страничка echoping на http://echoping.sourceforge.net/. Размеры архива небольшие, поэтому взять исходники или инсталлировать echoping из портов вполне реально, даже с медленным модемом. Инсталляция echoping из портов (две команды с консоли - вот в чем вся прелесть портов): server# cd /usr/ports/net/echoping server# make install Инсталляция из исходников чуть сложнее: server# tar -xzf echoping-5.1.0.tar.gz server# cd echoping-5.1.0 server# ./configure server# make server# make install Советую почитать документацию и посетить [34]домашнюю страничку echoping, оттуда можно почерпнуть много весьма полезного не только по теме, но и для общего развития, так сказать - областей применения для этой программы не счесть. Приступаем к разработке Функции скрипта мониторинга сводятся к вызову echoping, обработке информации по завершению и вызову скрипта протоколирования, если что-то не в порядке. Тестироваться будет хост http://remote.host.ru/: #!/bin/sh ping_host="remote.host.ru" Следующий этап - решить, что же именно нужно тестировать: доступность хоста вообще или же доступность определенного URL. Чтобы тестировать доступность хоста создадим небольшой текстовый файл echoping.answer.txt, с произвольным содержанием. Размещение его на web-сервере роли не играет, лишь бы echoping смог его открывать (это легко проверить с помощью браузера). Файл такого содержания имеет размер всего 44 байта: This is the sample answer file for echoping. По логике вещей, доступность хоста - есть доступность URL, например, index.html на нем. В чем разница? В том, что порядок размера того же index.html - десятки килобайт, а echoping.answer.txt - десятки байт. Получается немалый выигрыш в трафике: если требуется знать всего лишь доступность хоста, незачем брать большой файл: ping_file="/echoping.answer.txt" Чтобы протестировать доступность страницы, переменной ping_file просто присваивается соответствующее значение: ping_file="/some_dir/some-page.html" Вызов echoping с сохранением кода завершения и потока вывода будет выглядеть так: result=`/usr/local/bin/echoping -h $ping_file $ping_host 2>&1` result_code=$? У некоторых хостинг-провайдеров виртуальные хосты сконфигурированы так, что echoping может работать только со следующей командной строкой: result=`/usr/local/bin/echoping -h http://${ping_host}${ping_file} \ $ping_host 2>&1` По документации, код возврата не нулевой, если что-то не в порядке. Следующий фрагмент кода запускает в этом случае скрипт /root/scripts/report.error.sh, который отсылает уведомление с подробностями (потоком вывода echoping) по e-mail и оставляет запись в протоколе: if [ $result_code -ne 0 ] then /root/scripts/report.error.sh $0 "\ Нет ответа от $ping_host в течение 1 сек." $result_code "$result" fi Собираем все вместе Привожу этот простой [36]скрипт целиком: #!/bin/sh ping_host="remote.host.ru" ping_file="/echoping.answer.txt" result=`/usr/local/bin/echoping -h $ping_file $ping_host 2>&1` result_code=$? if [ $result_code -ne 0 ] then /root/scripts/report.error.sh $0 "\ Нет ответа от $ping_host в течение 1 сек." $result_code "$result" fi Запуск скрипта из cron Осталось только сконфигурировать cron, чтобы скрипт действительно занимался мониторингом. Существует одна тонкость: в частоте запуска скрипта следует соблюсти баланс между объемами трафика (не стоит ориентироваться на размеры echoping.answer.txt, HTTP-сессия сама по себе генерирует трафик) и достоверностью информации (вероятность того, что хост может быть недоступен, увеличивается со временем после очередного запуска echoping). Задания, выполняемые от имени root перечисляются в /var/cron/tabs/root. Если его нет, можно создать файл в текстовом редакторе или доверить создание непосредственно самому crontab: server# crontab -e -u root Строка, конфигурирующая cron для запуска /root/scripts/monitor.websites.sh каждые 30 минут: */30 * * * * /root/scripts/monitor.websites.sh Советую проследить режим файла заданий - 600 (rw-) с владельцем root:wheel и наличие в нем переменных окружения: SHELL=/bin/sh PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin HOME=/var/log После внесения изменений нужно, чтобы cron перечитал список заданий: server# crontab -u root /var/cron/tabs/root В /var/log/cron появится запись: Mar 30 11:11:11 server crontab[75680] REPLACE (root) Подведение итогов Все. С этого момента в своих протоколах /root/scripts/report.error.sh будет писать: Tue Mar 30 11:11:11 MSD 2004 \ /root/scripts/monitor.websites.sh \ нет ответа от remote.host.ru в течение 1 сек. 1 \ Can`t connect to server (Operation timed out) \ Уведомление отправлено admin@host.ru, \ копия admin_cell_phone@nwgsm.ru А на e-mail, указанные в скрипте будут приходить письма: Date: Tue, 30 Mar 2003 11:11:11 +0300 (MSK) From: Charlie Root <root> To: admin@ host.ru Subject: Сообщение об ошибке Время: Tue Mar 30 11:11:11 MSD 2004 Скрипт: /root/scripts/monitor.websites.sh Действие: нет ответа от remote.host.ru в течение 1 сек. Дополнительная информация: Код ошибки: 1 Поток вывода ошибочной команды: Can`t connect to server (Operation timed out) Например, такое письмо будет свидетельствовать о том, что на компьютере, где работает echoping проблемы с DNS: Date: Tue, 30 Mar 2003 11:11:11 +0300 (MSK) From: Charlie Root <root> To: admin@host.ru Subject: Сообщение об ошибке Время: Tue Mar 30 11:11:11 MSD 2004 Скрипт: /root/scripts/monitor.websites.sh Действие: нет ответа от remote.host.ru в течение 1 сек. Дополнительная информация: Код ошибки: 1 Поток вывода ошибочной команды: getaddrinfo error for host: remote.host.ru \ No address associated with hostname Изучив документацию к echoping, нетрудно заметить, что скрипт мониторинга может дополниться <<фичей>> мониторинга прокси-сервера, а применив awk можно вести статистику среднего времени отклика web-сервера. По-моему, звучит заманчиво. Кто-то, наоборот посчитает статью ерундой - отлично, те же самые функции реализуются скриптом на Perl socket-программированием, правда, по-любому, такой скрипт будет гораздо более объемным. Заключение Повторюсь, что целью данной статьи, как и других, впрочем, не было написание краткого руководства по программированию на shell. Было время - была конкретная проблема, но не было опыта ее решения. Проблема решена - появился опыт, значит, нужно им поделиться, дабы другие на те же грабли не наступали. В любом случае, буду признателен за конструктивную критику.
Скрипт мониторинга репликации MySQL на shell Содержание: * А в ответ - тишина...; * Основные требования и возможности; * Местоположение скрипта и аккаунт мониторинга; * Разработка скрипта. Проблема первая; * Разработка скрипта. Проблема вторая; * Доводим до совершенства; * Собираем все вместе; * Запуск скрипта из cron; * Подведение итогов; * Заключение. А в ответ - тишина... Поступив на работу в организацию, где тружусь на чье-то благо и по сей день, постепенно стало обнаруживаться, что хоть UNIX и беспрецедентно надежная операционная система, а приложения для нее все же могут давать сбои. Тогда и пришлось разрабатывать целую систему скриптов контроля за состоянием целого ряда демонов. Отдел программирования в то время занимался девелопингом весьма запутанной автоматизированной информационной системы средствами PHP и MySQL. Средством синхронизации была выбрана репликация баз данных того самого MySQL. Хорошо это или плохо - не время и не место обсуждать, но жить с этим приходится, и будет приходиться еще долго. Основная проблема состоит в том, что при обнаружении несоответствия или невозможности выполнить INSERT статус репликации тихо меняется на <<OFF>>. Обнаружить причину удается не сразу, учитывая сложность окружения (Apache, DNS, GD) и наличие <<глюков>> в скриптах PHP на этапе разработки. Основные требования и возможности Как и рассмотренный в статье <<Скрипт мониторинга web-сервера на shell>>, скрипт мониторинга репликации будет пользоваться для оповещения и протоколирования другим скриптом /root/scripts/report.error.sh, разработка которого детально описана в статье [31]<<Скрипт протоколирования событий на shell>>. Итак, сформулируем требования к скрипту мониторинга: * простота - язык скриптинга shell; * генерация минимального трафика - платить за лишний трафик ни к чему; * надежность оповещения - скрипт будет вызывать протоколирующий и отсылающий сообщение на e-mail скрипт; * оперативность оповещения - разумный компромисс между объемом генерируемого трафика и частотой запуска скрипта из cron; * полнота оповещения - скрипт должен оповещать не только об остановке репликации, но и о факте <<падения>> сервера; * безопасность - MySQL очень уязвим в связках и сам по себе; * возможность модернизации - в будущем возможна смена хостинг-провайдера, адресов или портов серверов. Местоположение скрипта и аккаунт мониторинга Определим местоположение скрипта. Доводы в пользу /root/scripts/ с режимом 500 (r-x) и владельцем root:wheel приведены в статье <<Скрипт протоколирования событий на shell>>, поэтому не буду повторяться. Скрипт мониторинга, назовем его monitor.mysql.sh, будет иметь режим 500 (r-x) и владельца root:wheel. Этим обеспечиваются требования информационной безопасности на уровне операционной системы. В составе MySQL поставляется широко известная пакетная утилита mysqladmin, которая и будет источником информации для скрипта. Соответственно, чтобы подсоединиться к серверу, необходим аккаунт пользователя. Для целей мониторинга вполне подойдет пользователь, назовем его repcontrol, с единственным правом USAGE, причем без права его передачи и длинным паролем. Резонным будет ограничить возможность соединения по хостам, если нет веских причин на обратное - мониторинг ведется только с одного хоста. Этим мы удовлетворим требования информационной безопасности по отношению к MySQL. На каждом контролируемом сервере от имени rootа отдадим: GRANT USAGE ON *.* TO `repcontrol`@`host.ru` IDENTIFIED BY `guessable`; Подробнее с добавлением аккаунтов пользователей MySQL можно ознакомиться на странице [36]5.5.3 Adding New User Accounts to MySQL. Теперь можно взглянуть на перечень параметров MySQL-сервера, которые поддаются мониторингу: server# mysqladmin -hhost.ru -P3306 -urepcontrol -pguessable extended-status +--------------------------+--------+ | Variable_name | Value | +--------------------------+--------+ | Aborted_clients | 0 | | Aborted_connects | 0 | | Bytes_received | 15949 | | Bytes_sent | 414411 | | Com_admin_commands | 63 | | Com_alter_table | 0 | | Com_analyze | 0 | | Com_backup_table | 0 | | Com_begin | 0 | | Com_change_db | 2 | | Com_change_master | 0 | | Com_check | 0 | | Com_commit | 0 | | Com_create_db | 0 | | Com_create_function | 0 | | Com_create_index | 0 | | Com_create_table | 0 | | Com_delete | 0 | | Com_drop_db | 0 | | Com_drop_function | 0 | | Com_drop_index | 0 | | Com_drop_table | 0 | | Com_flush | 0 | | Com_grant | 0 | | Com_insert | 0 | | Com_insert_select | 0 | | Com_kill | 0 | | Com_load | 0 | | Com_load_master_table | 0 | | Com_lock_tables | 0 | | Com_optimize | 0 | | Com_purge | 0 | | Com_rename_table | 0 | | Com_repair | 0 | | Com_replace | 0 | | Com_replace_select | 0 | | Com_reset | 0 | | Com_restore_table | 0 | | Com_revoke | 0 | | Com_rollback | 0 | | Com_select | 46 | | Com_set_option | 46 | | Com_show_binlogs | 0 | | Com_show_create | 46 | | Com_show_databases | 0 | | Com_show_fields | 46 | | Com_show_grants | 0 | | Com_show_keys | 0 | | Com_show_logs | 0 | | Com_show_master_status | 0 | | Com_show_open_tables | 0 | | Com_show_processlist | 0 | | Com_show_slave_status | 0 | | Com_show_status | 34 | | Com_show_innodb_status | 0 | | Com_show_tables | 2 | | Com_show_variables | 0 | | Com_slave_start | 0 | | Com_slave_stop | 0 | | Com_truncate | 0 | | Com_unlock_tables | 0 | | Com_update | 0 | | Connections | 101 | | Created_tmp_disk_tables | 0 | | Created_tmp_tables | 0 | | Created_tmp_files | 0 | | Delayed_insert_threads | 0 | | Delayed_writes | 0 | | Delayed_errors | 0 | | Flush_commands | 1 | | Handler_delete | 0 | | Handler_read_first | 8 | | Handler_read_key | 0 | | Handler_read_next | 0 | | Handler_read_prev | 0 | | Handler_read_rnd | 0 | | Handler_read_rnd_next | 4520 | | Handler_update | 0 | | Handler_write | 0 | | Key_blocks_used | 0 | | Key_read_requests | 0 | | Key_reads | 0 | | Key_write_requests | 0 | | Key_writes | 0 | | Max_used_connections | 1 | | Not_flushed_key_blocks | 0 | | Not_flushed_delayed_rows | 0 | | Open_tables | 46 | | Open_files | 97 | | Open_streams | 0 | | Opened_tables | 52 | | Questions | 320 | | Select_full_join | 0 | | Select_full_range_join | 0 | | Select_range | 0 | | Select_range_check | 0 | | Select_scan | 39 | | Slave_running | ON | | Slave_open_temp_tables | 0 | | Slow_launch_threads | 0 | | Slow_queries | 0 | | Sort_merge_passes | 0 | | Sort_range | 0 | | Sort_rows | 0 | | Sort_scan | 0 | | Table_locks_immediate | 51 | | Table_locks_waited | 0 | | Threads_cached | 0 | | Threads_created | 99 | | Threads_connected | 2 | | Threads_running | 2 | | Uptime | 228103 | +--------------------------+--------+ Первой переменной скрипта и будут реквизиты созданного аккаунта: mysql_user="-urepcontrol -pguessable" Разработка скрипта. Проблема первая В разработке скрипта мониторинга серверов MySQL есть две проблемы, по сути, решение которых и будет составлять код скрипта: первая - получить часть строки из таблицы напротив параметра Slave_running, вторая - серверов может быть несколько, и работать они могут на разных хостах и портах - избежать путаницы. Первая проблема весьма просто решается применением awk и grep. Сначала утилита mysqladmin соединяется с сервером и получает расширенную таблицу статусов, ее листинг приведен в конце предыдущего раздела: server# mysqladmin -hhost.ru -P3306 -urepcontrol -pguessable \ extended-status 2>&1 Затем из потока вывода с помощью grep можно получить интересующую строку: server# mysqladmin -hhost.ru -P3306 -urepcontrol -pguessable \ extended-status 2>&1 | grep Slave_running | Slave_running | ON | По умолчанию awk считает разделителями полей пробельные символы, следовательно, статус репликации - четвертый столбец: server# mysqladmin -hhost.ru -P3306 -urepcontrol -pguessable \ extended-status 2>&1 | grep Slave_running | awk `{print $4}` ON Так как поток диагностических сообщений перенаправляется в стандартный поток вывода, в случае возникновения каких-либо проблем, например, отсутствия связи с сервером, переменная result будет пустой. Условная конструкция будет выглядеть примерно так: result=`mysqladmin -hhost.ru -P3306 -urepcontrol -pguessable \ extended-status 2>&1 | grep Slave_running | awk `{print $4}`` case $result in ON) ;; OFF) /root/scripts/report.error.sh $0 "репликация на host.ru:3306 отключена" 0 "пусто";; *) /root/scripts/report.error.sh $0 "невозможно \ получить статус репликации на host.ru:3306 0 "пусто";; esac Недостаток подобной конструкции состоит в невозможности диагностики конкретной причины пустого (или отличного от <<ON>> и <<OFF>>) result. Существенным он может быть только в случае неустойчивого модемного соединения по плохому каналу в цепочке между хостом мониторинга и контролируемым хостом. По логике вещей, в любом другом случае, невозможность получить статус репликации говорит о том, что сервер <<лег>>. Разработка скрипта. Проблема вторая Если серверов MySQL несколько, а такая ситуация не так уж редка, то скрипт превращается в запутанную последовательность строк с result и case. Причем, чем больше серверов нуждаются в контроле, тем больше вероятность допустить где-нибудь ошибку. Выход напрашивается сам собой - использовать цикл. Но как быть, если на одном хосте сервера работают на одних портах, а на другом - на совершенно отличных, и найти какую-то закономерность сложно? Оригинальным решением будет воспользоваться shell-подпрограммой, и уже внутри функции mysql_slave_running организовать цикл. Первым параметром передается хост, а в цикле перебираются оставшиеся - номера портов. Нетрудно заметить, что первым параметром передавать предпочтительнее наиболее общий реквизит, не обязательно это должен быть хост: mysql_slave_running() { mysql_host=$1; shift for mysql_port in $* do result=`mysqladmin -h$mysql_host -P$mysql_port \ $mysql_user extended-status 2>&1 | grep Slave_running | awk `{print $4}`` case $result in ON) ;; OFF) /root/scripts/report.error.sh $0 \ "репликация на ${mysql_host}:${mysql_port} \ отключена" 0 "пусто";; *) /root/scripts/report.error.sh $0 \ "невозможно получить статус репликации \ на ${mysql_host}:${mysql_port}" 0 "пусто";; esac done } Путаницы в скрипте становится значительно меньше, тем более, ничто не мешает использовать для форматирования табуляцию: mysql_slave_running "host.ru 3306 64080 64098" mysql_slave_running "provider.ru 64098" Доводим до совершенства И снова, если в скрипте присутствуют повторяющиеся из строки в строку сочетания, значит, нужен цикл. Shell имеет одну интересную и весьма мощную, но малоизвестную возможность, многие из руководств как-то вскользь раскрывают ее, а то и вовсе обходят стороной. Похоже, некоторые из авторов не очень четко представляют, о чем пишут. Возможность эта - обыкновенные двойные кавычки <<">>, вернее то, где и каким образом трактуются shell текст и переменные, заключенные в них. Автору пришлось изучать этот аспект shell-программирования методом проб и ошибок. Итак, воспользуемся кавычками для передачи в цикл параметров - группы символов и пробелов, заключенных в кавычки, будут считаться циклом как отдельные параметры, а функцией mysql_slave_running - как набор параметров. Форматированием можно добиться весьма наглядного представления: for mysql_host in \ "host.ru 3306 64080 64098" \ "provider.ru 64098" \ "another.host.ru 3306 64088 64068" do mysql_slave_running $mysql_host done Собираем все вместе Целиком, уже доведенный до совершенства, скрипт будет выглядеть так: #!/bin/sh mysql_user="-urepcontrol -pguessable" mysql_slave_running() { mysql_host=$1; shift for mysql_port in $* do result=`mysqladmin -h$mysql_host -P$mysql_port \ $mysql_user extended-status 2>&1 | grep Slave_running | awk `{print $4}`` case $result in ON) ;; OFF) /root/scripts/report.error.sh $0 \ "репликация на ${mysql_host}:${mysql_port} \ отключена" 0 "пусто";; *) /root/scripts/report.error.sh $0 \ "невозможно получить статус репликации \ на ${mysql_host}:${mysql_port}" 0 "пусто";; esac done } for mysql_host in \ "host.ru 3306 64080 64098" \ "provider.ru 64098" \ "another.host.ru 64088 64068" do mysql_slave_running $mysql_host done Единственное, что автору так и не удалось <<победить>> в приведенном варианте, так это расположение массива хостов и портов в середине скрипта. Запуск скрипта из cron Осталось только сконфигурировать cron. В принципе, процесс ничем не отличается от описанного в статье <<Скрипт мониторинга web-сервера на shell>>. Объем трафика невелик, поэтому требования к частоте запуска более мягкие, по сравнению с аналогичными требованиями мониторинга web-сервера. Задания, выполняемые от имени root, перечисляются в /var/cron/tabs/root. Если его нет, можно создать файл в текстовом редакторе или доверить создание непосредственно самому crontab: server# crontab -e -u root Строка, конфигурирующая cron для запуска /root/scripts/monitor.mysql.sh каждые 33 минуты: */33 * * * * /root/scripts/monitor.mysql.sh Период в 33 минуты выбран с целью развязать мониторинг серверов MySQL с другими скриптами по времени. Развязка по времени в свою очередь уменьшает пиковые нагрузки на канал доступа. Советую проследить режим файла заданий - 600 (rw-) с владельцем root:wheel и наличие в нем переменных окружения: SHELL=/bin/sh PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin HOME=/var/log После внесения изменений нужно, чтобы cron перечитал список заданий: server# crontab -u root /var/cron/tabs/root В /var/log/cron появится запись: Apr 28 11:11:11 server crontab[75680] REPLACE (root) Подведение итогов С момента снесения в cron скрипта мониторинга /root/scripts/report.error.sh в своих протоколах будет писать: Wed Apr 28 11:11:11 MSD 2004 \ /root/scripts/monitor.mysql.sh \ репликация на host.ru:3306 отключена 0 \ пусто \ Уведомление отправлено admin@host.ru, копия admin_cell_phone@nwgsm.ru А на e-mail, указанные в скрипте будут приходить письма: Date: Wed, Apr 28 2004 11:11:11 +0300 (MSK) From: Charlie Root <root> To: admin@host.ru Subject: Сообщение об ошибке Время: Wed Apr 28 11:11:11 MSD 2004 Скрипт: /root/scripts/monitor.mysql.sh Действие: репликация на host.ru:3306 отключена. Дополнительная информация: Код ошибки: 0 Поток вывода ошибочной команды: пусто Например, такое письмо будет свидетельствовать о том, что MySQL сервер <<лег>>: Date: Wed, Apr 28 2004 11:11:11 +0300 (MSK) From: Charlie Root <root> To: admin@host.ru Subject: Сообщение об ошибке Время: Wed Apr 28 11:11:11 MSD 2004 Скрипт: /root/scripts/monitor.mysql.sh Действие: невозможно получить статус репликации на host.ru:3306. Дополнительная информация: Код ошибки: 0 Поток вывода ошибочной команды: пусто Код ошибки и поток вывода подавляются заглушками <<0>> и <<пусто>>, так как содержимое их не несет какой-либо достаточной смысловой нагрузки. Таковая появляется лишь при очень неустойчивом модемном соединении. В разделе [57]<<Разработка скрипта. Проблема первая>> приведено объяснение этому, к тому же, поток вывода пропускается через каналы. Хранить в транзитных переменных, затем отправлять по почте и протоколировать исходное содержимое потока, по моему личному опыту, не информативно. Заключение По предыдущим публикациям, уже вошло в привычку в заключении акцентировать внимание на том, что данная статья не является учебным руководством по программированию на shell, а призвана дать информацию для размышления. Но, например, ситуация с кавычками в разделе <<Доводим до совершенства>> несколько напоминает руководство, и, смею надеяться, приведенный пример и объяснение, в отличие от <<истинных>> руководств, более доходчив и понятен. Если говорить о перспективах рассмотренного скрипта, то путей лично мне видится два: мониторинг и/или ведение статистики каких-либо других параметров MySQL, или же приспособление скрипта под другой сервер баз данных. Буду признателен за конструктивную критику. Все права защищены. Статья не может быть скопирована или воспроизведена с помощью любых методов или носителей информации без письменного разрешения владельца прав на копирование. (На opennet.ru документ размещен с разрешения автора.)
Иcточник: http://www.freelance.pp.ru/  •  Опубликована: 05.03.2005
Нашли ошибку в тексте? Сообщите о ней автору: выделите мышкой и нажмите CTRL + ENTER
Теги:  


Оценить статью:
Вверх
Комментарии посетителей
Комментарии отключены. С вопросами по статьям обращайтесь в форум.