АйТи Фреш
Главная / Статьи / Серверы и хостинг
Серверы и хостинг

Proxmox Backup Server нашёл повреждённые снимки, а обычный Sync их не лечит: как работает resync-corrupt

Автор: Семёнов Евгений Сергеевич, директор ООО «АйТи-Фреш» · · ~22 мин чтения
Proxmox Backup Server нашёл повреждённые снимки, а обычный Sync их не лечит: как работает resync-corrupt
Иллюстрация к статье «Proxmox Backup Server нашёл повреждённые снимки, а обычный Sync их не лечит: как работает resync-corrupt».

У вас два Proxmox Backup Server: основной в серверной и резервный на другой площадке. Sync между ними который месяц горит зелёным. А потом вы запускаете Verification на резервном — и получаете три десятка снимков в статусе failed. Запускаете Sync ещё раз, надеясь, что он перекачает битое. Он отрабатывает за семь минут и снова зелёный. Не исправилось ничего. Разбираю, почему так устроено, что именно делает опция resync-corrupt, в каком порядке всё запускать, сколько это занимает по времени — и что делать, если повреждение оказалось не только на приёмнике.

Обычный Sync не перекачивает то, что у него формально уже есть

Начну с механики, потому что без неё всё остальное выглядит как магия. Sync-задание в PBS работает по группам бэкапов. Для каждого снимка оно скачивает с источника манифест — файл index.json — и сравнивает его с локальным манифестом. Если байты совпали, задание пишет в лог no data changes, закрывает снимок и идёт дальше. Ни индексные файлы, ни chunks оно при этом не трогает. И правильно делает: именно на этом сравнении держится вся экономия трафика, ради которой офсайт-копию вообще имеет смысл делать по узкому каналу.

Теперь вторая половина картины. Когда Verification находит повреждённый chunk, она его не оставляет лежать как есть. Chunk переименовывается — в исходниках это rename_corrupt_chunk, в логе задачи вы увидите строку вида corrupt chunk renamed to ..., на диске получается файл с суффиксом .bad рядом с исходным именем в каталоге .chunks. То есть кусок данных физически перестаёт существовать под своим цифровым отпечатком. В хранилище образуется дырка.

Сложите одно с другим. Манифест снимка не изменился ни на байт — он и не мог измениться, порча произошла в данных, а не в метаданных. Значит, Sync честно говорит no data changes и не скачивает недостающий chunk. Снимок на приёмнике остаётся в том же состоянии: манифест на месте, индексы на месте, одного куска данных нет. Он проходит синхронизацию и не проходит восстановление. Это худший из возможных сценариев, потому что вы узнаете о нём в тот момент, когда бэкап уже нужен.

Именно поэтому я не считаю зелёный Sync доказательством того, что резервная копия жива. Sync — это про доставку. Про целостность — только Verification, и только та, которую вы запустили на самом приёмнике, а не на источнике.

Зелёная галочка на Sync не означает, что копия восстановится. Она означает только то, что метаданные на двух серверах совпали. Пока вы не прогнали Verification на приёмнике — вы не знаете о своём аварийном резерве ничего.

Что делает resync-corrupt и почему он такой медленный

В документации PBS формулировка предельно короткая: включение расширенной опции resync-corrupt заставляет задание повторно синхронизировать все снимки, которые не прошли последнюю Verification. Опция появилась в PBS 3.3 (28 ноября 2024 года) — в том же релизе, где у sync-заданий появилось направление push, — и в текущей ветке 4.2 (апрель 2026) логика её работы та же. В конфигурации задания это булево свойство resync-corrupt, в справке оно описано одной фразой: если верификация локального снимка провалилась, попытаться стянуть его ещё раз. По умолчанию она выключена — и это осознанное решение разработчиков, а не недосмотр.

Работает это так. Результат проверки снимка PBS сохраняет прямо в манифесте, в незащищённой секции: manifest.unprotected["verify_state"]. Значений там три состояния, и от них зависит поведение sync-задания. Если verify_state равен Failed — снимок помечается на повторную выкачку. Если манифест вообще не читается (а это тоже симптом повреждения) — снимок тоже идёт на повторную выкачку, логика в исходниках прямо прокомментирована как «была ошибка загрузки манифеста, лучше пересинхронизировать». А вот если поля verify_state в манифесте нет — то есть снимок ни разу не проверялся — resync-corrupt его проигнорирует. Он не перепроверяет данные, он читает вердикт, вынесенный до него.

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

И отдельно то, обо что спотыкаются чаще всего: resync-corrupt доступен только для pull-заданий. Направление задаётся свойством sync-direction (pull по умолчанию или push), и для push флага нет. Push к тому же устроен иначе по правам и владению: содержимое на удалённой стороне всегда принадлежит пользователю из настроек remote, требуются Remote.Audit и Remote.DatastoreBackup, а удалённый PBS должен быть не старше 2.2 с поддержкой пространств имён. Инженер Proxmox в форумной ветке про массовые verify failed прямо это проговаривает: если есть возможность тянуть с источника, настройте pull-задание, потому что в нём можно выбрать флаг повторной синхронизации повреждённых, а в push — нельзя. Если у вас офсайт-копия организована пушем с основного PBS на резервный, то для лечения придётся временно поднять pull-задание с обратной стороны.

Ключевой вывод: resync-corrupt не ищет повреждения. Он исполняет приговор, вынесенный Verification. Без предварительной проверки на приёмнике флаг не сделает ровным счётом ничего — задание отработает и честно доложит, что чинить нечего.
Proxmox Backup Server нашёл повреждённые снимки, а обычный Sync их не лечит: как работает resync-corrupt — схема
Схема к статье. Открыть схему в полном размере

Правильный порядок: сначала Verification на приёмнике, потом Sync

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

Верификацию удобнее делать заданием, а не разовой командой: у verify-job есть два параметра, ради которых он и существует. ignore-verified пропускает снимки, уже успешно проверенные ранее, а outdated-after задаёт срок, после которого проверенный снимок считается устаревшим и проверяется заново. В PBS 4.1 (ноябрь 2025) добавили настройку параллелизма верификации: read-threads и verify-threads, диапазон от 1 до 32, по умолчанию один поток чтения и четыре потока проверки. На HDD-массиве увеличение потоков чтения обычно делает только хуже — головки и так пилят случайный доступ по 65 536 подкаталогам.

Дальше — само задание. Флаг можно щёлкнуть в веб-интерфейсе (Datastore → Sync Jobs → Advanced), но я предпочитаю CLI, потому что его видно в истории и можно положить в скрипт. Полная последовательность — во врезке этого раздела: сначала verify-задание на приёмнике, потом включение флага через proxmox-backup-manager sync-job update и ручной запуск, в конце флаг снимается.

Отдельно проверьте область действия задания. Если у вас в нём стоит group-filter, ограничение глубины пространств имён через max-depth или transfer-last (синхронизировать только N последних снимков в группе), то resync-corrupt вылечит ровно то, что попадает в фильтр. Битые снимки за пределами фильтра останутся битыми, и вы этого не заметите, потому что задание отработает успешно. Я на время лечения снимаю фильтры полностью и возвращаю их обратно после.

```bash # 1. Проверка на ПРИЁМНИКЕ — она и определит список на перекачку proxmox-backup-manager verify-job create verify-daily \ --store pbs-offsite --schedule 'daily 01:30' \ --ignore-verified true --outdated-after 30 proxmox-backup-manager verify-job run verify-daily # 2. Смотрим, что накопали proxmox-backup-manager task list --limit 20 # 3. Включаем флаг на pull-задании и запускаем руками proxmox-backup-manager sync-job update sync-offsite --resync-corrupt true proxmox-backup-manager sync-job run sync-offsite # 4. После лечения — снять флаг с ежедневного задания proxmox-backup-manager sync-job update sync-offsite --resync-corrupt false ```
Порядок действий: Правильный порядок: сначала Verification на приёмнике, потом Sync — схема
Порядок действий: Правильный порядок: сначала Verification на приёмнике, потом Sync. Открыть схему в полном размере

Разбор из практики: креативное агентство на 29 рабочих мест

Условно — креативное агентство «Бюро замыслов», 29 рабочих мест: дизайнеры, моушн-отдел, аккаунты и бухгалтерия. Кластер Proxmox VE из двух нод плюс кворум-устройство в офисной серверной, 12 виртуалок: 1С:Бухгалтерия, файловый сервер с исходниками макетов и видеопроектов, контроллер домена, сервер лицензий и рендер-очередь. Основной PBS стоит там же на отдельном железе, датастор на ZFS raidz2 из шести дисков по 4 ТБ. Резервный PBS — у нас в ЦОД, забирает данные pull-заданием через WireGuard, датастор на аппаратном RAID5 поверх ext4. Обе машины на ветке PBS 4.2. Занято около 7,5 ТБ — видеоархив дедуплицируется плохо, — 14 групп, порядка 620 снимков. Sync ежедневный, ночью, стабильно отрабатывал за 4–6 минут.

Verification на резервном сервере не была настроена вообще — классика. Не потому что кто-то ленивый, а потому что при заводке офсайт-копии задача звучала как «чтобы данные уехали», и на этом её закрыли. Мы взяли агентство на обслуживание, прогнали первичный аудит и запустили полную проверку резервного датастора. Она шла девять часов и выдала 23 снимка в статусе failed из 620. В каталоге .chunks нашлось 287 файлов с суффиксом .bad. На основном PBS верификация в тот же период дала ноль ошибок.

Причина обнаружилась в системном журнале резервной машины: за предыдущие полгода было два некорректных выключения по питанию, а батарея на кэше RAID-контроллера числилась деградировавшей ещё с зимы. Классическая write hole — контроллер отрапортовал о записи, данные до пластин не доехали. Ни ZFS-подобной самопроверки, ни контрольных сумм на уровне файловой системы там не было. То есть виноват был приёмник, а не канал и не источник.

Дальше по регламенту. Сначала проверили источник — полная верификация основного PBS, 0 failed, 21 из 23 «пострадавших» снимков на источнике жив и в пределах ретеншена. Потом сняли group-filter с pull-задания, включили --resync-corrupt true и запустили вручную. Обычный sync занимал 4–6 минут — этот шёл 1 час 50 минут и вытянул 96 ГБ, в основном куски образа файлового сервера. В логе задачи по каждому проблемному снимку шла строка вида re-sync snapshot ... due to corruption.

Результат: 21 снимок из 23 вылечился и прошёл повторную верификацию. Два не вылечились — они были старше сорока дней, а на источнике ретеншен настроен на тридцать, то есть исходников уже не существовало. remove-vanished на задании был выключен, поэтому приёмник их и хранил. Удалили руками: снимок, который заведомо не восстановится, только занимает место. После этого прогнали Garbage Collection: она убрала .bad-файлы и освободила 31 ГБ. Контроллеру заменили батарею, датастор пересобрали на ZFS. За четыре месяца после этого — ноль failed.

Два снимка мы потеряли не из-за повреждения, а из-за ретеншена: на источнике их уже спрунило. Будь на pull-задании включён `remove-vanished`, приёмник удалил бы их сам при очередном sync, и мы бы даже не узнали, что они были битыми. Если у приёмника окно хранения глубже, чем у источника, лечить старые снимки будет нечем. Это ещё один аргумент за то, чтобы верификацию ставить сразу, а не через восемь месяцев.

Источник тоже под подозрением, и это не паранойя

Инженер Proxmox в той самой форумной ветке даёт совет, который я считаю главным во всей теме: перед тем как полагаться на снимки при восстановлении, верифицируйте их и на исходных системах тоже. Логика простая — повторная передача исправляет резерв только тогда, когда на источнике лежат исправные данные. Если битый chunk приехал к вам с источника, resync-corrupt добросовестно перекачает битое ещё раз и снимок снова не пройдёт проверку.

Есть и вторая причина смотреть на источник. Инкрементальные бэкапы переиспользуют chunks предыдущих снимков — на этом стоит вся дедупликация. Один повреждённый кусок тянется через десятки снимков одной группы, и картина выглядит как лавина: сегодня один failed, через месяц пятнадцать из двадцати четырёх. Интересный побочный эффект, который в той же ветке проговаривает Chris: если снимок не прошёл верификацию, следующий бэкап зальёт chunks заново, и цепочка порчи рвётся сама. То есть верификация не просто выявляет проблему — она запускает механизм её самолечения на будущих точках.

Из этого получается практический приём, который я применяю на всех стендах с большим количеством групп, когда времени на полную проверку нет. По каждой группе бэкапов берём самый свежий снимок, ставим ему флаг protected — чтобы его не выкосил prune — и проверяем только его. Это на порядок быстрее полной верификации и при этом закрывает главный риск: свежая точка восстановления по каждой машине.

И честно про спорное. Флаг verified-only на sync-задании выглядит как идеальная защита — не тащить с источника то, что не прошло проверку. На практике он больно кусается, если на источнике верификация настроена нерегулярно: непроверенные снимки просто не поедут, и вы обнаружите на офсайте дыру в неделю. Я включаю verified-only только там, где на источнике верификация гарантированно ходит по расписанию и опережает sync по времени.

Где риск преувеличен: один-два `.bad` chunk — это не «датастор мёртв». Дедупликация означает, что битый кусок задевает много снимков, но подавляющее большинство данных при этом цело. Не надо в панике сносить хранилище — надо посчитать масштаб.
Памятка: Источник тоже под подозрением, и это не паранойя — схема
Памятка: Источник тоже под подозрением, и это не паранойя. Открыть схему в полном размере

Если повреждение есть и на источнике

Тогда resync-corrupt бессилен, и надо честно оценивать ущерб. Первым делом смотрим, сколько битых chunks и какие снимки они задевают. Считать .bad-файлы напрямую в каталоге датастора можно, но удалять их руками я не советую: этим занимается Garbage Collection, и она делает это согласованно с учётом ссылок.

Дальше — по приоритету восстановимости. Если в группе есть более старый снимок, прошедший верификацию, у вас есть точка восстановления, просто с большей потерей данных. Если повреждение задело один диск виртуалки из трёх — восстанавливайте поштучно, PBS умеет доставать отдельный образ и отдельные файлы из архива, необязательно катить всю ВМ. Если речь про файловый сервер — файловое восстановление из .pxar часто вытаскивает 95 % содержимого, потому что битым оказался конкретный chunk, а не весь архив.

И принудительно обновляем цепочку. Снимок, помеченный как failed, приводит к тому, что следующий бэкап этой группы зальёт chunks заново — то есть достаточно просто дождаться или запустить внеочередной бэкап, чтобы получить гарантированно свежую целую точку. Это, кстати, я делаю первым действием, ещё до всякого лечения: не важно, что происходит со старыми снимками, важно, чтобы на сегодня была одна заведомо целая копия.

Ну и правда, которую неприятно произносить: если битое и на источнике, и на приёмнике одинаково — значит, у вас не две копии, а одна, размноженная. Правило 3-2-1 существует ровно для этого. Офсайт-PBS, который получает данные синхронизацией, — это не независимая копия, а зеркало со всеми унаследованными дефектами. Независимость даёт только другой носитель и другой механизм: выгрузка на ленту, отдельный vzdump на съёмный диск, копия в объектное хранилище.

Sync копирует не только данные, но и ошибки логики хранения. Если у вас нет ни одной копии, полученной другим способом и лежащей на другом типе носителя, — правило 3-2-1 у вас не выполняется, сколько бы PBS ни стояло.

Регламент, который я ставлю на такие стенды

Первое и самое важное — развести задачи по времени, чтобы они не мешали друг другу. В той же форумной ветке настоящей причиной массовых verify failed оказалась не деградация дисков, а одновременная работа верификации и Garbage Collection на перегруженном сервере плюс забитый под ноль системный диск. Я строю ночное окно последовательно: сначала бэкапы, затем prune, затем Garbage Collection, затем верификация, и только после неё — синхронизация. Между этапами оставляю запас, а не ставлю их встык.

Второе — частота проверки. Документация PBS прямо рекомендует перепроверять все бэкапы минимум раз в месяц, даже если предыдущая проверка была успешной, потому что носители деградируют и bit rot никто не отменял. Рабочая связка: ежедневное задание с ignore-verified и outdated-after порядка 30 дней, которое подхватывает свежее и просроченное, плюс отдельное полное задание раз в месяц на выходных. На большом датасторе полная проверка идёт часами — планируйте её на время, когда сервер свободен.

Третье, и здесь моя позиция расходится с тем, что часто советуют. Держать resync-corrupt постоянно включённым на ежедневном sync-задании я не люблю: оно каждый раз перечитывает манифесты всех снимков, ежедневная синхронизация из семиминутной превращается в многочасовую, а пользы в 99 % случаев ноль, потому что чинить нечего. Я делаю два задания на одном и том же remote: ежедневное быстрое без флага и еженедельное с флагом, запускаемое после ночной верификации. Если вам такая схема кажется избыточной — включайте флаг руками по факту обнаружения failed, это тоже нормально, просто требует дисциплины.

Четвёртое — уведомления. Настройте оповещения по задачам PBS так, чтобы письмо или сообщение приходило не только при падении задания, но и при ненулевом числе неудачных снимков в верификации. Задание верификации, нашедшее 23 битых снимка, завершается со статусом «ошибка» — но если это письмо падает в общий ящик, который никто не читает, толку от него нет.

И то, на что можно спокойно забить. Не надо крутить worker-threads у sync-задания на HDD-хранилище: параллельная обработка групп появилась только в PBS 4.2 (значение от 1 до 32, по умолчанию 1, память и число соединений растут примерно линейно) даёт выигрыш на NVMe и на быстрых массивах, а на шпинделях чаще только добавляет случайного доступа. Не надо гнаться за максимальным verify-threads по той же причине. И не надо каждую неделю руками ходить в .chunks и считать .bad-файлы — если у вас настроены верификация и уведомления, вы узнаете о проблеме раньше, чем она станет видна в файловой системе.

Если делать только одно из всего списка — делайте Verification на приёмнике. Всё остальное имеет смысл лишь тогда, когда вы вообще знаете состояние своей резервной копии.
Памятка: Регламент, который я ставлю на такие стенды — схема
Памятка: Регламент, который я ставлю на такие стенды. Открыть схему в полном размере

Частые вопросы

Почему повторный запуск обычного Sync не исправляет повреждённый снимок?

Потому что Sync сравнивает манифесты, а не данные. Манифест повреждённого снимка не изменился, поэтому задание пишет в лог «no data changes» и не скачивает недостающие chunks. При этом сама Verification переименовала битый chunk в файл с суффиксом .bad, то есть кусок данных исчез из хранилища, а метаданные остались целыми. Снимок проходит синхронизацию и не проходит восстановление.

Нужно ли запускать Verification до Sync или её результат появится сам?

Обязательно до, и именно на приёмнике. resync-corrupt не проверяет данные — он читает поле verify_state в манифесте каждого локального снимка. Снимки со статусом Failed перекачиваются, снимки с нечитаемым манифестом тоже, а снимки, которые никогда не проверялись и поля verify_state не имеют, задание просто пропустит.

Работает ли resync-corrupt для push-направления?

Нет. Опция доступна только для pull-заданий (sync-direction pull, значение по умолчанию). Push-направление появилось в PBS 3.3 одновременно с resync-corrupt, но флага повторной синхронизации у него нет. Если офсайт-копия у вас организована пушем с основного PBS на резервный, для лечения придётся временно создать pull-задание с обратной стороны — именно это рекомендует инженер Proxmox в форумной ветке про массовые verify failed.

Насколько дольше идёт синхронизация с включённым флагом?

Существенно дольше, потому что заданию приходится открывать и разбирать манифест каждого снимка в области действия, а не быстро отсекать совпавшие. На стенде агентства с 620 снимками обычный sync занимал 4–6 минут, а прогон с resync-corrupt — 1 час 50 минут. Постоянно держать флаг включённым на ежедневном задании я не советую.

Что делать с файлами .bad в каталоге .chunks?

Ничего руками. Их удаляет Garbage Collection, которая делает это согласованно с учётом ссылок из индексов. Ручное удаление в .chunks — хороший способ добавить себе повреждений сверх имеющихся. После успешного лечения просто запустите GC и получите место обратно.

Что делать, если повреждение обнаружилось и на источнике тоже?

Повторная передача тут не поможет — она исправляет резерв только при наличии исправных данных на источнике. Сначала запустите внеочередной бэкап, чтобы получить одну заведомо целую точку на сегодня: снимок, помеченный как failed, приводит к тому, что следующий бэкап зальёт chunks заново. Затем оцените ущерб по отдельным снимкам и восстанавливайте поштучно — отдельный диск ВМ или отдельные файлы из архива, — либо откатывайтесь на предыдущий верифицированный снимок.

С какой версии PBS есть resync-corrupt и как включить его из командной строки?

Опция появилась в Proxmox Backup Server 3.3 (ноябрь 2024) и есть во всех последующих ветках, включая 4.x. На существующем pull-задании она включается командой proxmox-backup-manager sync-job update <id> --resync-corrupt true, выключается тем же ключом со значением false. В веб-интерфейсе — чекбокс Re-sync corrupt snapshots в расширенных настройках sync-задания.

Не удалит ли remove-vanished повреждённые снимки вместо того, чтобы их вылечить?

remove-vanished удаляет на приёмнике только то, чего больше нет на источнике, — повреждение тут ни при чём. Если снимок на источнике жив, remove-vanished его не тронет, а resync-corrupt перекачает. Если на источнике снимок уже удалён prune, при включённом remove-vanished приёмник удалит свою битую копию, при выключенном — оставит её висеть в статусе failed. Для включения нужен Datastore.Prune на локальном датасторе.

Столкнулись с похожей задачей? Обращайтесь — решим

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

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 💬 MAX: +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи