MAATRIX / Блог / Почему шифрованный диск почти не тормозит, а шифрованный бэкап тормозит заметно

Почему шифрованный диск почти не тормозит, а шифрованный бэкап тормозит заметно

MAATRIX

Включили LUKS на диске сервера — и ничего не заметили: нагрузка не выросла, диски отзываются как прежде. А потом настроили шифрованный бэкап тем же restic или borg — и первый же прогон занял заметно больше времени, чем без шифрования, процессор загружен, а окно бэкапа приходится расширять. Логика подсказывает, что раз шифрование одно и то же (AES), разницы быть не должно. На практике разница есть, и она системная: диск и бэкап шифруются на разных уровнях архитектуры, разными инструментами, и вокруг самого шифрования в случае бэкапа обычно происходит куда больше дополнительной работы. Разберём, откуда берётся эта разница и что с ней делать.

Как устроено шифрование диска целиком

Полнодисковое шифрование (full disk encryption) — например, LUKS поверх dm-crypt в Linux — работает не с файлами, а с блочным устройством. Между файловой системой и физическим диском (или виртуальным диском VPS) встраивается прозрачный слой: каждый блок данных при записи на диск шифруется, при чтении — расшифровывается. Для файловой системы, приложений и пользователя это полностью невидимо — они обращаются к обычному блочному устройству /dev/mapper/имя, как будто шифрования нет вообще.

Ключевое архитектурное решение здесь — единица работы. Шифруется не файл целиком и не поток данных произвольной длины, а фиксированный блок (обычно 512 байт или 4 КБ, в зависимости от режима). Каждый такой блок шифруется независимо от соседних, обычно в режиме XTS — специально спроектированном для шифрования блочных устройств так, чтобы одинаковые данные в разных секторах давали разный шифротекст, а произвольный доступ к любому сектору не требовал расшифровки всего, что было до него.

Это принципиально отличается от шифрования потока: dm-crypt не нужно «прогнать» весь диск последовательно, чтобы прочитать один блок в середине. Ядро просто перехватывает запрос ввода-вывода на уровне блочного устройства, шифрует или расшифровывает конкретный блок и передаёт его дальше — драйверу диска или файловой системе. Накладные расходы — это работа над теми же данными, которые и так читались бы и записывались, без дополнительных копий, без промежуточных файлов, без отдельного процесса в userspace.

Почему у полнодискового шифрования почти нет накладных расходов

Первая причина — работа целиком в ядре, на пути, по которому и так идёт каждый блок ввода-вывода. Нет переключений контекста между ядром и пользовательским процессом ради шифрования отдельно от чтения/записи: шифрование — часть того же пути данных, что и обычная работа с диском.

Вторая причина — аппаратное ускорение. На современных серверных процессорах (Intel Xeon, AMD EPYC, серверные ARM-чипы) шифр AES выполняется не программным циклом, а выделенными инструкциями процессора — AES-NI на x86 и аналогичные Cryptography Extensions на ARM. Один раунд шифрования, который раньше занимал десяток обычных инструкций с обращениями к таблицам подстановок в памяти, теперь выполняется одной инструкцией процессора за предсказуемое число тактов. Подробнее о том, как это работает и почему изменило представление о «дороговизне» шифрования, — в статье про AES-NI.

dm-crypt использует API ядра Linux crypto, которое автоматически выбирает аппаратно ускоренную реализацию AES, если процессор её поддерживает — проверить это можно так:

cryptsetup benchmark

Команда покажет пропускную способность шифрования для разных алгоритмов на конкретном процессоре. Если AES-NI доступен, цифры для AES обычно на порядок выше, чем для шифров без аппаратной поддержки — конкретные значения зависят от процессора и не стоит ориентироваться на цифры из чужих статей как на гарантию для своего железа.

Третья причина — узкое место в реальности почти всегда не CPU, а сам диск. Современный SSD или NVMe ограничивает скорость операций гораздо раньше, чем процессор успевает исчерпать свою пропускную способность на шифрование при аппаратном ускорении. Иначе говоря, шифрование добавляет работу, но эта работа не становится новым узким местом — диск и так был бы ограничивающим фактором. Подробнее о том, что именно защищает и не защищает шифрование диска, — в статье «Шифрование дисков: что защищает».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Как устроено шифрование бэкапа

Здесь принципиально другая архитектура. Инструменты вроде restic, borg или duplicati (а также классическая связка tar + gpg) — это не часть ядра и не прозрачный слой между файловой системой и диском. Это отдельная утилита в пользовательском пространстве (userspace), которая запускается как обычный процесс, читает файлы через стандартные системные вызовы, обрабатывает их в своей логике и только потом шифрует результат перед отправкой в хранилище.

Разница на уровне архитектуры такая:

Шифрование диска (LUKS/dm-crypt)Шифрование бэкапа (restic/borg/gpg)
УровеньЯдро, блочное устройствоПользовательский процесс
Единица обработкиФиксированный блок (сектор)Файл или чанк переменного размера
Что шифруетсяВсё, что пишется на дискТолько то, что попало в снапшот
Дополнительные слоиПрактически нетДедупликация, сжатие, метаданные
Аппаратное ускорениеВсегда через API ядраЗависит от реализации утилиты

Утилита бэкапа не обязана и часто не может использовать то же самое ядерное crypto API, к которому обращается dm-crypt. Многие инструменты реализуют шифрование через собственную криптографическую библиотеку (например, реализацию AES-GCM на Go в случае restic) — она вполне может использовать аппаратные инструкции процессора, но путь до них другой, и на практике эффективность такой реализации зависит от версии инструмента, используемой библиотеки и платформы. Это не значит, что шифрование бэкапа реализовано «плохо» — просто оно устроено иначе, и накладные расходы на него складываются из нескольких источников, а не только из самого AES.

Сжатие перед шифрованием — отдельная статья расходов

Практически все современные инструменты бэкапа сжимают данные перед тем, как их зашифровать. Порядок операций здесь важен и не случаен: сжимать нужно данные *до* шифрования, потому что после шифрования данные становятся статистически неотличимы от случайного шума — а алгоритмы сжатия ищут именно повторяющиеся паттерны и избыточность. Зашифрованные данные сжать эффективно уже не получится: попытка сжать шифротекст даёт нулевой или почти нулевой выигрыш, но тратит процессорное время впустую.

Значит, перед тем как зашифровать блок данных, инструмент бэкапа должен его сначала прочитать, затем прогнать через компрессор (restic и borg по умолчанию используют zstd, более старые схемы — zlib/gzip), и только сжатый результат передать на шифрование. Это два полноценных прохода по данным вместо одного, и оба требуют CPU: один — на поиск избыточности и упаковку, второй — на собственно AES. У LUKS никакого сжатия нет и быть не должно — блочное устройство хранит ровно то, что ему передала файловая система, побайтово, без попытки сделать данные компактнее.

Сжатие само по себе не всегда бесплатная операция и с точки зрения эффективности: для уже сжатых данных (архивы, видео, изображения) компрессор тратит время, но почти ничего не выгадывает в объёме — время на CPU уходит, а результат не меняется. Похожий эффект разобран в статье про сжатие на лету, которое иногда дороже трафика — там речь о другом контексте (передача по сети), но принцип тот же: сжатие — это всегда компромисс CPU против объёма, и он не всегда в вашу пользу.

Последовательное чтение множества файлов вместо потока блоков

Второй источник дополнительной нагрузки — сам процесс подготовки бэкапа устроен как обход файловой системы, а не как работа с непрерывным блочным устройством. Инструмент бэкапа должен:

  • обойти дерево каталогов и получить список файлов (stat на каждый);
  • открыть каждый файл отдельным системным вызовом;
  • прочитать содержимое, возможно разбивая крупные файлы на чанки для дедупликации;
  • для каждого чанка посчитать хеш (чтобы определить, менялись ли данные с прошлого бэкапа);
  • сжать новые или изменившиеся чанки;
  • зашифровать результат;
  • записать в хранилище бэкапов, часто по сети.

Каждый из этих шагов — отдельная операция с собственными накладными расходами, и они выполняются последовательно (или с ограниченной параллельностью) для каждого файла. На сервере с миллионами мелких файлов (типичный случай — веб-приложения с кэшами, node_modules, почтовые ящики в формате Maildir) сама операция обхода дерева и открытия файлов по отдельности может занимать сопоставимое или большее время, чем собственно шифрование данных. Это отдельная от криптографии проблема — обработка большого количества мелких файлов сама по себе дорога, что подробно разобрано в статье «Миллион мелких файлов убивает диск».

dm-crypt же не знает о существовании файлов вообще — для него есть только последовательность блоков фиксированного размера, которые нужно прошифровать по требованию файловой системы сверху. Никакого обхода дерева, никакого stat на миллион файлов, никакой дедупликации — просто перехват операций чтения/записи блочного устройства.

Где на практике теряется время при шифрованном бэкапе

Если собрать три источника вместе — юзерспейс-реализация шифрования, сжатие как отдельный проход и обход множества файлов с хешированием, — становится понятно, почему шифрованный бэкап ощущается как заметно более тяжёлая операция, чем просто «включить AES». Причём в большинстве реальных случаев именно шифрование как таковое — не главный виновник: аппаратное ускорение AES на современном сервере достаточно быстрое, и криптография редко становится узким местом сама по себе. Гораздо чаще ограничивающий фактор — это связка «однопоточное сжатие + большое число мелких файлов + сеть до хранилища бэкапов».

Практические способы снизить эту нагрузку, не трогая саму криптографию:

  • Проверить, используется ли параллелизм. Некоторые инструменты бэкапа по умолчанию ограничены одним потоком на сжатие/хеширование — стоит свериться с документацией конкретной версии на предмет флагов параллельной обработки, если они есть.
  • Снизить уровень сжатия там, где выигрыш небольшой. Для уже сжатых данных (медиа, архивы) можно исключить их из сжатия или снизить его уровень — компрессор потратит меньше CPU без ощутимой потери в объёме.
  • Ограничить окно бэкапа приоритетом ввода-вывода, чтобы процесс не конкурировал с продакшн-нагрузкой за диск — через ionice и nice, если бэкап и рабочая нагрузка делят один сервер.
  • Разделить полное и инкрементальное копирование. После первого полного снапшота дедупликация резко сокращает объём новых данных для обработки — именно первый прогон обычно самый тяжёлый.
  • Считать реальное узкое место, а не гадать. Профиль CPU во время бэкапа (top, htop, загрузка по потокам) быстро покажет, упирается ли процесс в один поток компрессора, а мониторинг диска — не упирается ли он в I/O хранилища назначения.

Если ваш сервер размещён у нас, начальная настройка и шифрования диска, и шифрованного бэкапа — обычная часть работы с VPS, а достаточный запас CPU и дискового ввода-вывода снимает часть этих накладных расходов ещё до оптимизации самого процесса бэкапа. Пошаговую настройку шифрованного бэкапа мы разбирали отдельно — в статье «Как установить и настроить бэкап с шифрованием на VPS», а частые ошибки такой настройки — в статье «Бэкап с шифрованием на сервере: частые ошибки и решения».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли отключить шифрование бэкапа и оставить только шифрование диска — не будет ли этого достаточно?

Нет, это разные угрозы. Шифрование диска защищает данные, пока диск физически находится в вашем сервере (например, от кражи оборудования из дата-центра). Бэкап, который вы выгружаете на другой сервер или в отдельное хранилище, физически покидает защищённый диском периметр — если он не зашифрован сам по себе, любой, кто получит доступ к хранилищу бэкапов, получит и данные в открытом виде.

Если аппаратное ускорение AES такое быстрое, почему вообще шифрование бэкапа заметно нагружает CPU?

Потому что в профиле нагрузки шифрование — не единственная и часто не главная статья расходов. Сжатие, хеширование для дедупликации и обработка множества отдельных файлов обычно занимают сопоставимое или большее время CPU, чем сам AES.

Стоит ли отключать сжатие в бэкапе, чтобы ускорить процесс?

Это компромисс: без сжатия бэкап займёт больше места в хранилище и больше трафика на передачу, но пройдёт быстрее по CPU. Разумный средний путь — снизить уровень сжатия или выборочно исключить из него уже сжатые типы файлов, а не отключать целиком.

Использует ли LUKS то же самое, что и restic/borg, только «под капотом ядра»?

Алгоритм один и тот же — AES, обычно 256 бит. Но режим работы и путь к аппаратному ускорению разные: LUKS работает в режиме XTS через ядерное crypto API, инструменты бэкапа чаще используют режим GCM через собственную криптографическую библиотеку в userspace. Оба могут использовать аппаратные инструкции процессора, но не через один и тот же программный путь.

Есть ли смысл шифровать бэкап, если диск сервера и так зашифрован?

Да, обязательно. Шифрование диска и шифрование бэкапа защищают от разных сценариев и не заменяют друг друга: диск — от кражи носителя на текущем сервере, бэкап — от компрометации хранилища, куда копия физически передаётся и где хранится отдельно от исходных данных.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →