The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Разработка скрипта для протоколирования событий и мониторинга MySQL и Apache (monitor shell log apache web mysql)


<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>
Ключевые слова: monitor, shell, log, apache, web, mysql,  (найти похожие документы)
From: Foxy S. Aries (Alexei A. Abramov) <foxy@randconsult.ru.> Newsgroups: http://www.freelance.pp.ru Date: Mon, 20 Sep 2004 18:21:07 +0000 (UTC) Subject: Разработка скрипта для протоколирования событий и мониторинга MySQL и Apache Оригинал: http://www.freelance.pp.ru Скрипт протоколирования событий на 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 документ размещен с разрешения автора.)

<< Предыдущая ИНДЕКС Поиск в статьях src Установить закладку Перейти на закладку Следующая >>

 Добавить комментарий
Имя:
E-Mail:
Заголовок:
Текст:




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2020 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру