С 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 преимущества проявляются особенно быстро, поскольку многие запросы касаются статических ресурсов. Тот, кто целенаправленно использует эти настройки, получает большую пропускную способность на каждое ядро, снижает накладные расходы и создаёт резервы для реальных пиков нагрузки.


