Задача: по включению сервера необходимо автоматически (без вмешательства администратора) гарантированно обеспечить целостность баз данных MySQL.
Зачем: для гарантированного запуска после аварии питания на сервере ключевых сервисов (демонов, программ, приложений), зависимых от баз данных.
Способ: синхронная(блокирующая) проверка баз данных с принудительным автоматическим восстановлением найденных повреждённых таблиц, выполняемая по каждому запуску/перезапуску демона mysql.
В качестве зависимого от MySQL важного сервиса предположим вымышленный демон MySuperMajorDaemon, хотя это может быть просто веб-сервер c сайтом, движок которого использует базу MySQL, LAMP, например.
Прежде всего нужно проверить систему инициализации (init) вашего дистрибутива, а именно:
В Debian GNU/Linux 4.0 используется классический
sysvint (System-V-like init utilities) в которой
init-сценарии демонов из каталога /etc/init.d/
запускаются последовательно и верно, но медленно, поэтому нам
остаётся проверить лишь порядок запуска и останова нашего демона,
относительно демона mysqld.
Примечание: в Ubuntu, несмотря на использование «параллельного»
upstart вместо классического sysvint, init-скрипты, похоже, также
стартуют последовательно. 
Итак, ниже приводим самый низкоуровневый способ проверки, подходящий для большинства дистрибутивов, использующих sysvinit и upstart. Для начала, определим текущий RUNLEVEL.
% sudo runlevel N 2
Выводим на экран имена скриптов в одну колонку в порядке запуска/останова.
# последовательность запуска для runlevel=2 % ls -1 /etc/rc2.d/ # последовательность остановки при выключении runlevel=0 % ls -1 /etc/rc0.d/ # последовательность остановки при перезагрузке runlevel=6 % ls -1 /etc/rc6.d/
Примечания:
/etc/init.d/ нужно использовать
/etc/rc.d/init.d/, а вместо /etc/rc?.d/ —
/etc/rc.d/rc?.d/file-rc
init с настройкой в единственном файле
/etc/runlevel.conf. Кстати, отличная штука для
поклонников BSD style,С порядком порядок
? Тогда двигаемся дальше.
Теперь куда-то нужно вставить код проверки и лечения баз.
Таких мест (чтобы было наверняка) всего два:
Мы выбираем первый вариант и, как оказывается, «всё уже украдено до нас» — нужный нам код уже предусмотрен прямо «из коробки» (из пакета «mysql-server»).
Часть кода init-сценария запуска демона mysqld
# скрипт /etc/init.d/mysql
...
start)
...
/usr/bin/mysqld_safe > /dev/null 2>&1 &
# 6s was reported in #352070 to be too few when using ndbcluster
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do
sleep 1
if mysqld_status check_alive nowarn ; then break; fi
log_progress_msg "."
done
if mysqld_status check_alive warn; then
log_end_msg 0
# Now start mysqlcheck or whatever the admin wants.
output=$(/etc/mysql/debian-start)
[ -n "$output" ] && log_action_msg "$output"
else
log_end_msg 1
log_failure_msg "Please take a look at the syslog"
fi
...
Как видно из кода, строка
«output=$(/etc/mysql/debian-start)» запускает некий
исполняемый скрипт «/etc/mysql/debian-start»
Смотрим его.
% cat /etc/mysql/debian-start
#!/bin/bash # # This script is executed by "/etc/init.d/mysql" on every (re)start. # # Changes to this file will be preserved when updating the Debian package. # source /usr/share/mysql/debian-start.inc.sh MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" MYUPGRADE="/usr/bin/mysql_upgrade --defaults-extra-file=/etc/mysql/debian.cnf" MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf" MYCHECK_SUBJECT="WARNING: mysqlcheck has found corrupt tables" MYCHECK_PARAMS="--all-databases --fast --silent" MYCHECK_RCPT="root" # The following commands should be run when the server is up but in background # where they do not block the server start and in one shell instance so that # they run sequentially. They are supposed not to echo anything to stdout. # If you want to disable the check for crashed tables comment # "check_for_crashed_tables" out. # (There may be no output to stdout inside the background process!) echo "Checking for corrupt, not cleanly closed and upgrade needing tables." ( upgrade_system_tables_if_necessary; check_for_crashed_tables; ) >&2 & exit 0
Отлично. Вкратце, скрипт работает так:
/usr/share/mysql/debian-start.inc.sh, в котором
описаны функции upgrade_system_tables_if_necessary() и
check_for_crashed_tables();/etc/init.d/mysql.Запуск системы продолжается (загружаются другие демоны), а функции (см. выше) параллельно отрабатывают в фоне и сообщают о результатах своей работы в системный журнал (Syslog) и дополнительно, в случае ошибок, root-y на e-mail.
Хм, в штатно-предусмотренном сценарии
«/etc/mysql/debian-start» нас не устраивают две
вещи:
MySuperMajorDaemon запустится на «недолеченных»
повреждённых базах и может страшно обидится на это;mysqlcheck, запущенный с дефолтными
опциями определёнными в MYCHECK_PARAMS, не будет
восстанавливать повреждённые базы, а только лишь найдёт их, запишет
об этом в журнал и уведомит root-а.Изменим это.
патч для debian-start
% diff -u0 /etc/mysql/debian-start.orig /etc/mysql/debian-start --- /etc/mysql/debian-start.orig 2007-02-22 03:04:51.000000000 +0300 +++ /etc/mysql/debian-start 2008-12-02 13:02:56.000000000 +0300 @@ -14 +14 @@ -MYCHECK_PARAMS="--all-databases --fast --silent" +MYCHECK_PARAMS="--all-databases --silent --medium-check --auto-repair" @@ -27 +27 @@ -) >&2 & +) >&2
Раскроем опции mysqlcheck, выбранные на наш
вкус.
Как убрали фоновую обработку (background), надеемся, понятно.
% man mysqlcheck
...
--medium-check, -m
Проверять быстрее чем с --extended опцией.
Этот режим найдёт 99.99% ошибок, что оправдано в большинстве случаев.
...
--auto-repair
Автоматически восстанавливать повреждённые таблицы.
Процессы восстановления начинаются только после проверки всех таблиц.
...
% dpkg -S /etc/mysql/debian-start mysql-server-5.0: /etc/mysql/debian-start
и, соответственно, могут быть вытащены из него для использования в других дистрибутивах, в которых не предусмотрено подобного механизма.
К недостаткам решения можно отнести увеличившееся время
выполнения скрипта «/etc/init.d/mysql start». Если
базы данных небольшие и целые, то это время вы можете даже не
почувствовать. Но если базы приличного объёма и при этом
повреждённые, то вы точно успеете сварить кофе или даже сходить
пообедать
.
Об этом следует помнить, особенно при удалённой работе с сервером по ssh и особенно при удалённой перезагрузке сервера Debian 4.0 Etch, ибо:
Debian 4.0 Etch
% ls -1 /etc/rc2.d | egrep '(mysql|ssh)' S17mysql-ndb-mgm S18mysql-ndb S19mysql S20ssh
То есть, по включению/перезагрузке компьютера, никто не сможет войти в систему (ни локально, ни по сети) пока не завершится процесс проверки и восстановления баз данных
В Убунту с этим делом полегче, сервер SSH запускается раньше MySQL.
Ubuntu 8.04
ls -1 /etc/rc2.d | egrep '(mysql|ssh)' S16ssh S17mysql-ndb-mgm S18mysql-ndb S19mysql
databases) или даже указать конкретные таблицы
(tables), но только одной базы данных. Детали смотрите
в первоисточнике «mysqlcheck(1)».Особо наблюдательные могут спросить: а как
mysqlcheck будет что-то там лечить, ведь для этого он
должен знать пароль root-а (mysql-льного, не путать с
системным).
Отвечаем: пароль mysql-ного root-а mysqlcheck
не знает, он запускается от пользователя
«debian-sys-maint», пароль которого прописан в файле
«/etc/mysql/debian.cnf».
$ sudo cat /etc/mysql/debian.cnf
# Automatically generated for Debian scripts. DO NOT TOUCH! [client] host = localhost user = debian-sys-maint password = ************** socket = /var/run/mysqld/mysqld.sock [mysql_upgrade] user = debian-sys-maint password = ************** socket = /var/run/mysqld/mysqld.sock basedir = /usr
Mysql-пользователь с именем «debian-sys-maint»
создаётся при установке пакета mysql-server, пароль для него из 16
знаков генерируется случайным образом.
«debian-sys-maint» может почти то же, что и root.
Теперь опять внимательно посмотрим
«/etc/mysql/debian-start»
MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf"
Теперь понятно откуда mysqlcheck берёт имя и пароль для работы с сервером?
Благодаря сохранённому в файле аккаунту
«debian-sys-maint» многие Debian/Ubuntu пакеты,
использующие базы данных, при установке/обновлении автоматически
или после подтверждения пользователя создают/обновляют структуры
своих баз. Это один из механизмов «дружественности к пользователю»,
которым достигается принцип «установил/обновил и сразу работает»
принятых(возможных) в пакетной базе дистрибутивов, основанных на
Debian.
Уже слышим брюзжание экспертов в области безопасности
.
Экперты: Как это так, пароль почти root-а (опять
напомним, mysql-льного, не путать с системным) сохранён в файле на
диске.
Отвечаем: /etc/mysql/debian.cnf имеет
атрибуты доступа 0600 root:root, которые позволяют
читать этот файл только одному пользователю в системе - root-у. А
если вы профукаете пароль системного root-а, то злоумышленник легко
получит доступ с базам и без информации из
/etc/mysql/debian.cnf.
Эксперты: Нельзя считать безопасным дистрибутив, в
котором устанавливаемые/обновляемые пакеты могут автоматически
править базы данных.
Отвечаем: Спорный вопрос, во многом зависит от качества
сборки и тестирования конкретного пакета, а также доверия к его
создателям.
Debian/Ubuntu, на сегодняшний день, имеют две самые большие
пакетные базы среди всех дистрибутивов GNU/Linux, доступ к которым
(установка/обновление пакетов) осуществятся через сетевые
депозитории и пакетный менеджер APT.
Т.е., почти всё, что может понадобиться пользователю, уже есть в
централизованном репозитории, в тщательно проверенных,
оттестированных пакетах. Схема тестирования и проверки пакетов в
Debian более чем (по нашему мнению - самая) серьёзная: циклы
«experimental -> unstable
-> testing -> stable».
Ну а самым яростным специалистам в области безопасности,
советуем вспомнить установлены ли вообще или давно ли менялись
пароли root-ов, и системного и mysql-ного ![]()
Чтобы сервер (компьютер) автоматически запустился после возобновления питания нужно:
Всё?