...

Правильное использование функций `sendfile` и `tcp_nopush` в NGINX для обеспечения максимальной производительности

С nginx sendfile и tcp_nopush Я передаю статические файлы из файловой системы в сокет с использованием алгоритма «zero-copy», что позволяет заметно снизить как нагрузку на процессор, так и количество пакетов. При правильной настройке обе директивы повышают эффективность передачи, снижают накладные расходы и создают основу для качественной оптимизации nginx при работе с ресурсами и загрузками.

Центральные пункты

  • Нулевая копия с помощью sendfile: меньше копий, большая пропускная способность
  • tcp_nopush буферизует пакеты: более крупные фреймы, меньшие накладные расходы
  • Комбинация включает: sendfile + tcp_nopush + tcp_nodelay
  • Примеры использования определить приоритеты: статические ресурсы, файлы большого размера
  • Тесты для NFS/SMB: оценить эффективность, при необходимости отключить sendfile

Почему функция sendfile значительно повышает производительность NGINX

Я активирую sendfile, поскольку ядро может отправлять файлы напрямую через сетевой стек, минуя дополнительные операции копирования в пользовательском пространстве. Этот путь с нулевым копированием сокращает количество смен контекста и экономит циклы ЦП, особенно когда множество одновременных клиентов запрашивает статический контент. Это выгодно для больших файлов, таких как изображения, CSS, JavaScript или архивы, поскольку передача данных происходит более плавно и с меньшими накладными расходами. Системные кэши также работают эффективнее, так как происходит меньше перемещений памяти, а ядро контролирует путь данных. Наиболее заметный прирост производительности наблюдается в локальных файловых системах, поэтому я сначала провожу измерения именно там, прежде чем переходить к экзотическим конфигурациям.

Что именно делает tcp_nopush и в каких случаях он показывает себя с лучшей стороны

С tcp_nopush Я прошу систему отправлять TCP-пакеты только тогда, когда они заполнены должным образом, а не отправлять небольшие сегменты преждевременно. В Linux это соответствует параметру TCP_CORK, в FreeBSD — TCP_NOPUSH, и в обоих случаях количество пакетов заметно уменьшается. Эта директива не сводит задержку к минимуму, она направлена на улучшение соотношения между полезными данными и накладными расходами. Я целенаправленно использую tcp_nopush для статических файлов, поскольку именно там связные потоки данных обеспечивают наибольший прирост эффективности. Без sendfile tcp_nopush не действует, поэтому я всегда включаю оба параметра вместе.

sendfile и tcp_nopush в паре: вот как я задаю основу

Сочетание sendfile а tcp_nopush сокращает количество копий и объединяет пакеты, благодаря чему один сервер на каждое ядро процессора может обрабатывать значительно больше параллельных передач. Я настраиваю оба параметра на уровне контекста http и часто добавляю tcp_nodelay, чтобы последние остатки потока прошли без задержки. Важно проводить тестирование с реальным трафиком, поскольку размеры пакетов, MTU и клиенты варьируются, и оптимальный баланс может слегка отличаться в зависимости от рабочей нагрузки. Для статических каталогов обычно достаточно глобальной активации, тогда как при динамических маршрутах ответов я обращаю внимание на последствия. Такая комбинация создаёт прочную основу для дальнейших этапов оптимизации nginx, которые будут реализованы позже.

директива Назначение Типичное действие Зависимость
sendfile включено Передача файла в сокет без копирования Меньшая нагрузка на ЦП, более высокая пропускная способность Идеальная локальная файловая система
tcp_nopush включен Заполнять посылки, сокращать накладные расходы Меньше сегментов в каждом файле Работает только с sendfile
tcp_nodelay on Отправлять последние байты без ожидания Быстрое завершение передачи Добавлено tcp_nopush

Вот как взаимодействуют параметры tcp_nodelay и tcp_nopush

Я активирую tcp_nopush, чтобы отправить начало передачи крупными пакетами, и одновременно разрешить tcp_nodelay, чтобы завершение не затягивалось. Оба параметра влияют на разные фазы потока и не мешают друг другу, когда NGINX передает файлы с помощью sendfile. Именно при работе с большим количеством небольших файлов параметр tcp_nodelay предотвращает ненужное ожидание клиента из-за небольшого остатка данных. Сначала я тестирую эту комбинацию в тестовой среде, отслеживаю RTT и размеры сегментов, а затем сверяю результаты с метриками в производственной среде. Таким образом я обеспечиваю эффективность в начале и высокую скорость в конце передачи.

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
}

Типичные сценарии применения: когда директивы оказывают сильное воздействие

Для больших Скачать таких как видео, архивы или ISO-образы, механизм «Zero-Copy» ядра значительно сокращает время обработки ЦП на каждую передачу. В конфигурациях, похожих на CDN, с большим количеством файлов CSS, JS и шрифтов, tcp_nopush сокращает количество сегментов и тем самым увеличивает полезную пропускную способность на каждый сокет. На сайтах WordPress с хорошим кэшированием большинство запросов приходится на статические ресурсы, поэтому я очень быстро замечаю эффект именно там. Также от этого выигрывают артефакты сборки, образы контейнеров или установщики, если они находятся локально, а не передаются через нестабильную сетевую файловую систему. Тем, кто ожидает пиковых нагрузок, эта комбинация позволит добиться максимальной стабильности на имеющемся оборудовании.

Практический пример: NGINX для WordPress с кэшированием и ресурсами

В настройках WordPress я устанавливаю sendfile, tcp_nopush и tcp_nodelay в глобальном контексте, напрямую выдаю статические ресурсы и строго разделяю PHP-FPM и динамические пути. Я добавляю соответствующие заголовки кэширования для изображений, CSS и JavaScript, чтобы браузеры совершали меньше обратно-прямых запросов. При предоставлении потоковых ответов я учитываю взаимодействие с буферизацией и тестирую, как размеры фрагментов влияют на задержку и пропускную способность; к этому подходит обзор по Потоковая передача ответов в виде фрагментов. Для текстового контента я использую сжатие, не сжимая при этом без необходимости двоичные файлы. Таким образом, поток запросов остается стабильным, нагрузка на процессор снижается, а время до получения первого байта сокращается.

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

 keepalive_timeout 65;
    gzip on;
    gzip_types text/css application/javascript image/svg+xml;

    server {
 listen 80;
 server_name blog.example.com;
 root /var/www/blog;

 location / {
 try_files $uri $uri/ /index.php?$args;
 }

        location ~ \.php$ {
 include fastcgi_params;
 fastcgi_pass unix:/run/php/php-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
 }

 location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg|woff2?)$ {
 expires 30d;
 add_header Cache-Control "public, max-age=2592000";
 }
    }
}

Когда я сознательно отключаю sendfile

Я включаю sendfile если файлы находятся в NFS, SMB или распределенных файловых системах, которые в моих тестах демонстрируют более низкую пропускную способность. Некоторые драйверы или задержки в пути доступа к хранилищу сводят на нет преимущества Zero Copy, поэтому решающую роль играют результаты измерений. При спорадических сетевых аномалиях я сначала отключаю tcp_nopush, чтобы сузить круг возможных причин, прежде чем начинать анализировать саму функцию sendfile. Необычные ошибки ядра или устаревшие стеки также могут стать причиной для временного перехода на классический путь чтения-записи. Важно вводить изменения постепенно и подкреплять их метриками.

Источники ошибок, на которые я обращаю внимание

Сначала я проверяю, есть ли tcp_nopush случайно включена, в то время как sendfile остается выключенным, так как в этом случае настройка не дает никакого эффекта. В случае динамических путей я слежу за тем, не приводит ли дополнительное буферирование к увеличению задержки, и сопоставляю выгоду с временем отклика. В сетях с высокой задержкой я измеряю, действительно ли более крупные пакеты помогают или же мне нужно подкорректировать размеры сегментов и параметры Keep-Alive. Настройка MTU и функции разгрузки сетевой карты также могут заметно повлиять на результат. Четкие журналы, образцы pcap и коррелированные системные метрики позволяют мне быстро определить, где необходимо внести корректировки.

Комплексный подход к производительности NGINX: дополнительные настройки

Кроме того, sendfile Правильный выбор значений параметров `worker_processes` и `worker_connections` окупается, так как позволяет избежать искусственного ограничения количества сокетов. В Linux я использую epoll и обеспечиваю достаточное количество файловых дескрипторов, чтобы пиковые нагрузки не приводили к возникновению узких мест. Для текстового контента я включаю gzip или Brotli и проверяю, не создаёт ли уровень сжатия чрезмерной нагрузки на ЦП. На транспортном уровне я дольше держу соединения открытыми и оптимизирую Keep-Alive, о чём говорится в руководстве Настройка Keep-Alive предоставляет практические рекомендации. TLS, повторное использование сеансов и HTTP/2 или HTTP/3 дополняют эту конфигурацию и обеспечивают высокую степень параллелизма при умеренной задержке.

Ограничения и особые случаи: TLS, HTTP/2/3 и проксирование

Я принимаю во внимание, что sendfile технически действует только для незашифрованных путей к файлам или специальных функций ядра. В классическом TLS NGINX шифрует байты в пользовательском пространстве, из-за чего преимущество «zero-copy» теряется; современные ядра могут частично перенести шифрование в ядро, что восстанавливает этот эффект, но такая возможность доступна не во всех конфигурациях. При HTTP/2 данные находятся в фреймах, несколько ответов используют одно TCP-соединение, а NGINX активно перепаковывает байты — в этом случае sendfile не так актуален. HTTP/3 основан на UDP/QUIC и снова подчиняется другим правилам, поэтому я добиваюсь повышения эффективности скорее за счет буферов, управления перегрузкой и правильно подобранных размеров блоков. Как Обратный прокси sendfile срабатывает только в том случае, если я действительно предоставляю файлы из локальной файловой системы; ответы из proxy_pass или fastcgi_pass в любом случае проходят через пользовательское пространство. Поэтому я строго отделяю ресурсы от динамического пути, чтобы максимально использовать преимущества метода «zero-copy».

Правильное понимание сжатия: gzip/Brotli против gzip_static

Как только NGINX начинает сжимать контент «на лету», ему приходится считывать файл, обрабатывать его и записывать результат — при этом теряется sendfile свое преимущество. Поэтому для статических ресурсов я, по возможности, использую, предварительно сжатые файлы (например, .gz или .br) и обеспечиваю их прямую доставку. Таким образом сохраняется маршрут «zero-copy», поскольку NGINX может передавать предварительно сжатый файл так же, как и любой другой ресурс. Для текстового контента, который редко изменяется, я таким образом добиваюсь снижения нагрузки на ЦП и стабильной пропускной способности без потери времени передачи. В случае с бинарными файлами и уже сжатыми форматами я избавляюсь от необходимости компрессии во время выполнения — здесь важна исключительно пропускная способность ввода-вывода, и здесь «sendfile» в сочетании с «tcp_nopush» демонстрируют свои преимущества.

AIO, directio и Page Cache: шаблоны для небольших и больших файлов

Я сочетаю sendfile с асинхронным вводом-выводом и прямым доступом к дискам, чтобы обеспечить оптимальную производительность в зависимости от размера файла. Небольшие и средние файлы используют кэш страниц ядра и остаются в траектории sendfile. Очень большие файлы, напротив, могут вытеснить кэш; в этом случае я целенаправленно считываю их с помощью directio вне кеша и использую потоки AIO. Таким образом я снижаю нагрузку на память и поддерживаю низкую задержку для других запросов. Типичный шаблон выглядит следующим образом:

http {
    # Стандартный путь: Zero-Copy из кэша страниц
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

 # Крупные файлы: обход кэша и асинхронное чтение
    aio threads;
    directio 4m; # действует только для файлов размером >= 4 MiB
    output_buffers 1 512k;    # буферы для путей directio
    sendfile_max_chunk 1m;    # справедливость при высокой нагрузке
}

Благодаря такой дифференциации небольшие объекты остаются чрезвычайно эффективными, в то время как передача очень больших файлов не перегружает оперативную память. Важно: directio отключает для соответствующих файлов маршрут sendfile — именно так я и предполагаю в случае работы с большими файлами.

Справедливость и управление потоком при высокой нагрузке

В периоды высокой нагрузки я хочу избежать ситуации, когда один-единственный поток монополизирует процессор или сокет. Я использую sendfile_max_chunk, чтобы NGINX возвращал ядро после передачи заданного количества байтов и освобождал ресурсы для других соединений. Для управления пропускной способностью помогают limit_rate и limit_rate_after, например, для ограничения скорости массовой загрузки, при этом ресурсы пользовательского интерфейса остаются быстродоступными. С помощью отложить_вывод Я настраиваю, при каком размере ответа NGINX начинает отправку — в сочетании с параметром tcp_nopush я таким образом обеспечиваю правильное разбиение пакетов. Кроме того, я обращаю внимание на lingering_close, чтобы оставшиеся пакеты были корректно переданы, а сокет не был внезапно закрыт.

Файловые системы, предварительное чтение и пути к хранилищу

Потому что sendfile При использовании кэшей страниц большую роль играет базовая файловая система. Я проверяю значения предварительного чтения (read-ahead) и настраиваю их таким образом, чтобы последовательное чтение больших файлов не затруднялось, при этом не вытесняя при этом небольшие ресурсы. На ext4 или xfs Я наблюдаю, насколько хорошо префетчинг и планировщик ввода-вывода согласуются с моей структурой пропускной способности. При работе с сетевыми файловыми системами (NFS/SMB) я тщательно тестирую rsize/wsize, кэширование и задержки, поскольку даже небольшие отклонения нейтрализуют преимущество технологии Zero-Copy. Моё правило остаётся прежним: сначала максимально использовать локальные пути, затем осторожно настраивать внешние стеки — и всегда ставить результаты измерений выше интуиции.

Прагматичная настройка сетевого стека и разгрузки сетевого адаптера

При большом количестве соединений я полагаюсь на автоматическую настройку буферов в современных стеках, но при необходимости настраиваю буферы отправки и приёма. Функции разгрузки сетевых карт, такие как TSO, GSO и GRO, заметно снижают нагрузку на ЦП; однако при проведении измерений я проявляю осторожность, поскольку перехват пакетов может искажаться в результате разгрузки (появляются, казалось бы, немногие, но очень большие сегменты). Поэтому я сопоставляю pcap‑Traces с метриками из NGINX и ядра, чтобы отделить реальные размеры пакетов от артефактов разгрузки. При пиковых значениях задержки я на короткое время прерываю тесты, отключив разгрузку, фиксирую разницу, а затем решаю, что принесет больше пользы в режиме непрерывной работы.

Шаблоны конфигурации для каждого местоположения: целевое включение и отключение

Я оставляю за собой возможность, sendfile перезаписывать в зависимости от пути или типа файла. Для статических каталогов эта функция остается включенной, а для потоковых или динамических путей я выборочно отключаю её, если приоритет имеют буферы или фильтры (например, сжатие). Краткий пример:

server {
    listen 80;
    server_name static.example.com;
    root /var/www/static;

 # Статические ресурсы: Zero-Copy
    location /assets/ {
 sendfile on;
 tcp_nopush on;
        tcp_nodelay on;
 expires 7d;
    }

 # Динамический контент или потоковая передача: гибкость превыше всего — даже перед Zero-Copy
    location /api/ {
 sendfile off;
 proxy_pass http://app_upstream;
    }
}

Такое разделение позволяет мне не терять преимущества в одной области только из-за того, что другой путь предъявляет особые требования.

Диапазон, фрагменты и большие каталоги

В случае крупных объектов играют роль диапазон-Запросы позволяют максимально использовать их преимущества: клиент загружает только необходимые части, а соединения остаются стабильными. В каталогах контента с очень большими файлами я предпочитаю логически сегментировать передачу данных — нагрузка на сервер распределяется более равномерно, а ошибки, такие как прерывания, отнимают меньше времени. В сценариях кэширования я предотвращаю „Thundering Herds“, разумно буферизуя ответы, но не удерживая искусственно небольшие фрагменты и остаточные данные. При этом ключевую роль играет взаимодействие с tcp_nopush: я делаю начальные сегменты большими, но не заставляю конец ждать.

Стратегия измерений и испытаний: достоверное подтверждение эффектов

Я подтверждаю результаты оптимизации с помощью воспроизводимых тестов. На стороне сервера я отслеживаю профили использования ЦП, $request_time, 1 ТП4 Тбайт_отправлено, активные соединения и смену контекста. В сети я измеряю размеры сегментов, количество повторных передач и распределение RTT; результаты перехвата пакетов я сопоставляю со статистикой сокетов, чтобы учесть эффекты разгрузки. На стороне клиента я сравниваю TTFB, First Contentful Paint и время загрузки при реалистичных значениях RTT и пропускной способности. Я варьирую MTU, настройки Keep-Alive и размеры файлов, чтобы видеть не только кривые в идеальных условиях. В итоге я на основе конкретных цифр решаю, обеспечивают ли sendfile/tcp_nopush в данной рабочей нагрузке требуемую стабильность и эффективность — и провожу точную настройку, пока это не будет достигнуто.

Детали HTTP, которые имеют решающее значение: Range и потоковая передача

Я использую диапазон-Запросы при работе с большими файлами, чтобы клиенты загружали только необходимые части, а соединения оставались стабильными. Особенно при прокрутке видео и возобновлении загрузки правильная поддержка диапазонов байтов помогает рационально распределять пропускную способность; дополнительную информацию можно найти на странице, посвящённой Запросы HTTP-Range. Для последовательных ответов с растущим телом сообщения я тестирую стратегии потоковой передачи и слежу за тем, чтобы буферы не удерживали данные слишком долго по неосторожности. При этом я учитываю наличие кэшей и устанавливаю соответствующие заголовки, чтобы прокси-серверы и браузеры работали корректно. Я учитываю взаимодействие с tcp_nopush, поскольку размер пакетов и синхронизация сброса напрямую влияют на воспринимаемую скорость.

Краткое резюме

С sendfile Я эффективно передаю файлы напрямую в ядро, а с помощью tcp_nopush обеспечиваю рациональное заполнение пакетов, прежде чем они начнут нагружать канал. Обе директивы дополняют друг друга, в то время как tcp_nodelay передает оставшийся последний байт без задержки. Я проверяю эффект в условиях реального трафика, обращаю внимание на путь к хранилищу, MTU, Keep-Alive и сжатие, а также последовательно провожу измерения. Для нагрузок типа WordPress и CDN преимущества проявляются особенно быстро, поскольку многие запросы касаются статических ресурсов. Тот, кто целенаправленно использует эти настройки, получает большую пропускную способность на каждое ядро, снижает накладные расходы и создаёт резервы для реальных пиков нагрузки.

Текущие статьи

Современный веб-сервер NGINX с оптимизированной сетевой передачей данных благодаря sendfile и tcp_nopush
Веб-сервер Plesk

Правильное использование функций `sendfile` и `tcp_nopush` в NGINX для обеспечения максимальной производительности

Практическое руководство по настройке NGINX с использованием параметров `sendfile` и `tcp_nopush` для обеспечения максимальной производительности при доставке статических файлов и загрузке больших файлов.