Скопировали 8 ТБ по сети и получили сорок отличий
Перенос 8 терабайт между серверами занял ночь, лог rsync закрылся без единой строки с ошибкой, счётчик файлов на входе и на выходе совпал. Логичный вывод — перенос успешен, можно выключать старый сервер. Отдельная сверка контрольных сумм, запущенная скорее для очистки совести, нашла сорок файлов, где сумма на источнике и на приёмнике не совпадает. Ниже — что стоит за этими сорока файлами и почему при таких объёмах верификация после копирования обязательна, а не опциональна.
Содержание
- Что произошло: 8 ТБ, чистый лог и сорок расхождений
- Почему «скопировалось без ошибок» не значит «скопировалось верно»
- Откуда берутся редкие расхождения при передаче больших объёмов
- Почему объём данных меняет расчёт: одна ошибка на миллион — это не ноль
- Практическая схема: сверка контрольных сумм после копирования, а не вместо него
- Что делать с найденными расхождениями
Что произошло: 8 ТБ, чистый лог и сорок расхождений
Сценарий стандартный: старый файловый сервер выводится из эксплуатации, данные — 8 ТБ смешанного контента, от логов и бэкапов до пользовательских файлов — нужно перенести на новый до отключения старого. Перенос запущен через rsync поверх SSH, с разбивкой на несколько параллельных потоков по каталогам, чтобы уложиться в разумное время. Копирование заняло около десяти часов, в логе — ни одной строки с ошибкой, rsync завершился с кодом 0 по каждому потоку, число файлов на входе и на выходе совпало посимвольно.
По всем формальным признакам, которые обычно и принимают за критерий успеха — перенос завершён. Именно на этом этапе большинство миграций такого рода объявляют закрытыми: файлы физически присутствуют на новом сервере, их количество совпадает, лог чист. Проблема в том, что «лог чист» и «содержимое идентично» — это разные утверждения, и разница между ними становится заметна только при прямом сравнении.
Отдельным шагом — уже не как часть процедуры переноса, а как дополнительная проверка — по всему дереву каталогов на источнике и на приёмнике были посчитаны контрольные суммы (sha256sum) и сверены построчно. Из нескольких миллионов файлов сорок дали разные суммы на источнике и на приёмнике. Не «файл отсутствует» — такую ошибку rsync бы заметил и по счётчику файлов, и по коду возврата. Именно другое содержимое при том же имени, том же размере в большинстве случаев и тех же правах доступа.
Почему «скопировалось без ошибок» не значит «скопировалось верно»
rsync (как и scp, как и большинство инструментов копирования по сети) полагается на транспортный уровень — TCP — в вопросе целостности передаваемых байт. TCP действительно проверяет контрольную сумму каждого сегмента и переспрашивает повреждённые пакеты, и на этом основании принято считать, что если соединение не оборвалось и приложение не сообщило об ошибке, то данные дошли байт в байт. Это верно в подавляющем большинстве случаев — и именно поэтому редкие исключения так легко проходят незамеченными: инструмент не соврал о наличии ошибки, потому что на своём уровне её действительно не увидел.
Контрольная сумма TCP — это защита от определённого класса повреждений на конкретном участке пути, а не сквозная гарантия для всего маршрута от диска источника до диска приёмника. Данные на этом пути проходят через несколько независимых слоёв: чтение с диска источника, буферизация в памяти, драйверы сетевых карт, коммутаторы и маршрутизаторы между серверами, буферизация на приёмнике, запись на диск приёмника. Ошибка, возникшая не на уровне TCP-сегмента, а, например, при чтении блока с диска источника ещё до того, как данные попали в сеть, или при записи на диск приёмника уже после того, как TCP успешно подтвердил доставку — пройдёт мимо всех проверок транспортного протокола просто потому, что она произошла не в его зоне ответственности. С точки зрения rsync и TCP всё было передано верно — потому что технически так и было, испорчен оказался не переданный поток, а то, что было прочитано на входе или записано на выходе.
Про похожий по духу, но другой по механизму случай — когда rsync тоже отчитывается об успехе, а файл на приёмнике оказывается другим — есть отдельный разбор: rsync отчитался об успехе, а файл на приёмнике другой. Стоит иметь в виду, что причины расхождения бывают разными, и «сеть виновата» — не единственная и не всегда верная гипотеза; иногда дело в самом инструменте копирования и его настройках, а не в передаче как таковой.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверОткуда берутся редкие расхождения при передаче больших объёмов
Причины, по которым отдельный файл может дойти испорченным при в целом исправной инфраструктуре, лежат на нескольких уровнях, и ни один из них не является экзотикой:
- Промежуточное сетевое оборудование. Коммутаторы и маршрутизаторы на пути между серверами — это тоже вычислительные устройства с собственной памятью и прошивками: переполнение буфера при всплеске нагрузки, редкая ошибка в прошивке, деградация порта. Такие сбои обычно приводят к потере или повреждению пакета, что TCP как раз обрабатывает штатно — но не исключают более редких сценариев, когда повреждение происходит уже после проверки контрольной суммы сегмента.
- Кратковременные проблемы канала. Наводки, деградация кабеля или трансивера, кратковременная перегрузка линка увеличивают частоту ошибок на физическом уровне. Протоколы канального и транспортного уровня в норме их полностью компенсируют повторной передачей — но компенсация штатного механизма не означает, что вероятность редкого несовпадения на конкретном сегменте равна нулю.
- Память и буферизация на серверах. Данные перед отправкой и после приёма какое-то время живут в оперативной памяти — в буферах приложения, в page cache операционной системы. Редкие сбои памяти (не обязательно неисправность модуля — влияет и температура, и электромагнитные наводки) на серверах без ECC-памяти не обнаруживаются и не исправляются на лету, и в отличие от сетевых протоколов, ничем не перепроверяются автоматически.
- Диск источника и диск приёмника. Чтение блока с уже слегка деградировавшего сектора на источнике или ошибка при записи на приёмнике происходит до и после сетевой передачи соответственно, поэтому сетевые механизмы контроля целостности такую ошибку в принципе не видят.
Каждый из этих механизмов в отдельности спроектирован так, чтобы ошибки предотвращать или тут же исправлять, и в среднем справляется с этим хорошо. Проблема не в том, что какой-то из уровней ненадёжен, а в том, что уровней много, независимых точек отказа тоже много, и когда через всю цепочку проходит не один файл, а несколько миллионов, даже очень редкое событие на каждом отдельном уровне рано или поздно где-то да случается. Точную вероятность по каждому из механизмов приводить не будем — она сильно зависит от конкретного оборудования, канала, температуры в стойке и десятка других факторов, и любые «средние» цифры здесь будут скорее вводить в заблуждение, чем помогать.
Почему объём данных меняет расчёт: одна ошибка на миллион — это не ноль
Ключевая мысль для больших объёмов простая: если вероятность повреждения на отдельный файл (или отдельный передаваемый блок) — пусть и очень маленькая — отлична от нуля, то при достаточно большом количестве файлов вероятность встретить хотя бы одно расхождение перестаёт быть пренебрежимо малой. Это обычная статистика редких независимых событий: чем больше попыток, тем выше суммарная вероятность хотя бы одного отклонения, даже если вероятность каждого отдельного отклонения крошечная.
Практический вывод: перенос в 200 МБ и перенос в 8 ТБ — качественно разные по риску операции, даже с одним и тем же инструментом и настройками. При 200 МБ отсутствие ошибок в логе с высокой вероятностью действительно означает, что всё скопировалось верно, — попыток слишком мало, чтобы редкое событие успело произойти. При нескольких терабайтах, особенно из множества отдельных файлов, тот же вывод из того же чистого лога уже не так надёжен просто потому, что попыток было на порядки больше.
Отсюда практическое правило: чем больше объём переноса, тем меньше оснований полагаться на «код возврата 0» как на единственный критерий успеха, и тем важнее отдельный шаг верификации после копирования. Это не значит, что инструмент копирования плохой или сеть ненадёжная — это значит, что при больших объёмах стоит закладывать проверку в процесс по умолчанию, а не как реакцию на подозрения.
Практическая схема: сверка контрольных сумм после копирования, а не вместо него
Главная ошибка в организации переноса — не в выборе инструмента, а в том, что верификация целостности либо не выполняется вообще, либо подменяется проверкой самого факта завершения копирования (код возврата, совпадение количества файлов, совпадение суммарного размера в байтах). Ни один из этих признаков не проверяет содержимое файлов — только его косвенные атрибуты, которые могут совпасть даже при испорченном содержимом.
Рабочая схема для переноса большого объёма выглядит так:
- Копирование — обычным способом, rsync, scp или что удобнее в конкретной инфраструктуре. Флаг
-c(checksum) у rsync можно не включать на этом этапе — он заметно замедляет сам перенос, пересчитывая суммы для решения «копировать или нет», и это не то же самое, что независимая проверка результата. - Расчёт контрольных сумм на источнике — после завершения копирования, по уже стабильному, не изменяющемуся дереву каталогов:
cd /data
find . -type f -print0 | xargs -0 sha256sum > /tmp/checksums_source.txt
- Перенос файла с суммами на приёмник отдельно от основного массива данных — он маленький, копируется мгновенно и его тоже стоит копировать явно, а не полагаться на то, что он «тоже часть той же передачи».
- Расчёт контрольных сумм на приёмнике — той же командой, по тому же относительному дереву:
cd /data
find . -type f -print0 | xargs -0 sha256sum > /tmp/checksums_target.txt
- Сверка:
diff <(sort /tmp/checksums_source.txt) <(sort /tmp/checksums_target.txt)
Строки, которые попали в diff, — это файлы, где суммы не совпали или файл отсутствует на одной из сторон. Именно на этом шаге в описанном случае и всплыли сорок расхождений — без него они остались бы незамеченными до первого обращения к одному из этих файлов в продакшене, что почти всегда происходит не в удобное время.
Для объёма в несколько терабайт полный пересчёт sha256sum по всем файлам может занимать часы — это ожидаемо, и ускорять его стоит не пропуском проверки, а распараллеливанием расчёта (xargs -P или parallel) и выбором алгоритма с балансом между скоростью и надёжностью. Подробный разбор, как сократить время расчёта на больших объёмах без потери достоверности проверки, — в отдельной статье: sha256 от четырёх терабайт считается шесть часов: как проверять быстрее.
Отдельный нюанс, о котором легко забыть: сумму на источнике нужно считать именно после того, как копирование полностью завершилось, а не во время него и не заранее — если исходные данные хоть немного меняются в процессе (логи дописываются, кэш обновляется), сравнение с более ранним снимком даст ложные расхождения, не имеющие отношения к качеству передачи. И наоборот, если источник продолжает изменяться уже после снятия суммы, но до того как с ним свериться — есть шанс поймать не ошибку передачи, а обычное легитимное изменение файла. Про похожую ловушку — когда контрольная сумма формально сошлась, а файл всё равно оказался проблемным из-за момента её расчёта — есть отдельный разбор: контрольная сумма сошлась, а файл битый: когда MD5 вас обманет.
Что делать с найденными расхождениями
Найти сорок расхождений на 8 ТБ — не повод перезапускать перенос целиком. Правильный порядок действий:
- Изолировать список расхождений. Вывод
diffиз предыдущего шага уже даёт точный перечень путей — с ним и нужно работать дальше, не трогая остальные файлы. - Перепроверить, что источник действительно не менялся. Если сам источник — активно используемая директория (логи, база), часть расхождений может оказаться ложной: файл успел измениться между копированием и расчётом суммы. Стоит пересчитать сумму источника ещё раз именно для этих сорока файлов и сравнить с первым замером.
- Докопировать только проблемные файлы, а не всё дерево заново. У rsync для этого есть смысл явно перечислить список файлов:
rsync -av --files-from=/tmp/bad_files.txt /data/ user@target:/data/
Это на порядки быстрее полного повторного переноса 8 ТБ и решает именно найденную проблему.
- Свериться повторно после докопирования. Пересчитать суммы уже только по списку из сорока файлов на обеих сторонах и убедиться, что теперь они совпадают. Пропускать этот шаг — то же самое исходное допущение «раз команда отработала, значит всё в порядке».
- Если расхождения повторяются регулярно на одних и тех же участках — стоит смотреть уже не на перенос как разовое событие, а на инфраструктуру: конкретный сетевой порт, конкретный диск, конкретный сервер. Систематическая порча данных обычно указывает на деградирующее железо, а не на статистическую случайность передачи.
Похожий разбор — когда после переноса больших объёмов формально всё оказалось на месте, но реальная проблема лежала не в содержимом файлов, а в правах доступа, — здесь: скопировали 2 ТБ и потеряли права доступа: rsync без одного флага. Оба случая объединяет одно: формальный успех переноса и фактическая целостность результата — разные вещи, и вторую нужно проверять отдельно.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Нужно ли всегда сверять контрольные суммы после переноса, даже если объём небольшой?
Строго — не обязательно, но привычка того стоит: сама проверка занимает предсказуемое время и почти ничего не стоит по ресурсам сервера, а цена пропущенного расхождения — это испорченные данные, обнаруженные в продакшене в неудобный момент.
Можно ли использовать rsync с флагом -c вместо отдельного расчёта sha256 после копирования?
Флаг -c заставляет rsync сравнивать контрольные суммы вместо времени изменения и размера файла при решении, копировать файл заново или нет — это полезно при повторных запусках и докопировании, но не заменяет независимую верификацию: если файл испортился уже после того, как rsync его скопировал (например, при записи на диск приёмника), повторный запуск с -c этого не поймает, если сама команда решит, что копировать нечего.
Что делать, если контрольные суммы на источнике и приёмнике не совпали, а файл на источнике уже недоступен (старый сервер выключен)?
Именно поэтому расчёт и сверку сумм стоит делать до отключения источника, а не после — это отдельный аргумент за то, чтобы включить верификацию в саму процедуру переноса как обязательный шаг, а не как факультативную перепроверку «на всякий случай».
Насколько велика вероятность встретить такое расхождение при переносе, скажем, 500 ГБ?
Точную цифру никто честно не назовёт — она зависит от конкретного оборудования, канала и десятков других переменных, и любые общие проценты здесь были бы гаданием. Практический ориентир проще: чем больше объём и чем больше отдельных файлов, тем выше смысл в отдельной верификации, вне зависимости от конкретной вероятности на файл.
Меняется ли что-то, если переносить данные не по сети, а локально, между дисками одного сервера?
Часть рисков (промежуточное сетевое оборудование, канал) отпадает, но риски со стороны диска и памяти остаются — поэтому верификация после переноса имеет смысл и для больших локальных копирований, не только сетевых.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →