Каждый специалист по резервному копированию рано или поздно сталкивается с одной и той же головоломкой. База данных работает круглосуточно, транзакции летят в файлы данных и журналы безостановочно, а задание бэкапа должно получить картину такого тома, словно часы на сервере остановились ровно на одну долю секунды. Попытка честно прочитать файл, который прямо сейчас перезаписывается, приводит к тому, что половина блоков принадлежит одному моменту времени, а вторая половина другому моменту, и при восстановлении такая копия превращается в мусор со слабыми шансами на чинопочинку. Служба теневого копирования томов в Windows решает именно эту задачу. Она даёт бэкап-приложению замороженную точку во времени, не останавливая при этом работу продукта, и умеет это делать настолько быстро, что конечный пользователь даже не замечает паузы. В этой статье разбирается внутренняя механика такого снимка, роли его участников, разница между согласованными уровнями консистентности, место хранения копий, практические приёмы чтения замороженного тома и та неприятная истина, что теневая копия не равнозначна резервной копии ни с какой стороны.
Актёры внутри конвейера снимка
VSS устроена как координация трёх сторон, и понимание их ролей избавляет от девяноста процентов диагностических ошибок в журналах. Первый участник называется requester, и это по сути бэкап-приложение. Именно оно инициирует процесс, формирует набор томов, которые должны попасть в снимок, и пошагово двигает церемонию через фазы подготовки, заморозки и фиксации. Requester не знает ничего о внутренностях баз данных, он только сверяет расписание и задаёт вопрос системе.
Второй участник называется writer. Writer регистрируется в службе VSS каждым приложением, которое держит на диске данные, чувствительные к порядку записи. Реляционная СУБД, почтовый сервер, служба каталогов, гипервизор, системный writer самой ОС - все они описывают в метаданных, какие файлы составляют их данные и как их корректно подготовить к снимку. Когда requester объявляет подготовку к заморозке, каждый writer получает событие и начинает дожимать то, что лежит в буферах. Транзакции, которые уже зафиксированы в памяти, спускаются в журнал, журнальные хвосты сбрасываются на диск, чекпоинт закрывается. После этого writer отвечает, что готов, и сервер приложения удерживает запись на миллисекунды, а всё остальное время продолжает принимать запросы в очередь.
Третий участник называется provider, и именно он физически создаёт снимок. Системный программный провайдер Microsoft работает через драйвер volsnap, аппаратные провайдеры от поставщиков СХД перекладывают работу на контроллер массива и зеркалирование на уровне рейда. Для типичного локального тома используется программный провайдер, и вся глубина VSS упирается в его технику копирования при записи.
Двигатель copy-on-write и экономия блоков
Самый популярный миф о снимке гласит, что система копирует весь том целиком в момент фиксации. На самом деле в момент снимка не копируется почти ничего. Провайдер помечает том как имеющий снимок и открывает область diff, в которую будут складываться вытесненные данные. С этого момента драйвер volsnap сидит в стеке хранения и перехватывает каждую операцию записи на защищённый том. Когда приложение хочет перезаписать некоторый блок, сначала старое содержимое этого блока читается и переносится в область diff, и только после этого на место старого кладётся новое. Пока блок ни разу не перезаписывали, он хранится в единственном экземпляре, и снимок просто ссылается на живые данные.
Из этой механики вытекают почти все практические свойства теневых копий. Во-первых, снимок на старте почти бесплатен по месту и занимает доли процента объёма тома. Во-вторых, чтение через снимок даёт именно ту картину, которая была на момент фиксации, потому что любое изменение с тех пор вытесняло старую версию в diff. В-третьих, цена появляется тогда, когда том активно переписывается после снимка. В таком случае каждый новый перезаписанный блок трижды касается железа, два раза читается и два раза пишется, и на интенсивных нагрузках это ощутимый хвост по вводу-выводу. Опытный инженер резервирования в связи с этим не держит снимки сутками, потому что каждый час жизни снимка умножает накладные расходы и раздувает область diff.
Согласованность уровня приложения против уровня сбоя
Один и тот же снимок может быть либо просто согласованным с точки зрения файловой системы, либо согласованным с точки зрения приложения. Различие между этими уровнями определяет, придётся ли после восстановления чинить базу чекпоинтами и откатом журнала, или она поднимется как ни в чём не бывало.
Снимок уровня сбоя, называемый обычно crash-consistent, напоминает картину диска, которую увидела бы машина после внезапного отключения питания. Файловая система целостна за счёт журналирования NTFS, но приложения в таком образе находятся в состоянии, в котором они были в момент внезапного стопа. Для большинства современных СУБД это не приговор, потому что при следующем запуске сработает восстановление после сбоя и журналы накатятся ровно до последней зафиксированной точки. Но это дополнительная работа при восстановлении, лишние минуты простоя и лишнее нервное воздержание, когда надо открыть сервер для клиентов.
Снимок уровня приложения достигается только полным прохождением церемонии с writer. Когда все writer зарегистрированы, получили события заморозки и успели дожать буферы, образ в снимке отражает состояние, которое приложение само считает завершённым и чистым. Такой образ поднимается быстро, without лишних фаз отката, и именно он считается эталоном для резервного копирования продуктивных баз. Диагностика часто сводится к тому, чтобы выяснить, почему writer ушёл в состояние failed или retryable: чаще всего виноваты переполненный журнал, кривые права на служебные каталоги или сторонний продукт фильтра, который вклинивается в стек.
Где живут теневые копии и почему заканчиваются
Хранилище теневых копий физически лежит в скрытом системном каталоге корня каждого тома под названием System Volume Information. Доступ в этот каталог по умолчанию имеет только системная учётная запись, и попытки просто провалиться туда через проводник закончатся отказом. Внутри каталога лежат файлы с длинными нечитаемыми именами, и именно они составляют область diff для каждого живого снимка на томе. Программный провайдер по умолчанию держит diff-область на том же томе, что и исходные данные, хотя технически её можно перенести на другой носитель командной настройкой.
Пространство для копий не бесконечно, и у него есть настраиваемый лимит, который по умолчанию равен десяти процентам ёмкости тома и поднимается при необходимости через vssadmin resize shadowstorage. Когда область diff подходит к потолку и новые блоки писать больше некуда, включается жёсткое правило: самый старый снимок удаляется целиком, чтобы освободить место для новых блоков. Если и этого не хватает, снимки вымываются каскадно один за другим, а в худшем случае служба просто роняет защиту, и пользователь получает том вообще без снимков, хотя в планировщике задания исправно стоят. Это одна из самых коварных неисправностей на серверах с интенсивной перезаписью: задания отрабатывают, журнал чистый, а предыдущие версии файлов пользователю недоступны. Утилита vssadmin list shadows и vssadmin list shadowstorage показывают текущее наполнение и дают понять, насколько далеко реальность ушла от лимита.
Чтение замороженного тома в деталях
Сам снимок после фиксации доступен как новое устройство в пространстве имён Windows. Его идентификатор начинается с префикса \\?\GLOBALROOT, и такой путь обычно выглядит как длинная строка Device\HarddiskVolumeShadowCopy с порядковым номером снимка на конце. К этому устройству нельзя просто подключить букву диска штатными средствами, поэтому бэкап-приложения работают с ним через явный путь или через символическую ссылку, которую создают временно командой mklink. Утилита diskshadow умеет делать expose, то есть выставлять снимок как обычную букву тома, что удобно для ручных манипуляций.
Отдельный нюанс касается инструментов копирования. Штатный robocopy поддерживает режим резервного копирования через флаг /b, который задействует привилегии резервного копирования и восстановления. Этот режим позволяет читать файлы, заблокированные другими процессами или ограниченные по ACL, игнорируя штатные проверки доступа под учётной записью, у которой есть право на резервное копирование. Если опустить этот флаг и пытаться копировать живой том в лоб, копия будет безнадёжно разорвана во времени, потому что целый процесс чтения занимает длинные минуты, и каждый файл отражает свой собственный момент. Комбинация снимка плюс чтение через ссылку на устройство снимка даёт честную точку во времени без остановки службы.
Теневые копии как цель злоумышленника
Появление пользовательской функции предыдущих версий файлов сделало теневые копии самым коротким путём к откату после мелких аварий. Пользователь щёлкает правой кнопкой по файлу, открывает вкладку предыдущих версий и видит снимки, сделанные планировщиком. Именно эту же удобную мишень атакует современный вымогательский софт. Цель вредоноса состоит в том, чтобы жертве некуда было откатываться, поэтому одна из первых команд, которую запускает шифровальщик с повышенными правами, звучит как vssadmin delete shadows /all /quiet. Рядом часто встречаются wmic shadowcopy delete, bcdedit с отключением восстановления загрузки и wbadmin delete systemstatebackup. Удаление теневых копий на продуктивном сервере вне планового окна техобслуживания является одной из самых громких сигнатур атаки и должно моментально будить систему мониторинга.
Реакцией инженерной зрелости является не только алерт на саму команду, но и включение защиты от подделки. Механизм Tamper Protection в современной ОС и в платформе антивируса запрещает процессам без полноценной цепочки доверия удалять теневые копии, снимать защиту и править ключевые параметры безопасности. Проверяется это простым экспериментом на тестовом стенде: даже под административной учётной записью команда удаления должна упираться в отказ, и этот отказ должен быть виден в журнале аудита. Аналогично стоит следить за службой VSS как таковой: её остановка на сервере без задания резервного копирования является вторым симптомом скрытой подготовки к шифрованию.
Почему снимок никогда не заменяет резервную копию
Финальная часть любого разговора с новичком выглядит примерно одинаково и заканчивается тем же выводом.
- Снимок живёт на том же физическом накопителе, что и исходные данные, а значит, отказ диска или контроллера убивает и том, и все его теневые копии одновременно.
- Снимки зависят от цепочки ссылок и области diff, поэтому повреждение одного звена способно обрушить всю последовательность точек во времени, а не один конкретный день.
- Время жизни снимка ограничено лимитом хранилища, и на активном томе старые точки вымываются задолго до того, как возникнет потребность откатиться к ним.
- Снимок не является проверенной переносимой сущностью. Его нельзя просто упаковать, отправить в другое здание, положить в облачное хранилище и спустя пять лет достать оттуда.
- Снимок не защищает от удаления или шифрования, пока атакующий имеет права на том, и именно поэтому его целенаправленно уничтожают в первую очередь.
Резервная копия отличается от снимка тем, что является самостоятельным набором данных на отдельном носителе, желательно с контрольными суммами, протоколом проверки восстановления и оторванным административным контуром. Идеальная цепочка резервирования выглядит так: requester создаёт VSS-снимок, из него аккуратно читается консистентный образ, этот образ превращается в резервную копию и уходит в независимое хранилище, а сам снимок аккуратно закрывается и освобождает область diff. Стратегия три-два-один по-прежнему не отменена: ни одна запасная сущность не фиксирует надёжность, пока это единственный экземпляр в компании. Снимок остаётся горячим инструментом для моментального отката, а резервная копия - последней линией, до которой дело не должно доходить слишком часто.