sha256 от четырёх терабайт считается шесть часов: как проверять быстрее
Вы запускаете sha256sum на файле в четыре терабайта — резервной копии, образе диска, датасете — и процесс растягивается на часы. Проблема не в алгоритме: одна команда читает файл последовательно и гоняет его через один поток CPU, не используя остальные ядра сервера и часто не выбирая всю пропускную способность диска. Ниже — рабочие способы ускорить проверку контрольных сумм на больших объёмах данных без потери надёжности там, где она реально нужна.
Содержание
- Куда уходит время при пересчёте контрольной суммы
- Параллельная проверка нескольких файлов одновременно
- Блочное хеширование: не пересчитывать файл целиком заново
- Быстрые некриптографические алгоритмы: где скорость важнее стойкости
- Куда реально упирается скорость: диск, сеть, CPU
- Практическая схема проверки для тома на несколько терабайт
Куда уходит время при пересчёте контрольной суммы
sha256sum bigfile.img — это один процесс, один поток чтения и один поток вычисления хэша. Пока файл не дочитан до конца, результата не будет, и распараллелить *этот конкретный вызов* штатными средствами coreutils нельзя. При этом сам SHA-256 не самый дешёвый алгоритм: он спроектирован так, чтобы быть трудозатратным, — это осознанная плата за криптографическую стойкость.
На практике время уходит на два независимых узких места:
- Чтение с диска. Для одного крупного файла это обычно последовательное чтение — на вращающемся HDD оно и так близко к пределу диска. На SSD/NVMe картина другая: одиночный поток часто не выбирает всю пропускную способность накопителя, потому что современные накопители спроектированы под параллельные запросы, а не под один длинный последовательный поток.
- Вычисление хэша. Один поток CPU считает SHA-256 над прочитанными данными. Если чтение быстрее, чем один поток успевает хэшировать, узким местом становится CPU — и это легко упустить, глядя только на
iostat.
Отдельная ловушка: проверять контрольную сумму файла, в который в этот момент кто-то пишет (лог, растущая база, активный дамп), бессмысленно — результат будет от «моментального снимка», который никогда не существовал целиком. Проверять есть смысл только статичные данные: после stop сервиса, на снапшоте или на уже отправленной копии.
Прежде чем ускорять, стоит понять — упираетесь вы в диск или в CPU. Во время прогона в соседнем терминале посмотрите iostat -x 1 и top: ядро под 100% при ненасыщенном диске — CPU-bound, насыщенный диск при свободном CPU — диск. Это определяет, какой из следующих приёмов даст эффект.
Параллельная проверка нескольких файлов одновременно
Если данные — это не один гигантский файл, а множество файлов (архив бэкапов, датасет из тысяч объектов, слепки виртуальных машин), самый простой и часто самый эффективный приём — считать их параллельно.
Через xargs:
find /data -type f -name '*.img' -print0 \
| xargs -0 -P 8 -I{} sha256sum {} >> checksums.txt
Флаг -P 8 запускает до восьми процессов sha256sum одновременно. Через GNU parallel — примерно то же самое, но с более гибким управлением выводом и повторами при сбоях:
find /data -type f -name '*.img' -print0 \
| parallel -0 -j"$(nproc)" --joblog parallel.log sha256sum {} > checksums.txt
--joblog полезен на больших прогонах: если процесс прервётся (обрыв сессии, перезагрузка), по логу видно, какие файлы уже посчитаны, и можно перезапустить только оставшиеся.
Сколько параллельных задач ставить — вопрос не «чем больше, тем лучше». На одном вращающемся диске или RAID без запаса по IOPS параллельные потоки превращаются в конкурирующие seek-и, и совокупная скорость может *упасть* по сравнению с последовательным чтением одного файла за раз. На SSD/NVMe, наоборот, параллелизм обычно помогает — накопитель спроектирован обрабатывать несколько запросов в очереди одновременно, и один поток эту очередь не заполняет. У предела параллелизма конкретного диска есть отдельный разбор — сколько параллельных потоков выдержит один диск до того, как очередь начинает расти быстрее скорости.
Практический подход — не гадать, а измерить: запустить с -P 2, -P 4, -P 8, -P 16 на выборке файлов и сравнить общее время. Оптимум для NVMe часто в районе числа ядер CPU, для сетевого хранилища — в районе допустимого числа одновременных соединений, для одиночного HDD иногда лучший результат вообще при -P 1.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверБлочное хеширование: не пересчитывать файл целиком заново
Параллелить по файлам — хорошо, когда файлов много. Но что делать с одним огромным файлом — образом виртуалки на несколько терабайт или дампом базы, который меняется частично (дозапись, снапшот поверх предыдущего)? Здесь помогает блочное хеширование: файл делится на блоки фиксированного размера, для каждого блока считается своя контрольная сумма, и все они складываются в манифест вместе со смещениями.
Практически это выглядит так:
# Разбить файл на блоки по 1 ГиБ (без физического копирования — split создаёт куски)
split -b 1G --numeric-suffixes=1 bigfile.img bigfile.chunk_
# Посчитать хэш каждого блока параллельно
ls bigfile.chunk_* | parallel -j"$(nproc)" 'sha256sum {} > {}.sha256'
# Собрать манифест: имя блока + его хэш
cat bigfile.chunk_*.sha256 | sort -k2 > bigfile.manifest.sha256
Это даёт два выигрыша. Во-первых, вычисление одного большого файла становится параллелизуемым — каждое ядро считает свой блок. Во-вторых, и это важнее для повторной проверки: если после первого прогона изменилась только часть файла (дозаписали хвост лога, обновили регион образа диска), достаточно пересчитать хэши только изменившихся блоков и сравнить их с манифестом — не трогая то, что точно не менялось. На файле в несколько терабайт, где реально «шевелится» пара процентов, это превращает повторную проверку из часов в минуты.
Важный нюанс: «блочный манифест» — не то же самое, что sha256sum от файла целиком, сравнивать их напрямую нельзя. Манифест — ваш собственный формат: размер блока, порядок, алгоритм — это нужно зафиксировать и не менять между прогонами. Саму манифест-таблицу тоже стоит защитить контрольной суммой — иначе не отличить повреждение данных от повреждения списка ожидаемых хэшей.
Так по сути работают инструменты бэкапа с дедупликацией и передача файлов по частям (rsync считает скользящие контрольные суммы блоков, торрент-клиенты и системы вроде IPFS строят дерево хэшей над чанками) — идея одна: не гонять заново то, что не изменилось. Похожий принцип, но на уровне множества файлов, а не блоков одного, разобран в материале про контроль целостности файлов без агента.
Если писать свой манифест-скрипт не хочется, присмотритесь к алгоритму BLAKE3 — он спроектирован как дерево Меркла изначально, и справочная реализация (b3sum) умеет параллелить хэширование одного файла по нескольким ядрам «из коробки», без ручного разбиения на блоки. Это не равнозначная замена SHA-256 там, где формат жёстко требует именно его, но там, где выбор алгоритма за вами — рабочий вариант получить блочный параллелизм без самодельного манифеста.
Быстрые некриптографические алгоритмы: где скорость важнее стойкости
SHA-256 — криптографический алгоритм: он специально спроектирован так, чтобы было вычислительно невозможно подобрать два разных набора данных с одинаковым хэшем (коллизию) или подделать данные под уже известную сумму. Это именно то, что нужно, когда контрольная сумма защищает от намеренной подмены — проверка подписанных дистрибутивов, релизов ПО, любых данных, которые мог модифицировать злоумышленник.
Но во множестве административных задач угроза другая: не злоумышленник, а случайное повреждение — битый сектор, сбой при передаче по сети, ошибка в памяти без ECC, тихая деградация данных на диске. Для обнаружения такой порчи криптографическая стойкость избыточна, а её цена в виде вычислительной нагрузки не бесплатна. В этих случаях разумно перейти на более дешёвые алгоритмы:
| Алгоритм | Тип | Устойчив к намеренной подделке | Типичное применение |
|---|---|---|---|
| SHA-256 / SHA-3 | криптографический | да | подписи, дистрибутивы, защита от подмены |
| BLAKE3 | криптографический, оптимизирован под скорость | да | замена SHA-256 там, где формат не фиксирован жёстко |
| xxHash (xxh3) | некриптографический | нет | дедупликация, быстрая сверка файлов, кэш-ключи |
| CRC32 / CRC32C | контрольная сумма, часто аппаратно ускорена | нет | обнаружение случайных битовых ошибок при передаче/хранении |
Оговорка про порядок величины: конкретный выигрыш в скорости зависит от процессора, реализации и того, упираетесь вы в CPU или в диск — точных цифр не назову, на вашем железе они будут свои. Общее правило — чем меньше у алгоритма встроенной криптографической «работы», тем меньше CPU-времени он ест на тот же объём данных.
Ключевое ограничение: CRC32 и xxHash не защищают от намеренной подделки — подобрать данные под заданную сумму CRC тривиально по вычислительным меркам. Использовать их там, где вы проверяете, что файл не подменил злоумышленник или недоверенная сторона (скачанный дистрибутив, чужой архив, данные из ненадёжного источника) — ошибка. А там, где источник и канал доверенные и нужно поймать случайную порчу бита при копировании между своими серверами или многолетнем хранении — это ровно тот инструмент, что нужен, и он ощутимо дешевле по CPU.
Отдельно про MD5: он тоже криптографический хэш, но давно и практически взломан в части устойчивости к коллизиям — подделать данные под заданную сумму MD5 умеют массово доступные инструменты. Ради скорости он не стоит: выигрыш относительно современных реализаций SHA-256 (особенно с аппаратными SHA-инструкциями) незначительный, а по надёжности это шаг назад.
Куда реально упирается скорость: диск, сеть, CPU
Прежде чем добавлять параллелизм или менять алгоритм, полезно определить, что именно у вас узкое место — иначе можно потратить время на оптимизацию не того звена.
Одиночный вращающийся диск (HDD). Практически всегда bottleneck сам диск: головка не может читать в двух местах сразу, параллельные запросы к одному HDD часто замедляют работу лишними перемещениями головки. Выигрыш здесь даёт не параллелизм чтения, а более дешёвый алгоритм (если CPU не успевает за диском) или блочное хеширование, чтобы избежать повторного чтения неизменившихся частей.
SSD/NVMe. Параллелизм обычно окупается — накопитель умеет обрабатывать несколько запросов одновременно (глубина очереди), и один поток эту очередь не насыщает. Как устроена эта параллельность на уровне очередей команд, разобрано в материале про предел одного диска.
Сетевое хранилище (NFS, SMB, объектное хранилище). Узкое место чаще не пропускная способность, а задержка на каждый запрос. Параллельные запросы «скрывают» задержку — пока ждём ответа на один, отправляем следующий. Число потоков стоит соотносить с лимитами сервера хранилища на одновременные соединения.
CPU. Узкое место, когда диск явно не насыщен, а ядро с хэшированием — под 100%. Решение — параллелить по файлам/блокам, задействуя больше ядер, либо переходить на более дешёвый алгоритм там, где криптостойкость не требуется.
Стоит перепроверять этот диагноз время от времени, а не полагаться на него навсегда — конфигурация диска и объём данных меняются, и то, что было CPU-bound на старом NVMe, может стать I/O-bound на новом RAID-массиве с медленными дисками, и наоборот.
Практическая схема проверки для тома на несколько терабайт
Собираем разобранные приёмы в рабочий процесс, который реально сокращает время с часов до разумных величин на регулярной основе.
Первый полный прогон. Занимает заметное время — этого не избежать, если вы ещё ни разу не строили базовый манифест. Здесь используем параллельную проверку по файлам (или по блокам для отдельных гигантских файлов), подобрав степень параллелизма под тип накопителя. Результат — манифест: путь к файлу (или блоку), размер, время изменения (mtime), алгоритм, хэш.
find /data -type f -printf '%p\t%s\t%T@\n' > /data/.manifest.meta
find /data -type f -print0 | parallel -0 -j"$(nproc)" sha256sum {} > /data/.manifest.sha256
Повторные прогоны — инкрементально. Идея та же, что в системах контроля целостности файлов: не пересчитывать то, что точно не менялось. Перед пересчётом сравниваем текущие size/mtime файлов с сохранёнными в манифесте — пересчитываем только для тех, у кого метаданные изменились или кто появился заново. Это не отменяет периодическую полную проверку (изменение данных без изменения mtime — редкий, но реальный случай), но резко сокращает *обычные* прогоны.
Планирование по расписанию. Полную проверку разумно ставить не чаще, чем требует ваша модель рисков (например, раз в квартал — как и другие периодические проверки на больших томах, для которых тоже приходится заранее закладывать окно обслуживания, см. сколько длится fsck на 10 терабайтах), а инкрементальную — хоть каждую ночь через cron.
Алертинг. sha256sum -c manifest.sha256 возвращает ненулевой код выхода, если хоть одна сумма не сошлась — этого достаточно, чтобы завернуть проверку в скрипт с уведомлением в мониторинг при первом же расхождении.
Отдельное хранение манифеста. Манифест стоит держать не на том же томе, что и проверяемые данные, с собственной резервной копией и своей контрольной суммой. Если носитель с данными деградирует, нужен независимый источник истины о том, какими хэши должны быть.
Комбинация «параллельность по файлам + блочность для гигантских файлов + инкрементальность по mtime + более дешёвый алгоритм там, где это оправдано моделью угроз» обычно сокращает время *повторной* проверки на порядок по сравнению с наивным одним вызовом sha256sum по кругу — первый полный прогон вы всё равно проведёте один раз, это неизбежная плата за базовый манифест.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли пересчитать SHA-256 на GPU и получить кратное ускорение?
Технически можно, но для типичной задачи проверки файлов на сервере это редко оправдано: узким местом почти всегда оказывается диск или сеть раньше, чем видеокарта успевает показать преимущество, а сложность инфраструктуры не окупается. GPU уместен для специализированных нагрузок, но не для рутинной проверки целостности бэкапов.
Правда ли, что MD5 заметно быстрее SHA-256 и его можно использовать ради скорости?
На современных CPU с аппаратными SHA-инструкциями разница обычно не настолько велика, чтобы оправдать переход на алгоритм с известными практическими атаками на коллизии. Нужна скорость — берите xxHash, CRC32C или BLAKE3, а не MD5.
Как проверить, что диск успевает за параллельными потоками, а не просто создаёт видимость нагрузки?
Смотрите iostat -x 1: если %util близок к 100% и очередь запросов (aqu-sz) растёт вместе с числом заданий, диск действительно занят полезной работой. Если %util далёк от предела при высоком -P, накопитель ещё не насыщен.
Что делать с файлом, который меняется прямо во время расчёта хэша?
Считать контрольную сумму активно изменяющегося файла бессмысленно — результат непредсказуем. Сначала остановите запись (снапшот, stop сервиса, блокировка на запись) — только после этого сумма имеет смысл для сравнения.
Есть ли смысл сжимать данные перед хешированием, чтобы уменьшить объём чтения?
Если данные уже сжаты (архив, снапшот со сжатием) — хешируйте как есть; сжатие на лету добавит CPU-нагрузку и не ускорит чтение с диска.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →