Архитектура чанковой загрузки: руководство по проектированию
Спроектируйте надежную систему чанковой загрузки. Стратегии разбиения, возобновляемые загрузки и оптимизация параллельной передачи.
Архитектура чанковой загрузки разбивает файл на части фиксированного или переменного размера и отправляет их независимо друг от друга — это значит, что кратковременный сбой сети не заставит начинать передачу 10 ГБ с нуля. Два доминирующих открытых стандарта — AWS S3 Multipart Upload (минимальный размер части 5 МБ, максимум 10 000 частей) и возобновляемый протокол tus.io (черновик RFC, широко реализованный). При правильной реализации чанковая загрузка даёт в 5–10 раз более высокую пропускную способность на высоколатентных каналах, переносит кратковременные разрывы соединения и позволяет выполнять параллельную расшифровку на стороне получателя. Ниже — как спроектировать систему, которая реально выдержит нагрузку в продакшене.
Почему монолитные загрузки не работают при масштабировании
Одиночный HTTP PUT файла размером 5 ГБ может сорваться полдюжиной способов. Окно перегрузки TCP долго раскачивается, ограничивая пропускную способность на высоколатентных путях. Браузеры допускают не более 6 одновременных соединений на источник, оставляя большую часть пропускной способности незадействованной. Серверные таймауты запросов (nginx по умолчанию — 60 секунд, CloudFront — 30 секунд для нестримингового контента) прерывают долгие загрузки. Мобильные сети при переключении между вышками разрывают соединение каждые несколько минут. А один перевёрнутый бит вынуждает повторить всю передачу с начала. Чанковая загрузка решает все эти проблемы, делая единицу работы небольшой, самостоятельно повторяемой и удобной для параллелизации.
Выбор размера чанка
Размер чанка — это компромисс. Мелкие чанки быстрее восстанавливаются после сбоев и дают более точную гранулярность прогресса, но создают больше HTTP-накладных расходов. Крупные чанки амортизируют затраты на рукопожатие и TLS, но тратят впустую пропускную способность при сбое чанка и необходимости его повторной передачи. Типичные диапазоны: от 1 до 5 МБ для мобильных загрузок с нестабильными сетями, от 5 до 16 МБ для загрузок в браузере с десктопа, от 16 до 64 МБ для серверных передач по надёжным каналам и 100 МБ и более для S3 Multipart, где потолок в 10 000 частей вынуждает использовать крупные чанки для файлов объёмом 1 ТБ. Некоторые системы адаптируются динамически — начинают с небольших чанков и увеличивают их по мере того, как соединение доказывает свою надёжность.
Чанкование фиксированного размера против контентно-определённого
Чанкование фиксированного размера (например, по 8 МБ) тривиально реализовать, удобно для параллелизации и поддерживает точные смещения для возобновления. Контентно-определённое чанкование, применяемое в rsync и restic, выбирает границы на основе скользящего хеша (как отпечаток Рабина), чтобы вставки в середину файла не сдвигали все последующие границы чанков. CDC отлично подходит для дедупликации в инструментах резервного копирования, но добавляет сложность и затраты CPU, не вознаграждаемые при чистой передаче файлов. Для архитектур загрузки фиксированный размер выигрывает по простоте и чисто отображается на части S3 Multipart или смещения tus.io.
Протоколы возобновляемой загрузки
Протокол tus.io, реализованный в tusd (Go), tus-js-client, Uppy и многих серверных фреймворках, использует HTTP PATCH с заголовком Upload-Offset для добавления чанков. Запрос HEAD возвращает текущее смещение на сервере, поэтому клиент знает, откуда возобновить передачу после сетевого сбоя. S3 Multipart Upload использует иную модель: инициируйте загрузку, чтобы получить UploadId, загрузите каждую часть (индексация с 1), затем отправьте запрос CompleteMultipartUpload со списком ETags. Клиенты могут запросить ListParts, чтобы увидеть, что уже загружено. Оба протокола сохраняют состояние между перезапусками клиента и корректно переживают разрывы соединения.
Параллелизм при загрузке чанков
Параллельная загрузка чанков резко увеличивает пропускную способность на высоколатентных каналах. HTTP/1.1 ограничивает браузеры до 6 одновременных соединений на источник; HTTP/2 мультиплексирует множество потоков по одному соединению, но всё равно ограничен окнами управления потоком. Типичный планировщик загрузки ставит чанки в очередь и отправляет 4–8 параллельно, с противодавлением при ответах сервера 429 или 503. Слишком большой параллелизм провоцирует шейпинг ISP и ограничения промежуточных устройств; слишком малый оставляет пропускную способность незадействованной. На практике 4 параллельных потока на домашнем интернете и 8–16 на гигабитной оптике — оптимальный вариант для большинства задач.
Клиентское состояние и метаданные для возобновления
Возобновляемые загрузки требуют, чтобы клиент сохранял достаточно состояния для возобновления после краша браузера или выключения ноутбука. IndexedDB, часть стандарта Web Storage, хранит манифесты загрузок с хешем файла, количеством чанков и информацией об успешных чанках. Индексируйте манифест по SHA-256-хешу файла, чтобы повторное добавление того же файла продолжалось с того места, где остановилось. Удаляйте устаревшие манифесты старше 7 дней во избежание разрастания. На мобильных устройствах WKWebView (iOS) и Chrome Custom Tabs (Android) могут вытеснить IndexedDB при нехватке памяти, поэтому при возможности сохраняйте критическое состояние в нативное хранилище.
Обработка чанков на сервере
Серверу нужно собрать чанки в готовый файл или, при использовании S3 Multipart, делегировать сборку S3. Минимальная архитектура: принять каждый PATCH чанка, записать во временный блоб с ключом по идентификатору загрузки и индексу чанка, зафиксировать смещение в хранилище метаданных (Redis или PostgreSQL) и при вызове CompletePart собрать или пометить завершённым. Используйте объектное хранилище (S3, Cloudflare R2, Backblaze B2) для блобов чанков, а не локальный диск — балансировщики нагрузки не могут легко делить локальное состояние. Удаляйте брошенные загрузки через 24–72 часа для освобождения места.
Проверка целостности — каждого чанка и сквозная
Проверяйте каждый чанк хешем при загрузке. ETag в S3 Multipart — это хеш MD5 для каждой части (или составной хеш для всего объекта). Для более строгой проверки вычислите SHA-256 каждого чанка на стороне клиента и отправьте его в заголовке — сервер хранит его вместе с чанком и может проверить при повторном чтении. После загрузки всех чанков вычислите корень дерева Меркла или потоковый хеш собранного файла и верните его клиенту. Клиент сравнивает с собственным хешем исходного файла. Любое несовпадение инициирует повторную загрузку проблемных чанков.
Шифрование и его взаимодействие с чанкованием
Сквозное шифрование немного усложняет чанкование. Каждый чанк нуждается в собственном nonce во избежание повторного использования IV в AES-GCM, а границы чанков должны быть частью схемы аутентификации. Типичный подход: получить ключ для каждого чанка через HKDF-SHA256 из корневого ключа шифрования файла, используя индекс чанка в качестве контекстной информации, затем зашифровать каждый чанк с помощью AES-256-GCM и нулевым или инкрементным nonce. Включите индекс чанка и общее количество чанков в AAD, чтобы атакующие не могли склеить или переставить чанки. При расшифровке убедитесь, что все чанки присутствуют и расположены в правильном порядке, прежде чем выдавать открытый текст.
Наблюдаемость для чанковых систем
Инструментируйте каждый чанк. Метрики для отслеживания: загруженных чанков в секунду, латентность загрузки чанка p50/p95/p99, частота повторных попыток для чанка и частота брошенных загрузок. Дашборды в Grafana или Datadog быстро выявляют регрессии. Распределённые трейсы через OpenTelemetry связывают клиентскую сессию с обработкой чанков на сервере. Логируйте структурированные события в JSON — тогда их можно искать в Loki, Elasticsearch или Splunk. Когда клиент сообщает о медленной загрузке, трейс покажет, какие именно чанки зависли и почему.
Всё вместе
Готовая к продакшену чанковая система загрузки сочетает чанки по 5–16 МБ, протокол tus.io или S3 Multipart, 4–8 параллельных потоков, состояние возобновления на IndexedDB, проверку целостности SHA-256 для каждого чанка и опциональное E2EE для каждого чанка с производным ключом. HexaTransfer использует чанковое шифрование на стороне клиента с AES-256-GCM и возобновляемые загрузки для надёжной обработки файлов до 10 ГБ при нестабильных соединениях.
Попробуйте на hexatransfer.com — бесплатно, без аккаунта, до 10 ГБ.
Безопасная отправка больших файлов со сквозным шифрованием
Передавайте файлы до 10 ГБ бесплатно со сквозным шифрованием. Регистрация не требуется. Ваши файлы шифруются в браузере перед загрузкой — никто другой не может их прочитать.
Отправить файл