Несколько советов, как делать резервные копии баз данных

На первый взгляд, сделать резервную копию базы данных какого-либо сайта предельно просто, если есть доступ к утилите mysqldump и планировщику заданий cron. Добавляем в планировщик запись вида:

3 14 * * * /usr/bin/mysqldump -u root -pпароль имя_базы > путь/backup.sql

и все, каждый день в 3 часа 14 минут будет сниматься дамп. Время для резервного копирования следует выбирать так, чтобы в этот момент нагрузка на сервер была минимальной за сутки.
Но такое решение недостаточно надежно. Если база повредится, скажем, в 3:12, то дамп будет перезаписан пустым файлом.
Для защиты от этого имеет смысл сохранять перед снятием новой копии сохранять старую, а также делать отдельные копии через определенные промежутки времени. Например, я сохраяю еженедельную и ежемесячную, а чтобы меньше нагружать SQL-сервер, просто копирую файлы дампа:

2 14 * * * /bin/cp путь/backup.sql путь/backup.yesterday.sql
3 14 * * * /usr/bin/mysqldump -u root -pпароль имя_базы > путь/backup.sql
4 14 * * 1 /bin/cp путь/backup.sql путь/backup.weekly.sql
4 14 2 * * /bin/cp путь/backup.sql путь/backup.monthly.sql

 

Задержки в час сделана для того, чтобы дамп успел создаться/скопироваться полностью.

Такие копии хороши, когда требуется восстановить базу целиком. Но иногда бывают ситуации, когда нужно восстановить только часть контента, причем так, чтобы сохранить то, что было добавлено после снятия backup. Например, такое может потребоваться, если на форуме был удален один раздел. В этом случае дамп, сделанный с настройками выше, не подойдет, поскольку в нем есть SQL-команды на удаление и создание всех таблиц базы заново. Поэтому имеет смысл поступить следующим образом: снимать резервную копию структуры таблиц в один файл, а сами данные — в другой. Кроме того, чтобы при импорте данных в уже существующу таблицу не было ошибок, имеет смысл делать их вставку через INSERT IGNORE. В этом случае команды снятия dump приобретают вид:

 

3 14 * * * /usr/bin/mysqldump --no-data -u root -pпароль имя_базы > путь/backup.struct.sql
>3 15 * * * /usr/bin/mysqldump --insert-ignore --no-create-info -u root -pпароль имя_базы > путь/backup.sql

В этом случае при необходимости частичного восстановления базы можно будет импортировать только backup.sql, и будут восстановлеы только те записи, которые были удалены (и не будут затронуты те, которые появились позже), а при необходимости полного восстановления — сначала backup.struct.sql, а потом уже backup.sql. Также в некоторых случаях имеет смысл пользоваться опцией --replace, в этом случае вместо оператора INSERT будет использоваться REPLACE, что позволит привести все имеющиеся в базе записи к тому виду, который был на момент снятия backup, а более поздние — остались без изменений.

Если у вас есть root-достпу к серверу, то рекомендуется делать резервную копию именно от имени root, и сохранять в каталог, который недоступен обычным пользователям. Это пригодится в случае, злоумышленник найдет уявзвимость на сервере, позволяющую ему выполнять прозивольный код от имени того же пользователя, от которого запускаются скрипты сайте: в этом случае он не сможет удалить резервные копии. И не забывайте периодически выгружать резервные копии на собственный компьютер (или другой сервер при его наличии).

Добавлено позже: написал небольшой скрипт, в котором реализовал все описанные здесь идеи в более удобном для применения виде и выложил его у себя на GitHub.