Иллюзия контроля: Как я сам уничтожил бэкапы, или Хроника одного пятничного безумия

Когда ты сам администрируешь свою серверную инфраструктуру, ты не просто арендуешь абстрактные вычислительные мощности. Ты берешь на себя полную, единоличную ответственность за каждый физический сектор на магнитных пластинах, за каждый вольт на шине питания под нагрузкой и за каждый байт данных, проходящий через кольца ядра операционной системы. В этой жесткой схеме нет места «технической поддержке» или «тикет-системам». Если всё работает идеально — тебя никто не замечает. Если всё рушится — ты остаешься один на один с ледяным мерцанием курсора в пустой консоли SSH в три часа ночи.

Вчера инфраструктура ушла в глубокий, беспросветный офлайн. Итог запланированной миграции на новое выделенное железо — тотальный, абсолютный провал. На домене висела глухая заглушка 503 — памятник моей собственной поспешности, идиотской избыточной самоуверенности и глупости. Да, я далеко не новичок в системном администрировании. Я прекрасно знаю все базовые принципы построения отказоустойчивых систем, наизусть помню правила резервного копирования и регулярно учу других, как надо делать правильно. Но в этот раз я умудрился похерить абсолютно всё, нарушив каждый существующий канон безопасности и эксплуатации.

Сегодня, когда дисковые массивы наконец досинхронизировались, а базы данных перестали плеваться ошибками целостности, я готов выдать полную, неприкрытую хронику этой катастрофы. Это честный инженерный разбор того, как поспешность превращает терабайты данных в цифровой мусор, как ломается человеческая логика и как выглядит процесс «хирургической» реанимации ядра системы, когда пути назад физически не существует.

Глава 1: PROTOCOL IMMORTALITY. Идеальная система, работавшая до пятницы

Чтобы понять глубину моего провала, нужно знать, как система работала до пятницы. У меня была выстроена жесткая, параноидальная схема бэкапов, основанная на философии утилиты tar. Это стратегия максимальной выживаемости: никаких проприетарных форматов, никаких зависимостей от Borg, Veeam или Bacula. Только чистый архив, который можно будет распаковать хоть через двадцать лет на любой Unix-подобной системе.

Архитектура базировалась на связке Master -> Slave (Источник -> Склад) через SSH-туннель с ключами Ed25519. Скрипт backup.sh решал ключевую проблему — атомарность баз данных. Перед тем как tar начинал собирать файловую систему, mysqldump делал текстовый слепок SQL-баз, исключая вероятность попадания битых транзакций в архив.

Всё работало как швейцарские часы:

  1. В воскресенье создавался полный (Full) бэкап.
  2. В будние дни tar создавал инкременты, опираясь на файл-метаданных .snar.
  3. Массивный архив отправлялся по SCP на удаленный Склад.
  4. На Складе отрабатывал скрипт clean.sh, соблюдавший 30-дневный Retention Policy.

Система была прозрачной, масштабируемой и абсолютно надежной. И я сам же её уничтожил одним нелепым решением.

Глава 2: Анатомия глупости. Пятничный компромисс и список исключений

Сервер phoenix901 готовился к переезду на новую физическую площадку. Мне показалось, что регулярные полные архивы стали слишком тяжелыми, а процесс их передачи по сети — неоправданно громоздким. И вот тут я совершил фатальную ошибку, которую сейчас вообще невозможно объяснить здравым смыслом.

В моей системе tar был настроен на жесткую фильтрацию через файл backupexclude.txt. Там находились системные директории (/proc, /sys, /dev, /run), которые привязаны к железу, логи и сами архивы, чтобы избежать рекурсии. Это логично. Это правильно.

Но в прошлую пятницу я открыл этот файл и вписал туда *.sql. Я исключил дампы баз данных из автоматической архивации. В моей голове щелкнула абсолютно дебильная, самонадеянная мысль: «Ладно, сейчас временно уберу базы из общего таска, чтобы сэкономить место на транзитном накопителе и ускорить упаковку, а перед самым отключением старого сервера зайду в консоль и заберу актуальные дампы вручную в один клик через mysqldump». Запомните этот момент: опытный администратор понадеялся на свою память и нарушил автоматизированный процесс ради сиюминутного удобства. Это первый шаг в бездну.

Глава 3: Понедельник. Ротация как приговор

Наступил понедельник — день, когда на удаленном бэкап-хранилище планово срабатывает скрипт ротации резервных копий. Скрипты отработали строго по расписанию. Старые, тяжелые, но консистентные копии, содержавшие полные слепки баз данных, были безжалостно удалены согласно правилам хранения. Их место заняли новые, «оптимизированные» пятничные архивы. Чистые, компактные, быстрые — и абсолютно пустые внутри с точки зрения данных SQL.

В консоли мониторинга горел заветный зеленый статус. Логи выполнения резервного копирования я прочитал по диагонали, обратив внимание только на код завершения процесса (Exit Code 0). Файлы создаются, размер архива измеряется сотнями гигабайт, права доступа корректны. То, что внутри этого монолита больше нет структуры таблиц блога и метаданных облака, система мониторинга знать не могла — она проверяла лишь факт успешного создания тарбола. Логика человеческого контроля дала сбой.

Глава 4: Вторник. Поспешность, депровижнинг и точка невозврата

Вчера начался процесс миграции. В этот момент у меня включился режим полной амнезии. Я напрочь забыл о манипуляциях с backupexclude.txt, которые совершил в пятницу. В моей голове была железобетонная уверенность в том, что бэкап крутится по старой, проверенной схеме — со всеми базами данных, конфигурациями пользователей и системными таблицами внутри.

План переноса казался простым и быстрым. Спешить было абсолютно некуда. Я дождался, пока шкала загрузки архива на локальный диск доползла до 100%. Архив весом под 180 гигабайт скачался без ошибок. И здесь я совершаю вторую критическую ошибку, за которую любого младшего администратора увольняют в тот же день без выходного пособия: я удалил старый сервер ровно через минуту после окончания скачивания файла контента.

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

Спустя десять минут на новом сервере я запускаю распаковку тарбола. Терминал бодро выплевывает строки структуры директорий, процесс завершается успешно. Я перехожу в каталог /var/lib/mysql внутри распакованного куска… и в этот момент внутри меня всё холодеет. Там пусто. Ни единого файла баз данных. Актуальных дампов SQL в архиве не было физически. Они остались на тех самых дисках старого сервера, которые минуту назад прекратили свое существование. Я лезу на бэкап-сервер в надежде вытащить старые копии, но понедельничная ротация уже сделала свою работу — всё зачищено. На домене крутится 503, инфраструктура превратилась в «тыкву», пути назад нет.

Глава 5: Операция «Реанимация». Цифровая археология

Состояние полной потери данных — это отличный холодный душ для эго. Я перевернул все локальные накопители в поисках хоть какого-то слепка баз. Единственное, что удалось обнаружить в закромах — старый SQL-дамп, датированный аж июлем прошлого года. Почти год разрыва.

Я развернул этот июльский дамп в пустую базу MariaDB. Сайт блога поднялся, но на него было больно смотреть — это был призрак из прошлого. Исчезли десятки публикаций, плагины, настройки и комментарии.

И тут произошло то самое совпадение, которое спасло текстовую часть проекта. В прошлую пятницу, прямо перед безумными экспериментами со скриптами архивации, я ковырялся в админке WordPress. И чисто на автомате зашел в инструменты и выкачал стандартный XML-файл полного экспорта сайта. Зачем? Логического ответа нет. Просто выкачал и бросил в папку загрузок.

Этот XML-файл от 22 мая стал хирургическим скальпелем. Я запустил встроенный импортер WordPress поверх живой, но откатившейся на год назад июльской базы данных. Движок отработал штатно, используя механизм Upsert: он сверял уникальные GUID постов, игнорировал существующее и аккуратно дописывал недостающие статьи и метаданные. Посты возвращались в консоль один за другим, восстанавливая хронологию. Текстовая часть блога была полностью восстановлена.

Глава 6: Война с Nextcloud и магия OCC

С Nextcloud началась позиционная война. База от июля и свежие физические файлы пользователей категорически отказывались работать вместе. Система ушла в глухую защиту. Реанимация шла строго по шагам командной строки:

  • Остановка внешних запросов: Принудительная остановка Apache и PHP-FPM для прекращения конкурентных запросов и дедлоков в базе.
  • Синхронизация структуры базы (Upgrade): Выполнение команды sudo -u www-data php /var/www/html/nextcloud/occ upgrade для перестроения индексов июля под требования новой версии ядра.
  • Принудительное перестроение кэша (Files:scan): Использование occ files:scan --all заставило систему принудительно пересчитать физические файлы и перезаписать индексы в oc_filecache. 4117 файлов были возвращены в строй с нулевым количеством ошибок.

Для пользователей, созданных после июля (например, user), пришлось вручную воссоздавать учетные записи через CLI (sudo -u www-data php occ user:add --display-name=user --email=user@example.com user), переносить файлы, применять жесткие права (chown -R www-data:www-data) и запускать персональный рескан. База приняла файлы, и старые данные отобразились в интерфейсе.

Глава 7: Физика дисков и невосполнимые потери

Параллельно со всеми манипуляциями массив md2 (RAID-1) встал на полную синхронизацию (resync). Одновременное линейное чтение/запись и тысячи мелких I/O-операций обрушили скорость до 70-90 МБ/с. Система ушла в жесткий I/O Wait, контроллер грелся, но диски выдержали. На отметке 92.3% массив стабилизировался и завершил ребилд.

Но чуда не случилось. В остальном все файлы и данные пользователей на месте, но есть одна безвозвратная потеря этой катастрофы — **база рассылки дайджестов**.

Таблица подписчиков, конфигурации триггеров и история отправлений лежали в отдельной локальной базе данных, которая не экспортировалась через XML и отсутствовала в июльском дампе. Она стерта вместе со старым сервером и не подлежит восстановлению. Всем моим читателям, которые получали дайджесты, **нужно переподписаться заново**.

Выводы. Железный стандарт эксплуатации

Проект Phoenix901 жив, но этот инцидент заставил меня пересмотреть свои принципы. Если ты совершаешь ошибку — ты обязан изменить систему так, чтобы человеческий фактор больше никогда не смог её сломать.

Что сделано и как мы будем жить дальше:

  • Тотальный возврат баз данных: Дампы БД принудительно возвращены в скрипты архивации. Файл backupexclude.txt больше не содержит исключений для SQL-файлов. Никаких «временных» компромиссов.
  • Тестовый стенд восстановления: Развернут изолированный тестовый стенд (стейджинг), идентичный боевому серверу. Любой процесс миграции или обновления будет проходить предварительную обкатку там.
  • Новый стандарт цепочки бэкапов: Полное резервное копирование (Full Backup) — строго раз в неделю. Остальное время — инкременты. Цикл сбрасывается только после того, как полная цепочка верифицирована на хранилище.
  • Верификация при сбросе цепочки: Каждый раз при сбросе цепочки будет проводиться ручная верификация и тестовое развертывание чистого фулл-бэкапа на стейджинге. Депровижнинг старых серверов — только после успешной валидации.

Железо не прощает спешки. Логи не прощают невнимательности. Я заплатил сутками работы на грани полной потери данных за свою поспешность. Мы в строю, фундамент обновлен, выводы сделаны. Переподписывайтесь на дайджест. Движемся дальше.

👁️ 9

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

девятнадцать − восемь =

root@phoenix901:~# connect
[×]

Получай дайджест раз в неделю.
Без спама.