Optimization guide · uploads

Как оптимизировать большие upload в Node.js?

Короткий ответ

Не лечите большой upload увеличением max body size. Оставьте prefetch выключенным, создайте ctx.bodyStream() до первого await и передайте его в downstream pipeline. Ограничьте размер одного потока через maxStreamBodySize, число одновременных upload и бюджет хранилища. swm-uws 0.7.3 останавливает socket reads при pause(), поэтому медленный consumer создаёт backpressure вместо накопления всего тела в памяти.

Readable
поток body
413
превышение размера
pause/resume
flow control

Границы ответа

Страница фиксирует контракт @swarmmachina/swm-core 5.1.2 и @swarmmachina/swm-uws 0.7.3 для Node.js 22/24. Она не измеряет throughput конкретного диска, object storage или сети и не обещает общий лимит памяти процесса.

Контракт потокового upload

УровеньЯвная границаПроверка перед запуском
ReaderСоздайте ctx.bodyStream() синхронно до первого await и не используйте другой body reader или prefetch для того же запроса.Тестируйте async before hook, reader conflict и ранний отказ авторизации.
Размерhttp.maxStreamBodySize задаёт server ceiling; route и per-call maxSize могут только сузить его.Проверьте Content-Length выше лимита и chunked upload, который пересекает лимит во время чтения.
ПамятьStreaming не списывается из maxBodyBudget, но queue downstream, удержанные chunks и параллельные upload всё равно потребляют память.Запишите RSS, длину очереди и число active upload в отдельном нагрузочном прогоне.
BackpressureКогда consumer не готов, native pause останавливает дальнейшие socket reads; уже принятые chunks из parser buffer всё ещё могут дойти до callback.Замедлите запись, убедитесь в pause/resume и проверьте, что процесс не буферизует весь файл.
ОтменаЕсли handler перестаёт читать body, вызовите stream.destroy() и завершите ответ по своей policy.Проверьте отказ авторизации, client FIN и повторное использование соединения после drain.
AdmissionЛимит одного файла не ограничивает сумму одновременно принимаемых файлов: нужен отдельный concurrency limit и бюджет хранилища.Запустите больше concurrent upload, чем разрешает policy, и подтвердите контролируемый отказ.

Выбор по профилю upload

  1. 01

    Небольшой JSON или form payload

    Оставьте bounded body reader

    body(), json() или prefetch проще, если материализация уже входит в известный лимит и нужна приложению целиком.

  2. 02

    Файл передаётся в disk или object storage

    Используйте ctx.bodyStream()

    Pipeline получает chunks по мере приёма и не требует удерживать полный файл в JS memory.

  3. 03

    Downstream временно медленнее сети

    Полагайтесь на pause/resume, но измеряйте

    Backpressure сдерживает socket reads, но не задаёт admission control и не ограничивает память всех остальных частей процесса.

Что не следует обещать

  • Поток не даёт бесконечно малое потребление памяти: parser buffer, chunks у consumer и очереди downstream остаются частью бюджета.
  • maxStreamBodySize ограничивает один request, а не сумму одновременных upload и не лимит object storage.
  • Нельзя смешивать streaming reader с body(), buffer(), text(), json() или prefetch в одном запросе.
  • Новая страница описывает контракт, а не универсальный benchmark. Производительность проверяйте на своём размере файлов, диске, сети и concurrency.

Первичные источники

Утверждения о reader, лимитах и pause/resume привязаны к опубликованным версиям пакетов.