Резервное копирование настроено, задание отрабатывает, файлы в каталоге лежат. На вопрос "а сколько будет восстанавливаться, если сегодня всё умрёт" обычно отвечают словом "быстро". Иногда "часа за два".
Я взял секундомер и проверил. Заодно выяснилось, что у одной из трёх баз резервных копий нет вообще, хотя стадия копирования три месяца отрабатывала зелёным.
Дальше по порядку: сначала числа замера, потом три механизма, каждый из которых по-своему превращал "копия есть" в "копии нет".
Что за стенд и зачем понадобился замер
Три базы трёх смежных систем живут на одной СУБД. Крутится она в контейнере, то есть в изолированном окружении на хосте, которому выделили четыре ядра и 7,8 ГБ памяти. Размеры разные: 23 ГБ, 3,4 ГБ и 597 МБ.
Повод для проверки был скучный и обязательный: надо было назвать бизнесу время восстановления. Требовалось число, за которое можно отвечать, а не диапазон из головы.
Замер сделали честно, но с оговоркой, которую сразу назову, чтобы потом не было претензий: восстанавливали в отдельную базу при работающем проде. То есть это чистое время заливки дампа, без остановки сервисов, без проверки целостности после, без переключения нагрузки. В реальной аварии сверху ляжет ещё и это.
Секундомер
| База | Размер | Дамп | Снятие дампа | Восстановление |
|---|---|---|---|---|
| Первая | 23 ГБ | 1,5 ГБ | 7,5 мин | 19 мин 39 с |
| Вторая | 3,4 ГБ | 296 МБ | - | около 3 мин |
| Третья | 597 МБ | дампа нет | - | - |
Строка третьей базы пустая не потому, что не успели померить. Дампа не существует, мерить нечего. К этому вернёмся отдельно, там самое интересное.
Считаем скорость. Восстановленная первая база заняла 21 ГБ, значит 1,07 ГБ в минуту. Вторая: 3,4 ГБ за три минуты, 1,13 ГБ в минуту.
Вот это совпадение и есть главная ценность замера. Две независимые базы разного размера дали одну и ту же скорость. Значит число не случайное и его можно переносить на другие объёмы. Это уже инструмент оценки, а не байка из моей практики.
Дальше арифметика, от которой становится неуютно:
- база на 100 ГБ едет полтора часа;
- терабайтная база едет пятнадцать-шестнадцать часов;
- трёхтерабайтная - около двух суток.
Вилку в час я оставляю специально: 15 часов получается по быстрой из двух замеренных скоростей, 16 по медленной. Если округлить до круглого гигабайта в минуту, выйдет 17, и вот это округление уже враньё в свою пользу наоборот - оно завышает. Точность тут и не нужна: решение принимается на уровне "полдня или четверть часа", а не "15 или 16".
Это и есть число, которое надо называть бизнесу вместо слова "быстро". Пока его нет, разговор про допустимый простой беспредметен: обе стороны кивают, обе представляют разное.
Оговорка про переносимость: скорость меряна на конкретном железе с четырьмя ядрами, и на быстрых дисках она будет выше. Но порядок величины останется тем же, и решает здесь именно он. Разница между "часа за два" и "пятнадцатью часами" возникает вовсе не из-за железа: просто первое число никто не проверял.
Побочный замер, который пригодится отдельно
Сжатие дампа: первая база 23 ГБ превратились в 1,5 ГБ, это 15,3 раза. Вторая: 3,4 ГБ в 296 МБ, 11,8 раза. Один порядок, разброс объясним долей структурированных данных.
Запомните эти числа, через два раздела они внезапно станут доказательством.
Ещё одна мелочь оттуда же. Восстановленная база оказалась меньше живой: 21 ГБ против 23 ГБ, минус 8,7 процента. Это не потеря данных, это раздувание, которое уходит при перезаливке. Полезно знать, чтобы не пугаться расхождения размеров при сверке.
Дыра первая: копия делалась исправно и не той базы
Теперь про третью базу, у которой в таблице прочерк.
Скрипт резервного копирования в её репозитории существует. Он запускается. Он отрабатывает без ошибок. Стадия в сборке зелёная.
Скрипт этот - копия соседского, снятая когда-то вместе с репозиторием. Имя базы в нём берётся из переменной окружения, а у переменной есть значение по умолчанию, и это имя соседней базы. Сборка третьей системы такую переменную не задаёт, потому что о ней никто не знает.
Итог: стадия "резервная копия" в третьей системе честно снимает дамп соседней базы. Три месяца подряд.
Значение по умолчанию у переменной окружения в инфраструктурном скрипте - вообще самая опасная строка из всех, что там бывают. Она превращает ситуацию "переменная не задана" из громкой ошибки в тихое неправильное поведение. Скрипт не падает, не ругается, не пишет предупреждение. Он делает работу, просто не ту, для которой его позвали.
Как это доказали
Первое доказательство было простым: в каталоге соседней системы обнаружился дамп, помеченный отпечатком коммита третьей. Файл лежит не там, где должен, и назван так, что видно, кто его положил.
Доказательство рабочее, но слабое. Совпадение имён всегда можно объяснить чем-то ещё: не тот шаблон имени, кто-то руками перенёс, старая версия скрипта.
Сильное доказательство даёт арифметика по степени сжатия, и оно не требует ничего, кроме размеров файлов:
- наблюдаемый дамп весит 302 МБ;
- дамп соседней базы (3,4 ГБ) весит 296 МБ, разница 2 процента - то есть это та же база, снятая сутки спустя;
- если бы дампилась третья база (597 МБ) при сжатии хотя бы 11,8 раза, дамп весил бы около 50 МБ;
- наблюдаемые 302 МБ больше ожидаемых в шесть раз.
Дамп не может быть в шесть раз больше, чем позволяет исходный объём. Это не аргумент про имена файлов и не рассуждение про то, кто что настроил. Это про физику: столько данных там просто неоткуда взять.
Приём переносимый, и я советую унести его к себе. Знаете типичную степень сжатия своих дампов - можете за минуту проверить, ту ли базу вы копируете. Размер файла делите на размер базы и сравниваете с привычным. Отклонение в разы означает, что копируется что-то другое. Сама по себе база лучше сжиматься не начинает.
И следующий шаг из того же наблюдения: дамп, который внезапно стал заметно меньше вчерашнего, это повод остановить выкатку. Строкой в логе тут не обойтись. Уменьшение обычно значит, что часть данных в копию не попала.
Дыра вторая: откат целится в чужой прод
Раз скрипты копирования разъехались, я пошёл смотреть скрипты отката. Там оказалось хуже.
Копирование пишет дамп в каталог с суффиксом имени базы. Откат читает из корня без суффикса. Две половины одного механизма разошлись на один уровень каталога, и этого достаточно, чтобы откат взял чужой файл.
Дальше складываем со значениями по умолчанию, которые лежат в том же скрипте: корень каталога копий указывает на базу первой системы, восстановление настроено в базу второй, корень проекта - тоже второй.
Складывается сценарий, который я не хочу видеть ни у себя, ни у вас. Откат с включённым восстановлением базы, запущенный из сборки третьей системы, погасит контейнеры второй системы и зальёт дамп первой поверх её прода. Три системы, ни одна из них не та, из которой нажали кнопку.
Не выстрелило только потому, что кнопка ручная и её ни разу не нажимали в такой комбинации. То есть спасла нас статистика. Защиты никакой не было.
Отсюда правило, которое стоит один вечер работы: скрипт восстановления обязан отказываться работать, если имя целевой базы не задано явно. Не подставлять умолчание, не брать из соседней переменной, а останавливаться с текстом "скажи, куда лить". Умолчание в скрипте копирования стоит одной потерянной копии. Умолчание в скрипте отката стоит чужого прода.
И проверка на пять минут для тех, у кого несколько похожих связок: возьмите скрипт копирования и скрипт отката одной системы и сравните, как каждый из них собирает путь. Если пути собираются разными строками кода - рано или поздно они разъедутся. Здесь они разъехались на суффикс каталога, и никто этого не заметил, потому что копирование работало правильно.
Дыра третья: восстановиться на вчерашний вечер нельзя
Третий механизм скучнее двух предыдущих, зато он есть у большинства.
Ежедневное задание копирования настроено только у первой базы. У двух других копия снимается перед выкаткой, и всё. Архивирование журнала транзакций выключено, реплик нет.
Это значит, что восстановление на момент времени невозможно в принципе. Не "сложно" и не "долго". Просто нечем: чтобы доехать до вчерашних семи вечера, нужен непрерывный журнал, а его никто не пишет.
Считаем допустимую потерю по каждой базе:
| База | Что есть | Сколько данных теряем |
|---|---|---|
| Первая | ежедневная копия | до суток работы |
| Вторая | копия перед выкаткой | всё с последней выкатки |
| Третья | ничего | вся история |
Про третью строку стоит сказать прямо, потому что она читается легче, чем есть на самом деле. "Вся история" означает, что при потере диска система начинается с чистого листа.
Часть данных не восстанавливается ничем
Здесь начинается то, о чём при разговорах про резервные копии обычно не думают.
Часть таблиц наполняется из внешних систем, и это привычно считают безопасным: ну и что, перекачаем. Так вот, перекачать можно только то, что внешняя система отдаёт задним числом. А отдаёт она текущее состояние.
В разобранных базах к невосстановимому относится:
- собственный журнал решений робота: почему он в такой-то день выбрал такое-то действие;
- срезы цен конкурентов на каждый день;
- история рейтингов;
- история остатков.
Ни один внешний источник ретроспективу не отдаст. Сегодняшние цены - пожалуйста, вчерашние - уже нет.
Из того, что удалось посчитать по размерам, безвозвратного набралось 2,6 ГБ, около 11 процентов первой базы. У остальных таких таблиц размеры не назывались, значит реальная доля выше.
И вот здесь неприятная закономерность. Хуже всего с копиями именно у тех систем, где данные существуют в единственном экземпляре. Логика понятная: аналитическая надстройка выглядит вторичной, "там же ничего своего нет". А своего там как раз больше всего, потому что она годами копила то, что нигде больше не хранится.
Проверка для вашей базы делается за один заход и не требует инструментов. Пройдите по крупным таблицам и на каждую ответьте на один вопрос: если её сегодня не станет, откуда я возьму данные за прошлый март? Таблицы, на которых ответа нет, и есть ваш настоящий предмет резервного копирования. Всё остальное перезальётся.
Почему все три дыры оказались в одном месте
Причина общая, и она названа точно: три репозитория клонировались друг из друга.
Так делают все и правильно делают: зачем писать сборку заново, если рядом лежит рабочая. Дальше прикладной код расходится, живёт своей жизнью, обрастает правками. А инфраструктурные скрипты остаются одинаковыми и продолжают указывать на исходную систему.
Хуже всего то, что расхождения не видно ни в одном сравнении версий, потому что сравнивать нечего: файл никто не менял. Он был скопирован правильным и остался правильным для той системы, откуда его взяли.
Это отдельный класс дефектов, и он не ловится ни ревью, ни линтером, ни тестами. Ловится он одной проверкой, которую надо делать руками и раз в полгода: открыть каталог резервных копий и посмотреть, лежит ли там файл нужной базы нужного размера.
Не статус задания, не зелёная стадия в сборке, не запись в журнале. Файл, имя, размер, дата. Всё остальное говорит вам о том, что скрипт отработал, и ничего не говорит о том, что он сделал.
Мелочь, которая испортит вам оценку сроков
Отдельно про то, обо что легко споткнуться при планировании работ с большими таблицами.
Системная статистика по числу строк в самой большой таблице показывала 688 тысяч. Реально там 20 миллионов строк. Занижение в 29 раз.
Такие счётчики обновляются по своим правилам и после массовых операций расходятся с фактом надолго. Если по ним оценивать объём работы, ошибка будет на порядок, а не на проценты: планировали разобрать таблицу за час, а она едет двое суток.
Проверка простая: перед оценкой посчитать строки прямым запросом хотя бы на одной крупной таблице и сравнить с тем, что показывает статистика. Разошлось в разы - дальше верить статистике нельзя нигде.
Кстати, о правдоподобии: 20 миллионов строк в 13 ГБ дают около 650 байт на строку. Для документа с текстовыми полями нормально. Такую проверку полезно делать всегда, когда число выглядит подозрительно большим или маленьким: если байт на строку получается три или тридцать тысяч, значит вы посчитали не то.
Чего этот замер не показал
Границы называю честно, потому что без них любой замер превращается в рекламу.
Восстановление под нагрузкой не мерили. Заливали в отдельную базу при работающем проде. Восстановление прода вместо прода добавит остановку сервисов, проверку после заливки и переключение нагрузки, и добавит непредсказуемо.
Читаемость дампов не проверена. Из всех имеющихся файлов восстановлением проверен ровно один, тот, что в таблице. Про остальные известно только то, что они лежат и весят сколько-то. Файл в каталоге не доказывает, что он восстановится: битый архив выглядит на диске точно так же, как целый.
Ни одна из трёх дыр на момент разбора не исправлена. Разбор кончился отчётом. До починки дело не дошло, и это тоже часть честной картины.
По совести, из всего перечисленного самая неприятная строка вторая. Про отсутствие копий у третьей базы хотя бы известно. Про читаемость остальных дампов не известно ничего, и узнать это можно ровно одним способом - попробовать восстановить. В тот день, когда файл понадобится по-настоящему, пробовать будет поздно.
Что стоит проверить у себя на этой неделе
Порядок от самого дешёвого к самому дорогому.
- Откройте каталог копий и посмотрите на файлы. Имя базы, размер, дата. Сравните размер с ожидаемым по вашей обычной степени сжатия. Это пять минут и ловит подмену базы целиком.
- Сравните, как собирают путь скрипт копирования и скрипт отката. Разными строками кода - значит однажды разъедутся.
- Найдите в скриптах все значения по умолчанию, где стоит имя базы, каталога или сервера. Каждое такое умолчание однажды сработает не там.
- Восстановите одну копию и засеките время. Получите своё число гигабайт в минуту и сможете умножить его на размер любой своей базы.
- Пройдите по крупным таблицам с вопросом "откуда я возьму эти данные за прошлый март". Список таблиц без ответа и есть то, ради чего вообще нужны копии.
Первые три пункта делаются за один вечер и не требуют ни согласований, ни окна. Четвёртый требует места на диске. Пятый требует головы, и он самый полезный.
Другие наши инструменты:
- Тестовая база сама обновляется из свежего прода - разворачивает копию рабочей базы по расписанию. Побочная польза ровно про эту статью: каждый прогон и есть проверка того, что дамп читается.
- Диагностика журнала транзакций - показывает, что мешает журналу освободиться. Тот самый журнал, без которого восстановление на момент времени невозможно.
- Карта объёмов базы 1С - из чего база состоит и какие таблицы дают ей размер. Время восстановления считается от гигабайтов, а гигабайты обычно лежат в двух-трёх таблицах.
- Чек-ап СУБД под 1С - настройки сервера, включая модель восстановления и обслуживание. Смотреть до того, как понадобится копия.
Спорное, и я на этом настаиваю не до конца
Про восстановление на момент времени у меня нет твёрдой позиции, и я честно скажу почему.
С одной стороны, непрерывный журнал стоит денег: место, настройка, регулярная проверка, что цепочка не порвана. Для вспомогательной системы, где потеря дня работы означает "робот пересчитает", это может быть избыточным. Бизнес про такую возможность не просил, и никто не мешает признать это осознанным выбором.
С другой стороны, разница между "теряем до суток" и "теряем всё с последней выкатки" - это разница между неприятностью и катастрофой, и стоит она одного включённого режима восстановления.
Что я знаю точно: решение должно быть названным. Здесь оно не было принято, оно сложилось само из того, что у одной базы задание настроили, а у двух других руки не дошли. Это не выбор, это отсутствие выбора, замаскированное под нормальную работу.
А теперь вопрос, ради которого я это пишу. У вас наверняка есть системы, где копии снимаются перед выкаткой и больше никогда. Вы это когда-нибудь называли вслух и записывали как решение, или оно у вас тоже просто сложилось? И если называли, чем закончился разговор с бизнесом про допустимую потерю: он согласился на сутки или попросил меньше, а платить за это отказался?
Мне интересны обе стороны, особенно те случаи, когда именно эта договорённость однажды сработала и кто-то за неё отвечал.
Вступайте в нашу телеграмм-группу Инфостарт