Работа с rsync и многими другими утилитами для бэкапирования несёт в себе совершенно не очевидную и от этого особенно недооценённую опасность — риск получить рассинхронизацию содержимого файлов, о которой никто и никогда не узнает до того, пока не станет поздно. Статья задумана как рассказ об очень интересной, но малоизвестной утилите precizer. С её помощью можно контролировать целостность данных при синхронизации, бэкапировании или восстановлении файлов. Программа вполне удобно организована и позволяет убедиться, что ни один байт не был утерян в процессе.
Основано на реальных событиях (обожаю этот жанр кино!)
Учитывая просто отвратительную надёжность современных HDD, статья описывает ставшую уже тривиальной борьбу с последствиями выхода HDD из строя.
Материал разделён на несколько глав, пестрящих избыточными техническими подробностями с целью обосновать, почему было принято именно такое решение, а не иное. Возможно, читателям такая архитектура покажется полезной и удобной, и возникнет непреодолимое желание повторить, но сделать ещё лучше! В тексте будет много IMHO, эмоций и попыток плоско пошутить. Гарантирую!
Кому интересен ответ только на главный вопрос, можно сразу перейти к практике использования программы precizer.
Выделенный жирным текст можно читать отдельным слоем и получить краткое представление о затронутых темах.
А тем временем…
В «кино» снимались
Аппаратная составляющая, схема хранения и синхронизации для бэкапирования, домашний Disaster Recovery Center
Нюансы выбора при покупке современных HDD высокой ёмкости
Об одном из самых надёжных методов восстановления информации с проблемных, полуживых дисков (ddrescue)
Синхронизация бэкапов между географически разнесёнными хранилищами (rsync)
precizer. Проверка результатов синхронизации и восстановления информации с диска с помощью расчёта контрольных сумм файлов
Аппаратная составляющая. Как всё организовано

Железо дома
Компактная машинка Dell OptiPlex XE2 SFF, размером с видеомагнитофон конца эпохи (да, я видел настоящих динозавров и вот такое тоже...). На борту LibreBoot в компании с Gentoo (это вообще тема для отдельной статьи). Этот PC выполняет роль одновременно кинотеатра и домашнего сервера с одним ёмким 3.5" HDD и NVME под систему. Железка была куплена по цене одного похода в кафетерий. Выпущена 13 лет назад и поставлялась в девственно новом состоянии и с полной комплектацией: фирменной клавой, мышкой и слюнявчиком для офисного планктона. Небольшой апгрейд CPU на самый крутой того же поколения i7-4790K, скромная, но современная видеокарта AMD RX 6400 и 32Gb памяти превратили заурядное старьё в образчик комфорта со всеми преимуществами современных технологий: теперь можно подключить многоканальную звуковую систему вместе с телевизором по HDMI и отдавать декодирование видео 4K на попечение видеокарты.

Почти тот же видеомагнитофон, но с чуть лучшим звуком и бо́льшим разрешением. Вся прелесть аппаратного решения начала особенно радовать после замены штатных кулеров на почти бесшумные Noctua, благодаря чему сам компьютер перестал быть слышным даже во время просмотра фильма «Тихое место». Общая производительность неожиданно приятно удивила. Бенчмарки показали суммарную разницу по баллам всего в 23% с рядом торчащим лептопом i7 12 поколения, используемым для работы, а производительность каждого ядра индивидуально оказалась хоть и ниже, но совсем незначительно. Лишнее подтверждение, что закон Мура вовсе не закон и давно не работает. Зацените разницу — 4 поколение против 12! Вот так прогресс за 13 лет! (ну да, ну да... полноценный проц против ноутбучного, и размер в попугаях. мгу-у-у.. оке-е-ей..)
Железо на удалённой стороне
Raspberry Pi 5 16gb с переходником USB 3.1 на 3.5 HDD и штатной ОС с закосом под Debian. Переходник копеечный, но обеспечивает скорость обмена данными выше возможностей SATA HDD дисков, что полностью покрывает потребность. Единственный нюанс — для 3.5" дисков нужен отдельный блок питания (включается в сам USB-SATA переходник).

Изначально Raspberry покупалась для мультимедийных нужд и малинка вполне могла бы стать полноценным 4K видеоцентром, если бы хватило терпения в борьбе с допиливанием Debian до требований по безопасности и заработал бы многоканальный звук. Но нет, терпения не хватило после месяца ежедневных страданий стараний именно над звуком. На последних волевых были предприняты попытки поставить фаворитную ОС Gentoo в которой всё работает, но и там меня тоже поджидало разочарование в виде сложностей адаптации вшитой U‑Boot, файловой системы и загрузки Gentoo с microSD: в один прекрасный момент операционка переставала грузиться; чёрный экран и ни слова пояснений. После чего попытки приспособить малинку были признаны провальными и поэтому был куплен полноценный PC с нормальным процом, выбором по BIOS и полным спектром доступных операционных систем под архитектуру x86-64. А тем временем…
В процессе поиска решений была исследована система LibreELEC (bare-metal Kodi) и откровенно приятно удивила своей завершённостью программно-аппаратного комплекса. Как у профессионала у меня завышенные требования к функционалу домашнего сервера и поэтому для моих нужд LibreELEC оказался слишком ограниченным и негибким в плане расширения (там нет пакетов, каждый индивидуально вкомпиливается в образ из специально пропатченных многотонажными патчами сорцов! Бррр!). Но если нужен просто хороший мультимедийный центр только для музыки и кино на малинке, то решение определённо очень, очень привлекательное и работает даже с полной поддержкой многоканальности поверх HDMI искаропки! (смотреть в сторону проброса raw потока поверх stereo 2.0 в ALSA; ну да, забористо... но работает же!)
В результате всех мытарствований Raspberry Pi нашёл своё место как backup-сервер: потребление Ватт железкой сопоставимо с потреблением самого HDD диска; компактный размер — в алюминиевом корпусе с пассивным охлаждением точно повторяет размер пачки сигарет, бесшумный. Прекрасно справляется с каскадной шифрацией/дешифрацией разными алгоритмами в режиме реального времени (veracrypt) без деградации производительности для HDD. Другими словами — процессор шифрует поток данных быстрее, чем диск может его читать/писать (узкое место тут скорее сама физическая основа диска). Даже поддерживает аппаратное ускорение для целого ряда популярных алгоритмов (увы, для этого придётся потратить много времени для переконфигурирования ядра, оно старательно покоцано самими разработчиками малинки). Несомненно, Raspberry Pi 5 — крайне интересное решение и может гораздо больше, но сейчас играет роль третьего плана, только как backup-сервер. А тем временем…
Возникает логичный вопрос: почему просто не поставить два диска и не связать их в RAID1, зазеркалив данные без вот этого всего лишнего железного хлама, который нужно купить, настроить и потом ещё и обеспечить интернетом, удалённым доступом и бесперебойным питанием? Отвечаю кратко и по-делу: это не просто система резервирования или бэкапирования. Это полноценный Disaster Recovery Center домашнего масштаба со 100% доступностью данных без дополнительных телодвижений по их восстановлению из архивов или backup-бэкэндов. С одной локацией может случиться разное: ограбление, пожар, затопление или банальное упало-разбилось. Зеркальный рейд не спасает ни от одной из этих неприятностей, увы, не таких уж и редких. С DRC данные доступны сразу = подключился и получил. Например просто смонтировав шару с любой точки мира по sshfs и мгновенно получив доступ ко всему содержимому диска. Удобно! И к удобному быстро привыкаешь!
Синхронизация между дисками основного сервера и backup организована через rsync поверх ssh. Является ли это узким местом в безопасности? С учётом ограниченных возможностей по выбору алгоритмов (отсутствие каскадной шифрации, например) и критических дыр в безопасности ssh однозначно является узким местом, но не больше, чем проприетарные прошивки неизвестного происхождения на всех hardware компонентах, участвующих в каждом из этапов хранения и передачи данных. Не забывайте также про свои маршрутизаторы с китайскими, плохо скрытыми бэкдорами на каждом шагу. Определённо, пустить трафик хотя бы через OpenVPN было бы ещё более разумной идеей, но это планы на будущее.
Способ хранения бэкапов: периодическая синхронизация, копия 1-в-1 с учётом фильтров ненужного. Обе программы: и rsync, и precizer умеют гибко управлять фильтрами, выбирая что можно проигнорировать, а что — нет.
Я не люблю всё усложнять! (ага... Именно поэтому предпочитаю Gentoo и LibreBoot, ха-ха!) За годы админства с меня хватило и ленточных накопителей с их обманчивой надёжностью, и извращённого кекса с Bacula (его конфигами, процедурами восстановления с помощью консольных команд и отсутствием ГУЯ здорового человека). Однажды я себе так и сказал: «KISS! Хватит кошмара с дедупликацией и ротацией резервных копий ради экономии килобайт на петабайтных SAN-хранилищах!» Там где действительно нужна история и необходимость отката — точечно использовать git и синхронизировать копию в бэкап-таргет, а не разводить зоопарк снапшотов с ZFSами! Поэтому после десятилетий экспериментов прижилась именно такая схема: диск тут, диск там. Между ними rsync через интернет. Синхронизация по крону: скрипт в пяток строк с повтором при сбое и оповещением в случае фэйла. Всё! Ну а если масштабировать до уровня предприятия с Disaster Recovery, то SAN тут, SAN там; между ними оптика — всё просто! (ну да, ну да, всё именно так, только ещё плюс пару лет на настройку, интеграцию и пару киловатт в час для питания)
А тем временем…
Проблема возникла внезапно и на ровном месте. Жил себе не тужил большой, прекрасный HDD диск Toshiba MG06ACA10TE 10Tb и одним замечательным, солнечным воскресным утром шторы были наглухо закрыты от палящего назойливого солнца. Но сделано это было исключительно ради просмотра очередной серии долгожданного и поэтому заранее скачанного сериальчика и... И Ни! Че! Го! хорошего... Шторы пришлось открыть, просмотр отменить, а диск подвергнуть тщательному исследованию. Вроде как жив диск, а вроде и не совсем… Точно так же и с настроением, которое было окончательно испорчено. Некоторые файлы читались без проблем, но на других диск входил в ступор и переставал отвечать при вращающемся шпинделе. Перемонтирование - опять работает на некоторых файлах и виснет на других. S.M.A.R.T. и dmesg чуть прояснили картину и стало очевидным, что диск скорее мёртв, чем жив — многие секторы просто перестали быть доступными. Это стало понятным по пугающе растущим счётчикам в нескольких критических метриках сразу:
Current_Pending_Sector Reallocated_Sector_Ct Command_Timeout
В моменты «подвисаний» диск несколько раз пытается перепрочесть и релоцировать проблемные секторы, но в большинстве случаев это заканчивается ничем.
Заказ нового диска и томительное ожидание доставки стали венцом мучительного выбора производителя и модели. Теперь это Seagate ST28000NM000C-3WM103 25TB. Прошлая Тошиба выбиралась исходя из критериев предельно возможной надёжности и долговечности (исследования статистики имели место быть) ну и конечно — максимально доступной ёмкости среди представленных на рынке безгелиевых дисков тех времён. Согласно рекомендациям опытных и бывалых оба диска были идентичной модели, но из разных партий. Так получилось, что даже версии прошивок были разными. Цель была предельно простой — емкость 1-в-1 для периодических синхронизаций одного диска на другой. Но увы... По факту из двух купленных тогда железок одна проработала меньше двух лет, вторая жива по сей день. Да, это не дешёвое удовольствие, но восстановление ценных данных гораздо, ГОРАЗДО дороже! А иногда просто невозможно физически.
Облачные сервисы для бэкапов мной никогда не рассматривались всерьёз по целому ряду причин:
Скорость доступа
Нулевое доверие к третьей стороне. Небезосновательно!
1984
НЕнулевая вероятность взлома аккаунта и похищения личной информации (прецедентов — масса)
Учётка может быть заблокирована внезапно и просто так, по чьей-то прихоти или звёзды так сложились. Прецедентов безвозвратной потери доступа — сотни тысяч.
И конечно ключевой — цена. Несложный расчёт покажет, что дешевле свои два диска с синхронизацией, чем хранить эквивалентный объём в облаке и рано или поздно заиметь вышеперечисленные последствия.
Наконец-то отключат Интернет, а мы — уставшие!
Откуда обоснованное недоверие к третьей стороне? Хотя бы оттуда, что нет ни одного сервиса, обеспечивающего каскадное шифрование на стороне клиента открытым ПО, прошедшим сторонний аудит. Что уже говорить про использование post-quantum алгоритмов… Помню, какой-то из провайдеров громко пукнул на весь интернет о бета-версии подобной опенсорсной софтины. Готовый бинарник 500 мегабайт. ШТА?! Сходил за исходниками. Открыл. Код на JavaScript и запускается как браузерное приложение в каком-то движке, который нужно отдельно тянуть как блоб с их сайта (ну кто бы мог сомневаться!). Закрыл. Удалил навсегда. Остальной рекламный пердёж улетал фтопку настолько быстро, что даже название той шарашкиной конторы вспомнить уже не представляется возможным. Думаю, не только у меня воспоминаний об этом эксперименте не осталось. Что в результате? А воз и ныне там — все SaaS нагибаются регуляторами и ни одно нормальное(?) правительство не позволит такой роскоши, как подкрепить защиту конституционных прав граждан реальными действиями в ущерб шпионажу.
Ах, да… Ещё есть постоянно поддерживаемый в рекламе гунжёж от производителей дисков о шифровании прям электроникой диска, но там такой бездарный трэш, угар и бэкдорно-бутафорское шифрование, что это даже не хочется обсуждать вслух.
А тем временем…
При покупке нового диска выбора безгелиевых вариантов больше не осталось. Совсем! Они просто перестали продаваться. В результате пришлось скрипя зубами смириться с полной недоступностью понятия «долговечность» даже в теории и что диск покупается максимум на три года, при этом надо быть готовым, что даже через 2 года всё, что на нём может храниться одномоментно может перестать быть доступным раз и навсегда (есть такая особенность у гелиевых). В этот раз даже не было смысла исследовать статистику выхода дисков из строя — срок эксплуатации и так минимален и окирпичивание гарантировано производителем. На заведомо лживые маркетинговые посылы про 5 «гарантированных» лет даже не хотелось обращать внимания. Молекулы гелия настолько малы, что быстрая диффузия газа через металл корпуса диска (вот уж где действительно гарантированно) сыграет свою роль скорее рано, чем поздно. По сравнению с негелиевыми дисками диффузия это вопрос времени и никакие громкие заявления гнилых корпорастских маркетологов законы физики не отменят. С негелиевыми дисками (особенно с теми, где НЕ используется лазер для прогрева поверхности) ещё был шанс, что диск может прожить так долго, что столько даже и не нужно. Но в современных дисках как будто специально выбирают такие технологии, с заранее заложенным сроком эксплуатации, которые предполагают быстрый износ и деградацию материала носителя (прогрев лазером и улетучивающийся гелий). Простая аналогия — достаточно вспомнить шарики на детских праздниках и как быстро они перестают летать. Ведь они не сдуваются на самом деле, это гелий просачивается между молекулами материала и улетучивается! Но всё это — техническая лирика. А тем временем…
Новый диск приехал и настала очередь попытаться восстановить данные. Нет, не из бэкапа, а считать из старого диска на новый, ведь старый как-то, но всё же работает и в моём случае этим имело смысл воспользоваться.
Для этой цели существует просто восхитительный спасательный круг под названием GNU ddrescue! Это узкоспециализированный инструмент для восстановления данных с повреждённых дисков. Пытается считывать все секторы, пропуская плохие и возвращаясь к ним позже. Сохраняет «карту» диска в текстовом файле, расставляя на ней метки проблемных секторов, чтобы можно было прервать очень длительный процесс и продолжить позже. Принцип такой: считать что считывается в один проход, а потом что не удалось считать сразу, то читать снова, снова, снова и снова до тех пор, пока не удастся хоть что-нибудь, да прочесть. При последующих запусках перечитывается и обновляется составленная карта, устанавливается количество попыток перечитать бэдблоки, за счёт чего можно повторять многократно без риска перечитывать уже успешно скопированное. Всё, что для этого нужно, это исходный диск, целевой диск и запуск команд в несколько этапов:
С опцией -n — сначала считываем всё, не повторяя плохие сектора, чтобы быстро получить максимум данных и карту
ddrescue -f -n /dev/sdX /path/to/imagefile.img /path/to/mapfile.map
Потом следует попытка восстановления бэд-секторов, запуская утилиту уже с параметром -r3, что заставит программу попытаться прочитать плохие секторы 3 раза:
ddrescue -d -r3 /dev/sdX /path/to/imagefile.img /path/to/mapfile.map
mapfile.map это просто текстовый файл с номерами секторов бэдблоков. При просмотре можно увидеть диапазоны в каком-то внутреннем адресном пространстве. Если удалось прочесть за несколько попыток, то бэдблок убирается из «карты». Очевидно, что файл карты нужно размещать где угодно, но не на проблемном диске, с которого идёт копирование.
В опциях запуска всё предельно понятно, но может смутить только /path/to/imagefile.img Да, это именно файл-образ, файл-дамп исходного диска, как его делает dd (в названии есть dd помните?) Размер образа будет равен размеру исходного диска. Место бэдблоков в файле-образе заливается нулями. Если удаётся считать бэдблок при повторных запусках ddrescue, то те нули переписываются реальными данными. Таким образом проход за проходом количество несчитываемых бэдблоков уменьшается и файл-образ заполняется данными всё больше и больше. Это если исходный проблемный диск это позволяет. Я долго играл с опциями, уменьшал скорость считывания, увеличивал попытки перечитываний бэдблоков и это в конце концов дало свой положительный эффект!
У программы ddrescue море опций чтобы помочь достичь цели и считать данные с проблемного диска. Ими можно и нужно смело экспериментировать!
Например, диск может выдавать данные из проблемных секторов охотнее при уменьшении скорости чтения, поэтому можно попытаться ограничить максимальную скорость параметром:
--max-read-rate=2M
Это не уменьшит скорость шпинделя, но действительно может быть полезным когда диск входит в ступор на штатных скоростях считывания. Однозначно, этот параметр — прекрасный повод поэкспериментировать!
Если диск очень плохой, можно использовать ключ:
--no-scrape
чтобы ddrescue не пытался слишком долго ковырять мелкие плохие блоки.
Если диск уходит в «залипание» от больших диапазонов чтения, можно уменьшить считываемый блок:
--cluster-size=64
Чем мой случай уникален и почему было потрачено столько сил для восстановления данных со старого носителя на новый? Объясняется всё просто! Как известно, люди делятся на два типа. Те, кто уже делает бэкапы, и те, кто по наивности верит в «авось» и автосейв, а потом узнаёт цену потерянных семейных фотоархивов, исходников программ, биткоинов, утерянных библиотек избранной литературы и вообще всей оцифрованной жизни за несколько десятилетий. Учитывая мой богатый админский опыт, наивность уже давно позади и бэкапы есть. Но! Они находятся от меня ровно на расстоянии половины планеты, со скоростью доступа 2,5 мебибайта в секунду максимум. Учитывая объём, копирование могло бы занять полтора месяца в идеальном случае, увы недостижимом из-за падений скорости порой до 0,5 в часы пик, к тому же повторяющийся несколько раз в разных частях Земного шара. Стыдно признавать, но был ещё момент — оригинал и копия отставали друг от друга больше чем на месяц (ну конечно не из-за лени починить скриптик, а исключительно из-за технических нюансов, хе хе!).
Поэтому использование ddrescue оказалось хорошей идеей и всего за неделю я получил 9 терабайт, восстановленных из 10 (исходный диск к моменту сбоя был почти полностью забит, поэтому это почти 9Тб полезной нагрузки). Один терабайт остался в нечитаемых бэдблоках. И никакие ухищрения с настройками опций ddrescue больше не помогали вытащить ни байта. Финальный размер imagefile.img при этом составил 9 тебибайт. Ну и ладно! Уже неплохо — есть с чем работать!
Монтируем файл образа как обычный диск:
sudo losetup -Pf --show /path/to/imagefile.img
Получим что-то вроде /dev/loop0
После этого смотрим разделы:
lsblk /dev/loop0
Например, появятся:
/dev/loop0p1 /dev/loop0p2
Монтируем нужный раздел:
sudo mkdir -p /mnt/img sudo mount /dev/loop0p1 /mnt/img
Размонтирование и отключение:
sudo umount /mnt/img sudo losetup -d /dev/loop0
Хорошо, ddrescue отработал, восстановлено что было возможно. И что дальше? Вот тут надо разъяснить, что ddrescue работает на уровне блоков — он не знает и не проверяет файловую систему. Там где не удалось считать кусок файла программа просто вставит нули. В том месте, где хранилась метаинформация о размещении файлов и приключился бэдблок — будет потеряна информация о размещении файлов. Простая аналогия — письмо и дырокол. В письме ссылки на книги, страницы и строки, формирующие оригинальный текст. Дырокол может в произвольных местах оставить дыры в письме. Если дыра попала на название книги, то можно попытаться понять, что это было и тем самым восстановить ссылку на кусок оригинального текста. Если дырокол чпокнет по номеру страницы или строки — то всё, целый блок текста из ссылки окончательно утерян и восстановлению не подлежит. Так же и с файловой системой. Мой случай это EXT4. Она размазывает информацию о ветках древовидной файловой структуры по всему пространству (многократно резервируя). Какие последствия это за собой несёт? Потерю метаинформации о размещении файлов! Даже если удалось считать блок байт, составляющих полный объём файла, то не факт, что удастся восстановить метаинформацию о принадлежности этого блока байт к имени файла, файла к директории, этой директории к её материнской директории и так далее по цепочке. На самом деле это очень, очень грустно! Грустно потому, что после запуска fsck оказалось, что однозначно восстановить все первоначальные связи удалось только для 70% от тех 90% секторов. Всё остальное — мешанина из разных кусков файлов в директории lost+found. Итог не впечатляет. Больше недели трудов и восстановлено только 63% от изначального объёма файлов.
И-и-и… н-н-нет! Это ещё не все проблемы! Потому что неизвестно, сколько из восстановленных 63% файлов не содержат нулей вместо реальных данных в тех местах, где на диске были бэдблоки. А также fsck при исправлении ошибок файловой системы мог просто оторвать кусок файла прикинув, что и так сойдёт, а без остального можно и обойтись — просто размер поменяется. Получается то, что на восстановленном образе существуют файлы с нулями вместо реальных данных и не существует абсолютно никакой возможности понять, в каких файлах целостность не была нарушена, а какие файлы содержат замещённые нулями блоки данных!!! Почему так? Потому, что большинство файловых систем не считает и не хранит контрольных сумм! Именно поэтому невозможно понять, файл поломан или он действительно в некоторых своих местах содержит нули совершенно легитимно. Контрольные суммы это значительные накладные расходы и по CPU и по занимаемому пространству. Если Вы счастливый обладатель другой операционной системы, то не обольщайтесь — Ваша FS тоже не поддерживает контрольные суммы, благодаря которым можно было бы дать однозначный ответ: файл поломан или нет. Увы… имеем что имеем! Исключения есть и это парочка перегруженных фичами файловых систем, так «любимых» за сложность их настройки, использования, тормознутость, требовательность к ресурсам и баги (такие монстры как *ZFS, Btrfs, ReFS). Но смогут ли они помочь в восстановлении файлов, или борьбе с теми проблемами, которые возникли в результате выхода HDD из строя? Забавно, но нет! Контрольные суммы не содержат данных и не помогут восстановлению пропавшей информации (не путать с кодами коррекции ошибок в RAID) они служат только единственной задаче, ответить на вопрос: файл в полном порядке или целостность нарушена. К тому же, контрольные суммы где-то хранятся (правильно, на битом HDD) и могут попасть точно в такие же самые места, пробитые «дыроколом» и точно так же потеряться как и остальная метаинформация о целых директориях с файлами. Именно потому, что преимущества не очевидны, а накладные расходы огромны, контрольные суммы не используются в большинстве ФС, даже для проверки целостности метаданных, не то что для проверки целостности данных внутри файлов.
Надо обратить внимание, что весь процесс восстановления, синхронизации вовсе не был трудозатратным. Только неудобство: запустить команду и очень долго ждать завершения приходилось из-за объёмов и более чем скромных скоростей HDD дисков по сравнению с Solid State альтернативами.
А тем временем…
Пора́ сделать следующий шаг и синхронизировать недостающие данные с бэкапного диска. Проверенное временем и оптимальное средство для поставленной задачи это rsync. Тот же rsync с помощью которого синхронизировались файлы с основного на бэкапный, с его помощью будет и обратная операция. Смело запускаем:
rsync -aHAX --delete-after --progress --stats --partial --append-verify --ignore-times -e 'ssh -T -o Compression=no -o Ciphers=aes128-gcm@openssh.com,aes128-ctr -o MACs=umac-128@openssh.com,hmac-sha2-256' --exclude software/install/linux/os/ --exclude 'movie/tv series/' remote_user@remote-backup-host.com:/backup/ /destination_folder_on_the_new_HDD/
Всего неделя синхронизации и картина при повторном запуске rsync выглядит вообще очень мило и обнадёживающе:
Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total transferred file size: 0 bytes Literal data: 0 bytes Matched data: 0 bytes File list size: 0 File list transfer time: 0,000 seconds
Таким образом rsync сообщает, что все файлы идентичны и там и тут.
Прекрасно, да? За одним ма-а-а-леньким исключением: 100% идентичность источника и целевого диска ЭТО АБСОЛЮТНАЯ ЛОЖЬ!
Каким образом так могло получиться, что синхронизация добавила наши недостающие 37% с удалённого диска и ввела в полное заблуждение что в изначальных 63 процентах файлов (которые были восстановлены напрямую со старого диска) полный и абсолютный порядок? Очень просто — rsync сверяет путь и метаданные файлов (размер файла st_size и время последней модификации mtime) и на основании только этих трёх метрик принимает решение, идентичен файл или его нужно пересинхронизировать. Всё выглядит логично, но не для текущей ситуации, когда нужно сверять файлы байт-в-байт и только тогда принимать решение о полном соответствии или замене. Хорошо, для rsync и это не проблема, а вполне решаемая задача. С опцией -c/--checksum rsync рассчитывает контрольные суммы для каждого файла на обеих сторонах и при несовпадении действительно очень интеллектуально выбирает алгоритм и синхронизирует файл по частям (разбивает на чанки, сверяет контрольную сумму каждого чанка и синхронизирует только ту часть, CRC которой не совпала). Вроде всё идёт медленно, но уверенно. Но проходит несколько дней и процесс останавливается полностью. Что произошло? Банальный разрыв связи? Запускаем заново и… Что? Rsync весь расчёт контрольных сумм начал с самого начала? А почему не сохранить промежуточный результат между сессиями? Нет, не поддерживается? Ладно... бывает… Задача оказалась решаемой, но не в масштабе терабайтных объёмов и продолжающихся сеансов. Может есть альтернативы rsync? Да, есть, но буквально все — участники парада уродов: одна программа борется по убогости с другой и все стремятся занять первое место в конкурсе на самое отвратительное решение сделанное через ж.
А тем временем, решение нашлось! Пусть и не замена синхронизации, но альтернативный путь. И это — программа precizer
До появления этой программы в моей админской жизни была идея самостоятельно написать скрипты для хеширования и сравнения контрольных сумм стандартными системными инструментами. Но процесс обещал превратиться в бесконечный ад. Поэтому появился серьёзный повод найти радикально новый подход для поставленной задачи. Перебрав несколько инструментов (каждый со своими странностями и заморочками) я выбрал один наиболее простой и достаточно фичастый, как золотую середину между функциональностью и затраченным временем чтобы разобраться как именно им воспользоваться. Программа precizer позволяет создавать один файл со слепком всех контрольных сумм указанной директории и всеми поддиректориями. Укажем весь диск и поехали. У программы есть подготовленные исполняемые портируемые сборки как под x86-64 архитектуру, так и под arm64. Это именно то, что нужно для запуска на обеих машинах (под Gentoo, и на Raspberry Pi). Как скачать и запустить программу есть инструкция на несколько строк в README сайта.
Скачиваем и запускаем независимо на обеих машинах в tmux терминале:
# На первой машине: ./precizer /backup/ # На второй: ./precizer /destination_folder_on_the_new_HDD/
Это минимально необходимый набор действий. Да, вот так просто!
В результате на каждой из машин появится свой файл с базой данных контрольных сумм. По умолчанию имя файла будет совпадать с именем хоста:
# На первой машине: first_hostname.db # На второй: second_hostname.db
Да, это долгий процесс сам по себе. Для расчёта контрольных сумм нужно считать каждый байт из всех 10Tb.
В случае необходимости можно прерывать процесс сколько угодно раз — с файлом базы данных ничего не случится и процесс можно продолжить с прошлого места, просто добавив опцию -u/--update чтобы сообщить программе продолжить начатое, а не запускать всё заново (согласно мануалу этот флаг сделан для защиты от случайной модификации БД):
# На первой машине: ./precizer -u /backup/ # На второй: ./precizer -u /destination_folder_on_the_new_HDD/
А тем временем…
Всего за неделю был завершён расчёт контрольных сумм как на стороне backup сервера, так и на стороне домашнего компьютера. Каждый байт был считан с диска и стал частью контрольной суммы, записанной в файле БД. Программа очень лояльна к разрывам и прерыванию процесса. Причём продолжит расчёт контрольных сумм ровно с того места в файле, где была прервана. Даже если это была половина 150 гигабайтового файла, то precizer не станет рассчитывать его с самого начала, а продолжит с места разрыва. Это если прервать через Ctrl+C или сигналом преднамеренного прерывания. То же самое относится ко всей файловой системе. Если уже есть база данных, то для записанных в неё файлов контрольные суммы не будут рассчитываться заново. При прерывании программа достаточно быстро доходит до точки файловой системы где была остановлена и продолжит расчёт с неё. Очень крутые фишки как по-моему!
В результате получились два .db файла с именами хостов. Каждый .db файл размером около 500 мегабайт (ого, да?! Сам не ожидал) В программе используется алгоритм SHA-512, а это 512 бит (64 байта) на один файл + путь к файлу с его именем + метаинформация. Миллион, двести тысяч файлов.
После копирования обоих файлов БД на одну из машин начинается самое интересное — можно наконец-то увидеть реальную разницу между ФС дисков. Для этого есть опция -c/--compare
./precizer -c first_hostname.db second_hostname.db
Если за эталон взять состояние на backup-машине, все те файлы, контрольные суммы которых не совпадают на новом диске нужно удалить. Для этого я взял список файлов предоставленный precizer, скопировал в текстовый файл и добавил цикл с rm, превратив его в скрипт.
После удаления «битых» файлов и повторной синхронизации rsync в финале ещё раз был использован precizer, чтобы наверняка убедиться в 100% идентичности копии. На надёжность алгоритма SHA-512 действительно можно положиться и если обе контрольные суммы совпадают, то можно быть уверенным, что файлы абсолютно идентичны.
По сравнению с rsync программа precizer сущий младенец, которому не более пары лет. Однако нельзя сказать, что программа сырая. Богатая документация и заявленное покрытие кода тестами вызывают определённое уважение, а автоматизация сборки дарит скромную надежду на стабильность работы и отсутствие грубых ошибок, свойственных новоделу.
Что понравилось в программе
Конечно мне понравился результат! Удалось чётко понять какие файлы после восстановления и последующей синхронизации оказались с «дырками» или просто подрезанными несмотря на то, что согласно FS-метаинформации данные должны быть в полном порядке. Таких файлов оказалось около сотни тысяч из общего количества более чем в миллион. Очевидно, что без precizer, вручную, мне бы просто физически не удалось бы удостовериться, что домашний диск после восстановления данных байт-в-байт идентичен эталонному на backup-сервере. Теперь, со времён инцидента, я постепенно внедряю precizer во все этапы бэкапирований. Не только в процессе восстановления, но и после синхронизации на удалённый сервер важно быть уверенным, что в бэкапе точная копия оригинала. Пока не всё автоматизировано но я к этому стремлюсь.
Скорость. Я для интереса померял как быстро считает контрольные суммы штатная системная утилита sha512sum и сравнил с precizer. Результат оказался один в один и по факту упирается в аппаратную производительность самого диска. Что интересно, та же штатная sha256sum работает помедленнее. Поэтому можно сделать вывод, что выбор алгоритма был оптимальным, хотя странно, что алгоритм только один и без выбора вариантов. Ну да это и не великая проблема — свою задачу программа выполняет. Ради интереса я также проверял совпадают ли SHA-512, созданный системной утилитой sha512sum с тем хешем, который генерирует precizer и сохраняет в БД. Ожидаемо да, совпадает.
Документация на русском языке. Удобно. Для меня время имеет значение, и на русском чтение и усваивание информации происходит раза в четыре быстрее, чем на остальных из всех трёх известных мне языков.
Что НЕ понравилось или хотелось, чтобы работало по-другому
Отсутствие прогрессбара в стиле копирования у Midnight Commander с общим прогрессом, прогрессом расчёта контрольной суммы каждого файла, средней скоростью, планируемым временем завершения. Есть малоинформативная опция --progress, но от неё мало толку. Она делает первый прогон по всему дереву файлов и выводит общую статистику: занимаемое место, количество файлов, директорий и что-то ещё по-мелочи.
Очередь вывода на экран. Так как нет прогрессбара, то невозможно понять, что происходит в текущий момент. Когда программа работает над очень большим файлом этого просто не видно. Строка о том, что файл обсчитан и добавлен в БД появляется только ПОСЛЕ расчёта контрольной суммы, а между началом этого процесса и появлением строки складывается ощущение, что программа зависла, потому что ничего не происходит и видна история только уже обработанных файлов.
Я немного поэкспериментировал с программой, примеряя её для гораздо более широкого использования, чем просто в домашних условиях и вот что заметил. Если прерывать программу штатными средствами (преднамеренное прерывание через Ctrl+C или kill -15) то действительно, данные с не до конца рассчитанным файлом сохраняются в БД. Но если использовать системный kill -9, когда само ядро бескомпромиссно отстреливает процесс, тогда нет, данные в БД не попадают даже при очень длительной работе над огромным файлом. Хотя в программе заявляется полная толерантность к сбоям, но ситуация с вырубанием питания при обсчёте большого файла не обрабатывается. Нужно отметить, что все те файлы, контрольные суммы которых уже обсчитаны и попали в базу данных, там и останутся несмотря на внезапный ребут. При повторном запуске расчёт контрольных сумм действительно не будет начат с самого начала, а продолжен только для необсчитанных файлов.
Многопоточность. Её просто нет. Заявленная суперпроизводительность упирается в один поток на одном ядре для всех дисковых операций. Для домашних нужд очевидно, большего и не надо, особенно с HDD, для которых параллельное чтение является злом во плоти. Но hero-текст на сайте заявляет поддержку от embedded до кластерных-супер-пупер-решений. Несмотря на громкие заявления пока эта фича остаётся только в roadmap (вернее, две фичи разных видов распараллеливания). С другой стороны многопоточности нет даже у rsync, которому сто лет в обед. Нет там её даже в планах.
README явно перенасыщен информацией на все случаи жизни. Хотя стоит признать, что приведённые живые примеры это действительно удобно, такое редко где можно найти в документации на опенсорсное ПО, где в лучшем случае можно бесконечно читать описание бесконечных опций man страницы так и не поняв как их применить вместе (rsync тому пример)! Хотя… может это на самом деле преимущество, а не недостаток! Ведь можно скинуть ссылку на Readme предпочитаемому AI и вообще не читая документацию сразу получить совершенно адекватные ответы на любые вопросы и настройки опций для запуска. Я так и делал. Мега удобно!
Буду рад ответить на вопросы в коментариях. Всем успехов в IT делах!

