Задача: по включению сервера необходимо автоматически (без вмешательства администратора) гарантированно обеспечить целостность баз данных 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-ного
Чтобы сервер (компьютер) автоматически запустился после возобновления питания нужно:
Всё?