Горячие бэкапы — это резервные копии, которые снимаются на работающем сервере без остановки приложений. На VDS такой подход особенно ценен: планирование простоев сложно, а короткие окна обслуживания часто невозможны. В этой статье показываю рабочий рецепт горячего backup с помощью LVM snapshots для файловых систем и консистентного mysql backup, с опорой на fsfreeze и минимальное время блокировки. Разберём подготовку LVM, практические шаги, типичные ловушки и восстановление (restore).
Когда и зачем использовать LVM snapshots
LVM снапшоты — это снимки состояния блочного устройства на момент времени. Они работают по Copy-on-Write: при изменении исходного тома копируется старая версия изменяемых блоков в отдельно выделенное пространство снапшота. Отсюда следуют плюсы: мгновенное создание, возможность монтировать снапшот в ro и спокойно вычитывать данные в архив. И минусы: пока существует снапшот, запись в оригинальный том замедляется, а если место под снапшот закончится, он станет непригодным.
Сценарии, где LVM особенно полезен:
- Горячие копии директорий сайтов, медиа и конфигов, когда остановка сервисов нежелательна.
- Физический
mysql backupдля InnoDB с минимальным временем read lock, удобный для быстрогоrestoreили развертывания стендов. - Контрольные точки перед обновлением (с возможностью отката
lvconvert --merge).
Важно: LVM снапшот фиксирует состояние блочного устройства, а не приложения. Для полной согласованности баз данных требуется короткая фаза «заморозки» — см. блок про MySQL.
Предварительная проверка: есть ли LVM и хватает ли места
На большинстве современных образов Linux используется LVM по умолчанию. Проверьте разметку и свободное место в группе томов:
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT,LVM
vgs -o vg_name,vg_size,vg_free
lvs -o lv_name,vg_name,lv_size,lv_attr
Нам нужна свободная емкость в VG (Volume Group) для пространства снапшота. Правило большого пальца: размер снапшота ≈ ожидаемому объему изменений на исходном LV за время жизни снапшота с запасом. Для файлового архива на несколько минут обычно хватает 1–10% от размера LV, но всё зависит от интенсивности записи.
План: какие тома снимем и как будем вычитывать
Определите, что именно архивируем: том с данными сайтов (например, /var/www), том с логами, том с /var/lib/mysql. Для XFS и ext4 подход одинаков, но есть нюансы монтирования снапшота XFS: нужен параметр nouuid.
Далее выбираем стратегию выгрузки снапшота: tar в файл, поток в удаленное хранилище, rsync в каталог с дедупликацией, или подключение к инструментам версиирования. Снапшот сам по себе жить долго не должен — создали, смонтировали, вычитали, удалили. Подробнее о вариантах хранения см. гайд по S3‑бэкапам restic/borg.

Быстрый старт: горячий бэкап каталога на ext4/XFS
Предположим, данные в /mnt/data, это отдельный LV /dev/vg/data. Шаги:
- Уточняем файловую систему:
findmnt -no FSTYPE /mnt/data
- Замораживаем ФС на 1–3 секунды (чтобы записать на диск все метаданные):
# Для XFS
xfs_freeze -f /mnt/data
# Для ext4
fsfreeze -f /mnt/data
- Создаём снапшот нужного размера (пример 5ГиБ):
lvcreate -L 5G -s -n data_snap /dev/vg/data
- Размораживаем ФС:
# XFS
xfs_freeze -u /mnt/data
# ext4
fsfreeze -u /mnt/data
- Монтируем снапшот только для чтения:
mkdir -p /mnt/snap
# Для XFS важно указать nouuid
mount -o ro,nouuid /dev/vg/data_snap /mnt/snap
# Для ext4 можно просто
# mount -o ro /dev/vg/data_snap /mnt/snap
- Выгружаем в архив или зеркало:
# Архив tar с атрибутами и ACL
cd /mnt/snap
tar --xattrs --acls -cpf - . | gzip -1 > /backups/data-$(date +%F).tar.gz
# Или rsync в каталог с датой
rsync -aHAX --delete /mnt/snap/ /backups/data-$(date +%F)/
- Чистим за собой:
umount /mnt/snap
lvremove -y /dev/vg/data_snap
Снапшот держите как можно меньше по времени. Чем он живёт дольше, тем сильнее падает производительность исходного тома из‑за Copy‑on‑Write.
Консистентный MySQL backup через LVM snapshot
Для InnoDB корректный физический бэкап делается так: коротко блокируем записи в MySQL, замораживаем ФС с fsfreeze на время создания снапшота, снимаем снапшот, сразу же возвращаем MySQL в нормальный режим. Важные предпосылки:
- Данные MySQL находятся на отдельном LV (рекомендовано) и директория
datadirизвестна, чаще всего/var/lib/mysql. - Основные таблицы — InnoDB; для MyISAM и прочего потребуются более строгие блокировки, лучше мигрировать в InnoDB.
- Журналирование транзакций включено стандартно; опции согласованы с безопасным режимом (
innodb_flush_log_at_trx_commit=1,sync_binlog=1— желательно).
Пошагово
- Уточните
datadirи LV:
mysql --version
grep -i '^datadir' /etc/mysql/*.cnf /etc/my.cnf 2>/dev/null || echo "check service unit"
lsblk -o NAME,MOUNTPOINT,LVM | grep mysql || findmnt /var/lib/mysql
- Откройте интерактивную сессию MySQL и выполните блокировку чтения/записи, не закрывая сессию (это критично — пока сессия открыта, замок держится):
mysql -uroot -p
FLUSH TABLES WITH READ LOCK;
FLUSH LOGS;
-- при репликации можно зафиксировать позицию:
SHOW MASTER STATUS;
- Во втором окне терминала заморозьте ФС, создайте снапшот и сразу разморозьте:
# Если ФС XFS
xfs_freeze -f /var/lib/mysql
lvcreate -L 5G -s -n mysql_snap /dev/vg/mysql
xfs_freeze -u /var/lib/mysql
# Если ext4
fsfreeze -f /var/lib/mysql
lvcreate -L 5G -s -n mysql_snap /dev/vg/mysql
fsfreeze -u /var/lib/mysql
- Вернитесь в первую сессию MySQL и снимите блокировку:
UNLOCK TABLES;
- Смонтируйте снапшот в
roи выгрузите:
mkdir -p /mnt/mysqlsnap
mount -o ro,nouuid /dev/vg/mysql_snap /mnt/mysqlsnap # для XFS
# mount -o ro /dev/vg/mysql_snap /mnt/mysqlsnap # для ext4
# Важно копировать весь datadir, включая ibdata*, ib_logfile*, undo*, redo* и служебные каталоги
rsync -aHAX /mnt/mysqlsnap/ /backups/mysql-$(date +%F)/
umount /mnt/mysqlsnap
lvremove -y /dev/vg/mysql_snap
Почему нужен двойной «замок» (FTWRL + fsfreeze)? FTWRL останавливает изменения на уровне СУБД, а fsfreeze фиксирует на диске состояние ФС, чтобы LVM снапшот гарантированно отражал согласованные метаданные. Блокировка держится считанные секунды.
Советы и частые нюансы
- Не исключайте файлы redo/undo/ibdata — это физический
mysql backup, нужен полныйdatadir. - При восстановлении на другой сервер удалите или замените
auto.cnf, чтобы избежать конфликта UUID. - Если в базе есть MyISAM, FTWRL обязателен; любые фоновые записи в эти таблицы должны быть остановлены.
- Репликацию можно синхронизировать: сохраните координаты из
SHOW MASTER STATUSвместе с копией; подробнее см. гайд по репликации GTID/semisync.

Восстановление (restore) из бэкапа
Файловые данные
Вариант «поверх»: аккуратно развернуть содержимое в целевой каталог, исключая временные файлы.
rsync -aHAX --delete /backups/data-2025-01-10/ /mnt/data/
Быстрый откат LV на момент снапшота (если вы оставили снапшот ради отката):
umount /mnt/data
lvconvert --merge /dev/vg/data_snap
mount /mnt/data
Помните: для lvconvert --merge снапшот должен быть неактивен и исходный LV — отключен/отмонтирован.
MySQL
Восстановление физического бэкапа:
systemctl stop mysql
mv /var/lib/mysql /var/lib/mysql.bak.$(date +%s)
rsync -aHAX /backups/mysql-2025-01-10/ /var/lib/mysql/
chown -R mysql:mysql /var/lib/mysql
# Для SELinux
command -v restorecon && restorecon -Rv /var/lib/mysql || true
systemctl start mysql
journalctl -u mysql -e --no-pager
Если поднимали реплику, проверьте auto.cnf (UUID), а также конфигурацию server-id и подключение к источнику. Для восстановления до точки во времени используйте бинлоги согласно сохранённым координатам.
Размер снапшота и контроль заполнения
Пока живёт снапшот, все записываемые блоки исходного LV дублируются в его COW‑область. Следите за заполнением:
lvs -o lv_name,lv_attr,Data%,Cpy%Sync
Поле Data% у снапшота должно оставаться далёким от 100%. Если достигнет 100%, снапшот станет непригоден и монтироваться перестанет. Подбирайте размер с запасом и держите снапшот недолго.
Производительность и влияние на сервисы
Снапшот добавляет накладные расходы на запись. На загруженных дисках это заметно. Практика:
- Создавайте снапшот на время копирования и удаляйте сразу после.
- Планируйте бэкап на часы с минимальной нагрузкой.
- Для сильно записываемых томов рассмотрите LVM thin snapshots (если используете thin-pool), они эффективнее по месту и скорости на множественных снимках.
Thin-пулы и thin snapshots (коротко)
Если ваши тома — thin LVs, команда создания снапшота остаётся практически той же, но снапшот будет типа thin-snapshot и использовать thin-pool. Пример создания тонкого пула и тома:
# Создать thin-pool на 100G
lvcreate -L 100G -T vg/thinpool
# Создать thin-том 50G
lvcreate -V 50G -T vg/thinpool -n data
# Снапшот thin-тома
lvcreate -s -n data_snap vg/data
Thin-снапшоты хорошо подходят для частых контрольных точек и экономят место, но также требуют мониторинга заполнения пула.
Автоматизация: безопасный скрипт
Ниже пример упрощенного скрипта для бэкапа тома с данными и MySQL. Учтены ловушки: аварийный выход по ошибке, логирование, защита от одновременных запусков. Доработайте под свои пути/имена.
#!/usr/bin/env bash
set -Eeuo pipefail
LOCK=/run/backup.lock
exec 9>&1 1>>/var/log/backup.log 2>&1
{
flock -n 200 || { echo "Already running"; exit 1; }
} 200>"$LOCK"
echo "=== $(date -Is) backup start"
VG="vg"
LV_DATA="data"
LV_MYSQL="mysql"
SNAP_DATA="data_snap"
SNAP_MYSQL="mysql_snap"
BACKDIR="/backups/$(date +%F)"
mkdir -p "$BACKDIR"
# 1) DATA
xfs_freeze -f /mnt/data || fsfreeze -f /mnt/data || true
lvcreate -L 5G -s -n "$SNAP_DATA" "/dev/$VG/$LV_DATA"
xfs_freeze -u /mnt/data || fsfreeze -u /mnt/data || true
mkdir -p /mnt/snap_data
mount -o ro,nouuid "/dev/$VG/$SNAP_DATA" /mnt/snap_data || mount -o ro "/dev/$VG/$SNAP_DATA" /mnt/snap_data
rsync -aHAX --delete /mnt/snap_data/ "$BACKDIR/data/"
umount /mnt/snap_data
lvremove -y "/dev/$VG/$SNAP_DATA"
# 2) MYSQL
mysql -uroot -p"${MYSQL_ROOT_PASSWORD:-}" -e "FLUSH TABLES WITH READ LOCK; FLUSH LOGS;" &
LOCKPID=$!
sleep 1
xfs_freeze -f /var/lib/mysql || fsfreeze -f /var/lib/mysql
lvcreate -L 5G -s -n "$SNAP_MYSQL" "/dev/$VG/$LV_MYSQL"
xfs_freeze -u /var/lib/mysql || fsfreeze -u /var/lib/mysql
mysql -uroot -p"${MYSQL_ROOT_PASSWORD:-}" -e "UNLOCK TABLES;" || true
mkdir -p /mnt/snap_mysql
mount -o ro,nouuid "/dev/$VG/$SNAP_MYSQL" /mnt/snap_mysql || mount -o ro "/dev/$VG/$SNAP_MYSQL" /mnt/snap_mysql
rsync -aHAX /mnt/snap_mysql/ "$BACKDIR/mysql/"
umount /mnt/snap_mysql
lvremove -y "/dev/$VG/$SNAP_MYSQL"
echo "=== $(date -Is) backup done"
Замените ввод пароля на безопасный способ (локальный
.my.cnfс правами 0600 или сокет/плагин), а также добавьте уведомления и выгрузку в удалённое хранилище.
Проверка и тест восстановления — обязательны
Бэкап без регулярной проверки — иллюзия безопасности. Делайте периодически пробный restore на отдельном стенде: распакуйте архивы, прогоните проверки целостности (для файлов — контрольные суммы, для MySQL — запуск с настройками по умолчанию и просмотр логов ошибок). Автоматизируйте минимальную проверку на уровне CI: подтверждение, что архив читается, структура каталогов соответствует ожиданиям, объёмы сопоставимы, а на тестовом экземпляре база успешно запускается.
Частые ошибки и как их избежать
- Недооценили размер снапшота — он переполнился и стал невалидным. Увеличивайте с запасом, сокращайте окно жизни снапшота, переносите копирование на менее загруженные часы.
- Забыли
nouuidпри монтировании XFS снапшота — ФС не примонтировалась. Добавьте опцию. - Долго держали FTWRL — приложения простаивали. Отработайте последовательность в тесте: «заморозка» должна занимать секунды.
- Снимали снапшот без
fsfreezeдля чувствительных к метаданным сценариев — получили «грязное» состояние. Добавьте короткий freeze. - Восстанавливали MySQL, но забыли права/контексты — база не стартует. Проверьте владельца
mysql:mysqlи контексты безопасности.
Итоги
LVM snapshots — надёжный и быстрый способ организовать горячий backup на vds для файлов и баз данных. Ключевые элементы успеха: наличие свободного места в VG, краткая и безопасная «заморозка» (fsfreeze), минимальная блокировка в MySQL (FLUSH TABLES WITH READ LOCK), оперативное копирование и немедленное удаление снапшота. Регулярно проверяйте восстановление (restore) и контролируйте заполнение COW‑области — тогда бэкапы будут не только «сняты», но и реально пригодны в критический момент.


