Резервное копирование базы данных MySQL с помощью снимков ZFS

12

Я обнаружил, что многие сайты говорят именно об этом, но мне не хватает нескольких важных деталей. Основные шаги

  • Бегать FLUSH TABLES WITH READ LOCK
  • Сделайте снимок ZFS
  • Бегать UNLOCK TABLES

Различные источники сообщают, что InnoDB, который я использую, на самом деле не соблюдает FLUSH. Руководство пользователя MySQL отмечает, что есть FLUSH TABLES...FOR EXPORTвариант для использования с InnoDB, но для этого необходимо указывать каждую таблицу отдельно, а не выполнять резервное копирование всей базы данных. Я бы предпочел не указывать каждую таблицу по отдельности, потому что вполне вероятно, что список таблиц будет не синхронизирован с реально существующими таблицами.

Другая проблема, которую я имею, - я планировал сделать что-то подобное mysql -h"$HOST" -u"$USERNAME" -p"$PASSWORD" --execute="FLUSH TABLES WITH READ LOCK". Однако это снимает блокировку сразу после выхода из сеанса. Это имеет смысл, но также довольно раздражает, поскольку мне нужно удерживать блокировку чтения, когда я делаю свой снимок.

Моя другая идея - сделать горячее резервное копирование с помощью такого инструмента, как Percona XtraBackup, и сделать моментальные снимки резервной копии, но я бы предпочел не платить стоимость, чтобы записать все мои данные во второе место, просто чтобы сделать снимок.

Энди Шульман
источник
Зачем иметь статический список таблиц? Вы можете с уверенностью генерировать список динамически во время выполнения.
EEAA
1
База данных на ВМ или на голом металле? Хранение даже на той же машине?
Майкл Хэмптон
EEAA, достаточно справедливо.
Энди Шульман
Майкл, база данных и блок ZFS - это разные машины, но ни одна из них не виртуализирована.
Энди Шульман
@AndyShulman Я думаю, что вы должны объяснить немного лучше. Это не имеет смысла.
ewwhite

Ответы:

4

Если вы используете InnoDB только для всех таблиц и установите innodb_flush_log_at_trx_commit:

  • 1 (содержимое буфера журнала InnoDB записывается в файл журнала при каждой фиксации транзакции, а файл журнала записывается на диск) или,
  • 2 (содержимое буфера журнала InnoDB записывается в файл журнала после каждой фиксации транзакции, а файл журнала записывается на диск примерно раз в секунду),

тогда вам не нужны FLUSH TABLES перед созданием снимка, просто запустите снимок ZFS напрямую. InnoDB может восстанавливать данные из журналов транзакций без потери данных.

Ссылка: https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

Хеа-Суан Лин
источник
Со словарем данных, введенным в MySQL 8, даже операции DDL (изменение схемы) теперь являются атомарными. До этого операции DDL во время снимка файловой системы могли давать частично зафиксированные (то есть поврежденные) результаты.
Берни
13

Вам необходима полная блокировка базы данных для последовательного резервного копирования (большинства) баз данных.

В руководстве https://dev.mysql.com/doc/refman/5.5/en/backup-methods.html говорится, что FLUSH TABLES WITH READ LOCK подходит для снимков ZFS.

Создание резервных копий с использованием снимка файловой системы

Если вы используете файловую систему Veritas, вы можете сделать резервную копию следующим образом:

  1. Выполните из клиентской программы FLUSH TABLES WITH READ LOCK.
  2. Из другой оболочки выполните команду mount vxfssnapshot.
  3. С первого клиента выполните UNLOCK TABLES.
  4. Скопируйте файлы из снимка.
  5. Размонтировать снимок.

Подобные возможности моментальных снимков могут быть доступны в других файловых системах, таких как LVM или ZFS.

Это отчасти смешно , что они вышли из того факта , что вам нужно FLUSH TABLES table_a, table_b, table_c FOR EXPORTдля InnoDB из этих инструкций. Также глупо указывать каждую таблицу таким образом. Но, как говорит EEAA, вы можете создать список таблиц, если начнете резервное копирование довольно легко.

Что касается удержания блокировки, вы должны поддерживать соединение БД во время выполнения снимка

Обычно я использую что-то вроде Perl или другого языка программирования, который может подключаться, блокировать БД и, сохраняя соединение БД, делать снимок, а затем разблокировать и отключить. Это не сложно. Держу пари, что есть инструменты, которые уже делают это, но написать один легко.

Я говорю легко, не сложно и т. Д. Несколько раз. Я предполагаю, что у вас есть базовые навыки программирования или хорошие навыки написания сценариев.

Райан Бабчишин
источник
Я надеялся сохранить такой концептуально простой скрипт на Bash, но вы правы, переключение языков делает это намного проще. Возможно, я неверно читаю ваш ответ, но, похоже, вы говорите, что мне нужно выполнить FLUSH TABLES WITH READ LOCKи то FLUSH TABLES...FOR EXPORT, и другое , тогда как мое чтение руководства по MySQL говорит, что необходим только один.
Энди Шульман
Извините, я не понял. Я просто иду по руководству, и оно говорит о двух разных вещах. Я предполагаю, что вы правы, и нужно только позже. Но все таблицы должны быть заблокированы в одной команде.
Райан Бабчишин
1
Учитывая, что документация не очень понятна, необходимо заблокировать всю базу данных и поддерживать соединение с БД во время создания моментального снимка, кажется, проще просто выключить БД, сделать ее резервную копию и перезапустить Это.
Эндрю Хенле
2
@ вздохнул Эндрю ... Я понимаю. Но это будет медленно, вызывать сбой / сбой соединений, и я видел, что это приводит к тому, что базы данных не могут правильно восстановиться (плохо для автоматизации). Было бы хорошо получить окончательный ответ от MySQL / Oracle. У них должен быть список рассылки.
Райан Бабчишин
7

Я сорвал и адаптировал концептуально простой скрипт на Bash, который я нашел в другом сообщении о сбое сервера от Tobia . Это должно пройти около 90% пути.

mysql_locked=/var/run/mysql_locked

# flush & lock MySQL, touch mysql_locked, and wait until it is removed
mysql -hhost -uuser -ppassword -NB <<-EOF &
    flush tables with read lock;
    delimiter ;;
    system touch $mysql_locked
    system while test -e $mysql_locked; do sleep 1; done
    exit
EOF

# wait for the preceding command to touch mysql_locked
while ! test -e $mysql_locked; do sleep 1; done

# take a snapshot of the filesystem, while MySQL is being held locked
zfs snapshot zpool/$dataset@$(date +"%Y-%m-%d_%H:%M")

# unlock MySQL
rm -f $mysql_locked

Здесь используемая mysqlвами команда запускается в фоновом режиме и касается файла. Он ждет в фоновом режиме, чтобы файл исчез, прежде чем выйти и, таким образом, разблокировать таблицы. Тем временем основной сценарий ожидает, пока файл не существует, затем создает снимок и удаляет файл.

Файл, на который указывает указатель, $mysql_lockedдолжен быть доступен для обеих машин, что вы должны сделать достаточно легко, так как они могут обращаться к общему набору данных (хотя они могут использовать разные пути, и вы должны учитывать это).

Майкл Хэмптон
источник
Я не знаю сценариев MySQL, так что это может быть глупой идеей, но не могли бы вы просто сделать это system zfs snapshot...внутри основного скрипта? Или моментальный снимок должен выполняться в отдельном процессе?
TripeHound
@ Трехсторонний гонщик должен каким-то образом происходить параллельно
Райан Бабчишин
@RyanBabchishin Я думаю, он прав, на самом деле. Команда SYSTEMзапускает вещи локально. Если я запускаю клиент mysql на коробке FreeBSD и выполняю LOCK; SYSTEM zfs snapshot; UNLOCK, кажется, что это будет работать.
Энди Шульман
@ И я только что сказал, что они должны проходить параллельно. Неважно, как вы это делаете.
Райан Бабчишин
2

Для myisam вам нужны FLUSH TABLES WITH READ LOCK, потому что это не ведение журнала.

Вам вообще ничего не нужно для innodb, IMO, потому что это ведение журнала. В любом случае это будет согласованно, просто автоматически откатывается журнал, если что-то происходит в атомный момент, когда вы делаете снимок.

Если вы хотите согласованности на уровне приложения, ваше приложение должно использовать транзакции. Если ваше приложение использует транзакции и innodb, любой снимок будет непротиворечивым, спросите путь до уровня приложения автоматически.

Джим Солтер
источник
2

Это моё решение, как создать снимок ZFS с сохранением блокировки:

mysql << EOF
    FLUSH TABLES WITH READ LOCK;
    system zfs snapshot data/db@snapname
    UNLOCK TABLES;
EOF
Петр Стастный
источник