Какое-то время назад я столкнулся с неприятной проблемой — понадобилось бэкапить несколько виртуальных машин. Надо сказать, что бэкапить для меня — значит иметь в результате не только архив с последней копией, а небольшую кучку этих архивов, сделанных по заданной схеме. Батничек для архивации, понятное дело, был написан быстро и работал без нареканий, но размер… Размер комплекта бэкапов получался огромным. Особенно печалило то, что это были почти одинаковые виртуалки, и почти одинаковые бэкапы этих виртуалок. Так я узнал слово «дедупликация» и «дифф» и начал подыскивать какую-нибудь утилиту для сжатия с дедупликацией.
Разные утилиты предлагали разные подходы к сжатию близких по содержанию файлов, но общим оказалось одно — выбираешь один исходный файл и натравливаешь утилиту на остальные — она определяет разницу между исходным и остальными и архивирует результат, а когда нужно развернуть — указываешь исходный файл и архив с диффом, утилита сама всё развернет.
Короче, исходник нужно было где-то иметь в развернутом виде. Всё время — и в момент архивации, и в момент разархивирования. То есть «картина маслом» — у меня пяток виртуалок, я хочу сегодня сделать архив с разницей между сегодняшними виртуалками и вчерашними — я должен:
— со вчера заготовить полную копию всего хозяйства,
— потом запустить утилиту, она сделает дифф и архив диффа.
Теперь я хочу куда-то скопировать всё это — я же не буду вчерашние данные (исходные) перетаскивать в несжатом виде — мне придется заархивировать и исходник. Если завтра мне понадобится сделать дифф между вчера и завтра — исходник должен быть доступен в несжатом и нетронутом виде — либо копия вчерашнего состояния, либо архив, который придется разворачивать. Если мне потребуется развернуть архив на новом хосте — сначала нужно развернуть исходник, потом развернуть сам дифф.
Ну ладно место на диске — можно купить, но время! Такая куча времени уходит на разархивирование исходника! Но нашелся он — архиватор, который умел делать всё правильно — загонять исходник в архив, причем с дедупликацией, а потом делать диффы прямо со сжатого исходника, причем скорость архивации/разархивирования упирается в скорость жесткого диска. Клёво! Но под Windows 2003 не работает. Как вы понимаете, если бы всё работало само — я бы эту статью не писал.
Итак, теперь — амбула.
Архиватор называется exdupe, он был типа фриварный, с частично доступным исходным кодом. Частично — потому что библиотека дедупликатора линковалась статически, а выложен был код на утилиту командной строки (сейчас выложен весь код). Всё лежит в виде проекта под Visual Studio 2012. Запускалось всё только под 64 битной версией винды (у меня — Win2003), и при запуске выдавало ошибку:
Исходник был тут же скачан с сайта программы (я допиливал версию 0.5.0).
Причина ошибки — несовместимость версий библиотеки VSSAPI.dll у моей винды и у того либа, который был подключен в проекте.
Поковыряв исходник, я понял, что самый простой путь — просто отключить поддержку Shadow Copy — убрать вызовы библиотеки VSS и обкорнать функции, отвечающие за обращение к VSS. Надо сказать, код был написан прямыми руками, хоть и с ошибками, и функций оказалось всего две и находились они в файле «shadow\shadow.cpp».
Вот что мы делаем:
Разные утилиты предлагали разные подходы к сжатию близких по содержанию файлов, но общим оказалось одно — выбираешь один исходный файл и натравливаешь утилиту на остальные — она определяет разницу между исходным и остальными и архивирует результат, а когда нужно развернуть — указываешь исходный файл и архив с диффом, утилита сама всё развернет.
Короче, исходник нужно было где-то иметь в развернутом виде. Всё время — и в момент архивации, и в момент разархивирования. То есть «картина маслом» — у меня пяток виртуалок, я хочу сегодня сделать архив с разницей между сегодняшними виртуалками и вчерашними — я должен:
— со вчера заготовить полную копию всего хозяйства,
— потом запустить утилиту, она сделает дифф и архив диффа.
Теперь я хочу куда-то скопировать всё это — я же не буду вчерашние данные (исходные) перетаскивать в несжатом виде — мне придется заархивировать и исходник. Если завтра мне понадобится сделать дифф между вчера и завтра — исходник должен быть доступен в несжатом и нетронутом виде — либо копия вчерашнего состояния, либо архив, который придется разворачивать. Если мне потребуется развернуть архив на новом хосте — сначала нужно развернуть исходник, потом развернуть сам дифф.
Ну ладно место на диске — можно купить, но время! Такая куча времени уходит на разархивирование исходника! Но нашелся он — архиватор, который умел делать всё правильно — загонять исходник в архив, причем с дедупликацией, а потом делать диффы прямо со сжатого исходника, причем скорость архивации/разархивирования упирается в скорость жесткого диска. Клёво! Но под Windows 2003 не работает. Как вы понимаете, если бы всё работало само — я бы эту статью не писал.
Итак, теперь — амбула.
Архиватор называется exdupe, он был типа фриварный, с частично доступным исходным кодом. Частично — потому что библиотека дедупликатора линковалась статически, а выложен был код на утилиту командной строки (сейчас выложен весь код). Всё лежит в виде проекта под Visual Studio 2012. Запускалось всё только под 64 битной версией винды (у меня — Win2003), и при запуске выдавало ошибку:
Entry Point Not Found
The procedure entry point VssFreeSnapshotPropertiesInternal could not be located in the dynamic link library VSSAPI.DLL.
Исходник был тут же скачан с сайта программы (я допиливал версию 0.5.0).
Причина ошибки — несовместимость версий библиотеки VSSAPI.dll у моей винды и у того либа, который был подключен в проекте.
Поковыряв исходник, я понял, что самый простой путь — просто отключить поддержку Shadow Copy — убрать вызовы библиотеки VSS и обкорнать функции, отвечающие за обращение к VSS. Надо сказать, код был написан прямыми руками, хоть и с ошибками, и функций оказалось всего две и находились они в файле «shadow\shadow.cpp».
Вот что мы делаем:
- находим функцию void unshadow(void)
- комментим строку 342:
VssFreeSnapshotProperties(&prop.Obj.Snap);
станет:
//removing shadowing //VssFreeSnapshotProperties(&prop.Obj.Snap);
- перед строкой 330
ULONG fetched = 0;
добавляем:
//remove shadowing return 1;
- находим функцию int shadow(vector volumes),
комментим строку 177:
hr = ::CreateVssBackupComponents(&comp);
станет:
//remove shadowing //hr = ::CreateVssBackupComponents(&comp);
5. перед строкой 157:
// Initialize COM and open ourselves wide for callbacks by // CoInitializeSecurity. HRESULT hr;
втыкаем:
//remove shadowing return 1;
Перед сборкой — рекомендую поменять имя экзешника в свойствах проекта, чтобы не перепутать с авторским «exdupe.exe». Типа «exdupe-050-noshadow.exe».
Собираем, запускаем — работает!
Алгоритм реально шустрый, конечно отжирает память и грузит ядра, но это можно настроить — мне комфортно запускать в два потока с ключиком "-t2". На обычном жестком диске дедупликация исходника со сжатием:
— 65.7 ГБ за 44 мин = 24.8 МБ/с
— сжал до 24.1 ГБ = коэффициент сжатия 0.37
дедупликация на следующий день
— время обработки 10 мин. 20 с. = 106 МБ/с
— дифф сжат до 2.1 ГБ
Отдельно скажу, что ограничение на запуск только из-под 64-битных версий ОС введено искусственно, и может быть отключено, при этом архивы, созданные 64-битной программой нормально разворачиваются 32-битной, правда рекордных скоростей тут и близко нет (и ждать не надо).
Бинарники и полные тексты проекта не выкладываю из-за ограничений лицензии.
Сайт утилиты exdupe — www.exdupe.com
Исходники: www.exdupe.com/old