Про бэкапы все знают, что они нужны, и почти все считают, что они есть. Выясняется это обычно в неудачный день: сайт после обновления не поднимается, в базе половина заказов, и выясняется, что копия делалась — но только базы, только раз в неделю и прямо на тот же диск, который и отказал. Разберём, что входит в полноценную копию магазина, где её держать и как убедиться, что из неё действительно можно восстановиться.
Что входит в копию магазина
Бэкап — это не «архив папки сайта». Сайт состоит из нескольких слоёв, и у каждого своя судьба при восстановлении.
- База данных — заказы, пользователи, каталог, настройки; то, без чего восстанавливать нечего
- Загруженные файлы — картинки товаров, документы, вложения из заявок; их нет ни в git, ни в базе
- Код — должен лежать в репозитории, и тогда в бэкапе не нужен; если репозитория нет, нужен
- Конфигурация окружения — файл с переменными, ключи платёжного шлюза, токены интеграций
- Конфиги сервера — nginx, пулы PHP-FPM, systemd-юниты очередей, задания cron
- Сертификаты и настройки почты — восстанавливаются быстро, но без них магазин не продаёт
Про загруженные файлы забывают чаще всего, потому что они лежат отдельно от кода. В магазине с десятью тысячами товаров это десятки гигабайт, и если они восстановились наполовину, каталог выглядит сломанным даже при целой базе. Если картинки приезжают обменом из учёта, их можно перелить заново — но это часы, и об этом лучше знать заранее, а не выяснять в процессе.
Конфиги сервера — вторая по частоте потеря. База и файлы восстановились, а магазин не работает, потому что никто не помнит, какие лимиты PHP были выставлены под обмен с 1С и как именно был настроен воркер очереди. Эти файлы маленькие, и включить их в копию стоит нисколько.
Проверка полноты бэкапа простая: можно ли по нему поднять работающий магазин на чистом сервере, не вспоминая ничего по памяти. Если нужно что-то вспоминать — копия неполная.
База: как снимать правильно
Для MySQL и MariaDB с таблицами InnoDB дамп снимается так: mysqldump --single-transaction --quick --routines --triggers --events. Разберём флаги, потому что каждый добавлен не для красоты.
--single-transaction делает согласованный снимок внутри одной транзакции и не блокирует запись. Без него дамп большой базы блокирует таблицы на всё время выгрузки — для магазина это значит, что в эти минуты никто не может оформить заказ. --quick выгружает построчно, не держа результат в памяти целиком. --routines --triggers --events добавляют процедуры, триггеры и планировщик: без них дамп восстановится, но часть логики пропадёт молча.
Дамп сразу сжимают: mysqldump ... | gzip > dump.sql.gz. База магазина в сыром виде занимает в несколько раз больше, чем в архиве, и на хранении это ощутимо.
Когда база переваливает за несколько десятков гигабайт, логический дамп перестаёт быть удобным: он долго снимается и очень долго восстанавливается. Тогда переходят на физические копии — xtrabackup или mariabackup, которые копируют файлы данных и умеют инкрементальные снимки. А если нужно уметь откатываться не на сутки назад, а на конкретную минуту до неудачного обновления, включают бинарные логи: ночной полный снимок плюс бинлоги дают восстановление на любой момент. Это уже уровень администрирования сервера, а не однострочника в cron, но для магазина с большим потоком заказов оправдано.
Куда складывать
Единственное место, где копия не является копией, — тот же сервер. Диск отказал, сервер разблокировали за неоплату, провайдер потерял виртуалку, кто-то выполнил удаление не в той директории — во всех этих сценариях локальный архив исчезает вместе с сайтом.
Рабочая схема — три копии, два носителя, одна вне площадки: локальная копия для быстрого откатa, копия в объектном хранилище другого провайдера и, если данные критичные, третья в ещё одном месте. Для небольшого магазина это два пункта из трёх, и даже этого достаточно, чтобы отличаться от большинства.
Отдельно про права доступа. Если сервер сам пишет копии в хранилище и у него есть права на удаление, то компрометация сервера означает потерю и сайта, и всех архивов — первое, что делает шифровальщик, это чистит бэкапы. Поэтому ключ доступа выдают только на запись и чтение, без удаления, а на стороне хранилища включают неизменяемость объектов на срок хранения. Это одна настройка, и она превращает бэкап из формальности в реальную страховку.
И архивы шифруют. В копии базы магазина лежат телефоны, адреса и история заказов покупателей — то есть персональные данные, которые нельзя хранить в открытом виде на чужом диске.
Как часто и сколько хранить
Два вопроса, на которые отвечает владелец магазина, а не администратор: сколько данных допустимо потерять и сколько времени допустимо лежать.
Первый определяет частоту копий. Если бэкап снимается раз в сутки, в худшем случае теряются сутки заказов. Для магазина с десятком заказов в день это неприятно, но переживаемо: заказы можно восстановить из писем и CRM. Для магазина с сотнями заказов это катастрофа, и там базу копируют чаще или держат бинарные логи.
Второй определяет способ хранения. Поднять магазин из сжатого дампа на новом сервере — это часы: установить окружение, развернуть код, залить базу, перелить картинки, настроить домен и сертификат. Если простой дольше нескольких часов недопустим, нужен не только бэкап, но и заранее подготовленный резервный сервер.
Схема хранения, которая закрывает большинство случаев: семь ежедневных копий, четыре недельных, шесть месячных. Ежедневные — для «сломали вчера». Недельные — для «сломали и заметили через неделю». Месячные — для случаев, когда нужно посмотреть, как данные выглядели до давнего изменения. Удаляются старые копии автоматически, иначе хранилище кончится в самый неподходящий момент.
Главное: проверка восстановления
Бэкап, из которого ни разу не восстанавливались, — это предположение о бэкапе. Причины, по которым архив оказывается нерабочим, скучные и встречаются постоянно:
- Дамп обрывается на середине, потому что на диске кончалось место, а код ошибки никто не проверял
- Копируется база, но не папка с загруженными файлами
- Копируется база сайта, но не база соседнего сервиса, от которой он зависит
- Архив шифрован, а ключ лежит на том же сервере, который потерян
- Задание в cron сломалось два месяца назад, последняя копия от июля
- Копия есть, но восстанавливать её не умеет никто из доступных людей
Все шесть пунктов обнаруживаются одной процедурой: раз в квартал копия поднимается на отдельный сервер или тестовый домен, и по ней проверяется, что магазин открывается, в каталоге есть товары, в админке видны последние заказы, картинки на месте. Занимает это полдня, и это единственный способ узнать состояние бэкапов до того, как они понадобятся.
Тестовую копию при этом обязательно закрывают от индексации на уровне сервера — паролем, а не строчкой в robots.txt. Иначе через месяц в выдаче обнаружится дубль магазина на техническом домене, и это уже отдельная проблема.
Уведомление надо настраивать не на ошибку, а на успех. Скрипт, который молчит при падении, выглядит точно так же, как скрипт, который работает. Отсутствие письма «копия снята, размер такой-то» — это и есть сигнал.
Порядок восстановления
Когда момент наступил, действуют по шагам, а не по памяти:
- Остановить обработку: выключить приём заказов и воркеры очередей, чтобы не плодить данные поверх битых
- Снять копию текущего состояния, даже сломанного — к ней ещё придётся возвращаться
- Понять точку возврата: на какой момент восстанавливаемся и что в этом интервале теряется
- Развернуть код из репозитория на нужном коммите
- Восстановить базу, затем загруженные файлы, затем конфиги и cron
- Проверить ключи интеграций: платёжный шлюз, обмен с учётом, CRM, почта
- Прогнать сквозной сценарий: открыть каталог, положить товар в корзину, оформить тестовый заказ, получить письмо
- Включить приём заказов и очереди, посмотреть логи первые полчаса
Шестой пункт — тот, на котором спотыкаются. Восстановленный магазин технически работает, но платежи не проходят, потому что в конфиге оказался тестовый ключ эквайринга из старой копии. Проверять интеграции нужно до того, как на сайт пустят покупателей.
И отдельный пункт, который не относится к восстановлению, но относится к последствиям: если магазин лежал больше нескольких часов, об этом стоит знать не только техническим людям. Реклама в это время расходует бюджет на страницы, которые не открываются, — кампании на время простоя останавливают. Это такая же часть поддержки сайта, как и сам откат.
Чек-лист
- В копию входят база, загруженные файлы, конфиги окружения и сервера, задания cron
- База снимается с --single-transaction и не блокирует заказы
- Есть копия вне сервера, у сервера нет прав удалять её из хранилища
- Архивы шифруются, ключ хранится отдельно от сервера
- Ротация настроена и старые копии удаляются сами
- Приходит уведомление об успешном снятии, а не только об ошибке
- Раз в квартал делается тестовое восстановление, закрытое паролем
- Порядок восстановления записан и доступен не одному человеку
Мы настраиваем резервное копирование магазинов, выносим архивы за пределы сервера, делаем проверочные восстановления и держим записанный порядок действий на случай аварии. Что входит в работу, смотрите на странице администрирования серверов. Если сервер только выбирается под новый проект, бэкапы закладываются вместе с остальной конфигурацией — об этом мы писали в разборе серверов для интернет-магазина.