понедельник, 23 января 2012 г.

Приключения: сбойнувший mysql backup с помощью master-slave


Есть у меня база mysql , среднего размера , гигов 20, досталась с биллингом.
Так как данные очень важные, вместо периодичных бекапов было настроено два slave для нее.
Пару раз в месяц заглядывал, как там , идет ли репликация, да и забыл со временем.

А сегодня внезапно на том сервере с базой, сразу два винта отчаянно забили в smartd , предупреждая о скорой смерти.

Заглянув в слейвы заметил там очень, очень давнюю ошибку:
 Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
Ну, другими словами получилась ситуация. то ли мастер послал кривой binary log, толи по сети он испортился, но слейвы проиграть его не смогли, и застопорились на этой position.

Причем у одного из слейвов был настроен relay-log-space-limit, и в какой то момент он просто перестал получать новые логи.

Дальше начинается цирк с конями. Какие то данные из /var/db/mysql видимо не читаются совсем.
Поэтому сделать чистый mysqldump не получается. В какой то момент сервер начинает так тупить часами, что дождаться невозможно.

В итоге предстоит восстановить текущее состояние базы, из древней базы slave, застопоренной репликации и горы бинарных логов.
Тот слейв что не имел relay-log-space-limit, до сих пор получает их в актуальном режиме. Но не "проматывает" их в свою копию БД.

Погуглив, нашел вот такую инструкцию
http://voituk.kiev.ua/2009/09/17/mysql-slave-could-not-parse-relay-log-event-entry/

у меня ситуация очень похожа, за исключением мелких нюансов, но что б не морочить голову опишу целиком:

  1. Средствами файрвола запретил все конекты к master за исключением слейва, что б состояние базы не менялось и слейв догнал. Если у вас в базу никто интенсивно не пишет, вам вероятно это не надо. Но у меня пишет толпа клиентов, глазами не уследить за position в логе. Тормознул на пяток минут, подождал пока трафик на slave не упал.
  2. Остановил слейв. stop slave
  3. Сбросил логи на мастере,что б не высчитывать позицию в бинарном логе -  flush logs 
  4. Сбросил логи на слейве. flush logs 
  5. Обойдя ошибку, позицию которую знаю из show slave status , преобразовал бинарный лог в sql с помощью mysqlbinlog, и загрузил этот sql в базу с помощью mysql --force
  6. Затем написал простенький скриптик на перле который "развернул" и "загрузил" в базу все остальные бинарные логи, у меня их огромная толпа оказалась.
  7. Тормозим slave mysqld
  8. Подменяем файл relay-log.info вписывая туда последний не загруженный relay log
  9. Запускаем slave mysqld
  10. Устанавливаем позицию репликации , slave set master=... в новый master log
  11. Стартуем репликацию. start slave
Вроде бы обошлось , и получил базу на "текущий момент".
Можно выкидывать старые сбойнувшие винты, и делать замену.
Но осадочек конечно остался. Нельзя ли было вместо всего этого кошмарного геморроя предусмотреть slave skip to=... по relay логу.