Мастер-класс по резервному копированию MySQL: Пишем надежный скрипт для сна

Мастер-класс по резервному копированию MySQL: Пишем надежный скрипт для сна

База данных MySQL — это сердце большинства веб-приложений, хранящее бесценную информацию: от пользовательских аккаунтов до финансовых транзакций. Потеря этих данных может стать катастрофой для бизнеса. Автоматизация резервного копирования через собственный скрипт — это не роскошь, а обязательная практика для любого администратора, которая гарантирует спокойный сон и быструю возможность восстановления в случае сбоя.

Почему именно скрипт, а не ручное копирование?

Ручное создание дампов — это человеческий фактор, забывчивость и ошибки. Скрипт работает по расписанию, четко и без эмоций. Он обеспечивает консистентность (согласованность) данных на момент создания бэкапа, что критически важно для транзакционных систем. Автоматизация — это основа любой стратегии Disaster Recovery.

Создаем базовый, но мощный скрипт на Bash

Самый распространенный и гибкий способ — написать скрипт для командной оболочки Bash. Он может работать на любом Linux-сервере.

Ключевые компоненты скрипта

  1. Утилита mysqldump: «Рабочая лошадка» для создания логических дампов. Она преобразует структуру и данные в набор SQL-команд.
  2. Параметры командной строки: Определяют, что копировать (одну БД, все, определенные таблицы), и как (с блокировками или без).
  3. Логирование: Запись результатов работы скрипта в лог-файл для последующего аудита.
  4. Обработка ошибок: Проверка кодов возврата команд, чтобы скрипт не молчал о проблемах.
  5. Ротация архивов: Автоматическое удаление старых бэкапов для экономии места.

Важно! Для создания дампа скрипту нужны учетные данные с достаточными привилегиями (минимум SELECT, LOCK TABLES, SHOW VIEW, TRIGGER). Никогда не храните пароль в скрипте в чистом виде! Используйте конфигурационный файл с ограниченными правами доступа (chmod 600).

Пример практического скрипта

Рассмотрим готовый пример с комментариями:

#!/bin/bash
# ============================================
# Скрипт резервного копирования MySQL
# ============================================

# Конфигурация
BACKUP_DIR="/var/backups/mysql"
MYSQL_USER="backup_user"
MYSQL_PASSWORD_FILE="/root/.my.backup.cnf" # Файл с паролем
DATABASE_NAME="my_app_db"
DAYS_TO_KEEP=7
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
LOG_FILE="$BACKUP_DIR/backup.log"

# Создание директории, если её нет
mkdir -p $BACKUP_DIR

# Имя файла бэкапа
BACKUP_FILE="$BACKUP_DIR/${DATABASE_NAME}_${TIMESTAMP}.sql.gz"

# Логирование начала
echo "[$(date)] Начало резервного копирования БД: $DATABASE_NAME" >> $LOG_FILE

# Создание дампа с использованием файла конфигурации для пароля
# Ключевые параметры:
# --single-transaction — для InnoDB, обеспечивает консистентность без блокировок.
# --routines — сохраняет хранимые процедуры и функции.
# --events — сохраняет события планировщика.
# --triggers — сохраняет триггеры (включено по умолчанию в новых версиях).

mysqldump --defaults-extra-file=$MYSQL_PASSWORD_FILE \
    --user=$MYSQL_USER \
    --single-transaction \
    --routines \
    --events \
    $DATABASE_NAME | gzip > $BACKUP_FILE

# Проверка успешности выполнения mysqldump
if [ ${PIPESTATUS[0]} -ne 0 ]; then
    echo "[$(date)] ОШИБКА: Не удалось создать дамп БД $DATABASE_NAME" >> $LOG_FILE
    exit 1
fi

# Проверка, что архив создан и не пустой
if [ -s $BACKUP_FILE ]; then
    FILE_SIZE=$(du -h $BACKUP_FILE | cut -f1)
    echo "[$(date)] УСПЕХ: Бэкап создан: $BACKUP_FILE (размер: $FILE_SIZE)" >> $LOG_FILE
else
    echo "[$(date)] ОШИБКА: Файл бэкапа пуст или не создан!" >> $LOG_FILE
    exit 1
fi

# Очистка старых бэкапов (ротация)
find $BACKUP_DIR -name "${DATABASE_NAME}_*.sql.gz" -mtime +$DAYS_TO_KEEP -delete 2>/dev/null

echo "[$(date)] Резервное копирование завершено." >> $LOG_FILE

Планирование выполнения с помощью Cron

Скрипт бесполезен, если его не запускать автоматически. Для этого используется планировщик Cron.

# Открываем crontab для редактирования
crontab -e

# Добавляем строку для ежедневного запуска в 2:00 ночи
0 2 * * * /bin/bash /путь/к/вашему/скрипту/backup_mysql.sh

Совет продвинутого уровня: Для очень больших баз рассмотрите использование физического копирования файлов данных (например, через Percona XtraBackup) или репликации на «горячий» standby-сервер. Это минимизирует время простоя при восстановлении.

Стратегия 3-2-1 — золотой стандарт

Создания файла на диске недостаточно. Придерживайтесь правила:

  • 3 копии данных.
  • На 2 разных типах носителей (например, локальный SSD + облачное хранилище).
  • 1 копия должна быть географически удаленной (другой дата-центр или S3/Selectel/Yandex Cloud).
Модифицируйте скрипт, чтобы он после создания архива загружал его, например, в S3-совместимое хранилище с помощью утилиты aws s3 cp или rclone.

Тестирование восстановления — самая важная часть

Бэкап, который никогда не тестировался на восстановление, — это не бэкап, а надежда. Регулярно (хотя бы раз в квартал) выполняйте процедуру восстановления дампа на тестовый сервер и проверяйте целостность данных. Включите это в свой регламент.

FAQ: Часто задаваемые вопросы

Какой параметр mysqldump использовать для минимальной блокировки таблиц?

Для движка InnoDB используйте --single-transaction. Он создает снимок данных на момент начала дампа внутри транзакции, не блокируя таблицы для записи надолго. Для MyISAM этот параметр не работает, может потребоваться --lock-tables.

Мой дамп получается огромным. Как его оптимизировать?

Используйте сжатие на лету (как в примере: | gzip). Также можно исключать большие, не критичные таблицы с помощью опции --ignore-table=database.table. Для инкрементального бэкапа рассмотрите инструменты вроде Percona XtraBackup.

Как автоматически удалять старые бэкапы?

В примере скрипта используется команда find с параметром -mtime +$DAYS_TO_KEEP. Она удаляет файлы старше указанного количества дней. Это классическая ротация.

Безопасно ли хранить пароль в скрипте?

Нет, категорически нет! Всегда используйте опцию --defaults-extra-file, которая читает учетные данные из защищенного файла с правами доступа 600. Никогда не передавайте пароль через аргументы командной строки, так как он может быть виден другим пользователям в списке процессов (ps aux).

Как сделать бэкап всех баз данных на сервере?

Используйте параметр --all-databases вместо указания имени конкретной БД. Не забудьте выделить больше места для хранения и убедитесь, что у пользователя есть глобальные привилегии.