1. 1
  2. 2
  3. 3
  4. 4

# теория · шаг 1 из 4

Как файл уезжает клиенту

Коротко

Для больших файлов настройка передачи зависит от диска, памяти и скорости клиента.

  • sendfile позволяет передавать файл без копирования через буфер пользовательского процесса; проверь, включён ли он в твоей сборке и конфиге.
  • aio threads помогает вынести блокирующее чтение, а directio меняет работу с файловым кешем. Их эффект нужно измерять.
  • limit_rate_after позволяет начать ограничение скорости после заданного объёма.
  • slice делит ответ на части, которые можно кешировать отдельно для повторных обращений и перемотки.

Если знаешь, что делает sendfile, и не путаешь limit_rate с limit_req - листай до «Теперь сам».

Сначала ответь сам

В чужом конфиге первой строкой стоит sendfile on;, и автор гордо называет это оптимизацией. Что она даёт на самом деле?

Ничего нового - она уже стоит. Официальный образ nginx:

↳  выводnginx -T | grep sendfile
    sendfile        on;

Строка живёт в nginx.conf из коробки много лет. Полезной она становится только там, где кто-то её выключил, - а такое бывает: sendfile off иногда ставят в контейнерах поверх сетевых файловых систем, где механизм работает неверно.

На что это похоже

Курьер, который забирает коробку со склада, привозит её в офис, ставит на стол, берёт со стола и несёт в машину. Коробку никто не открывал и ничего в ней не менял - но она дважды прошла через руки.

sendfile - это просьба к складу отгрузить прямо в машину. Данные из файла уходят в сокет внутри ядра, не проходя через память процесса.

Механизм: где живут данные при отдаче

без sendfile файл буфер процесса сокет две копии с sendfile файл сокет ядро перекладывает само ни одной
На раздаче статики это самая дешёвая оптимизация - и потому она включена по умолчанию.

Правило

/etc/nginx/nginx.confhttp
sendfile   on;
tcp_nopush on;

tcp_nopush работает только вместе с sendfile и просит систему подождать, пока наберётся полный пакет: заголовки ответа и начало файла уезжают одним пакетом вместо двух. Мелочь - но на раздаче тысяч файлов это тысячи лишних пакетов.

Рядом стоит tcp_nodelay on (включён по умолчанию), и они не конфликтуют: nopush действует, пока идёт тело через sendfile, nodelay - на остальном.

Разбор: когда sendfile мешает

У sendfile есть слабое место - он блокирующий. Пока ядро тянет с диска холодный блок, рабочий процесс стоит. На SSD и горячем кеше это незаметно, на раздаче медиатеки с обычных дисков - очень даже.

/etc/nginx/conf.d/media.confhttp › server › location /video/
aio       threads;
directio  16m;
output_buffers 2 1m;

aio threads уводит чтение в пул потоков: воркер отдаёт задачу и продолжает обслуживать других клиентов. directio 16m велит читать файлы крупнее 16 мегабайт мимо кеша страниц - большие файлы всё равно вытеснят из кеша всё полезное, а читаются один раз.

Обе возможности требуют флагов сборки, и в официальном образе они есть:

$  команда
nginx -V 2>&1 | tr ' ' '\n' | grep -E 'file-aio|threads'
↳  выводnginx -V 2>&1 | tr ' ' '\n' | grep -E 'file-aio|threads'
--with-file-aio
--with-threads

Это настройки под конкретную нагрузку, а не «сделать быстрее»

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

Разбор: сколько именно режет limit_rate

Замер на файле в 2 МБ, полное время скачивания:

настройка время
без ограничения 0,003 с
limit_rate 512k 3,01 с
limit_rate 512k плюс limit_rate_after 1m 1,00 с

Третья строка и есть рабочий рецепт: первый мегабайт уезжает на полной скорости - страница и превью не пострадают, - а дальше скорость режется.

/etc/nginx/conf.d/media.confhttp › server › location /downloads/
limit_rate_after 10m;
limit_rate       2m;
limit_conn       perip 2;

limit_rate ограничивает один запрос, а не соединение и не клиента: по одному соединению HTTP/2 идут параллельные запросы, и полоса у каждого своя. Суммарную скорость клиента держит связка с limit_conn из двенадцатого раздела: в HTTP/2 она считает соединением каждый одновременный запрос, и perip 2 даёт не больше двух полос по 2m. Это честная защита канала: скачивание идёт, но один клиент не съедает всю полосу. Значение можно взять из переменной - например, отдавать быстрее авторизованным:

/etc/nginx/nginx.confhttp
map $http_authorization $rate {
    default  1m;
    ~.       5m;
}

Что ломается без этого

Отдельная история - когда большой файл ещё и кешируется с бэкенда. Целиком он занимает зону и тянется одним куском; если клиент попросил середину файла, кеш от этого не помогает вовсе.

/etc/nginx/conf.d/media.confhttp › server › location /video/
slice             1m;
proxy_cache       media;
proxy_cache_key   $uri$slice_range;
proxy_set_header  Range $slice_range;
proxy_cache_valid 200 206 1h;

Модуль slice режет запрос на куски по мегабайту, и каждый кусок кешируется отдельной записью. Перемотка видео на середину тянет два-три куска вместо гигабайта, а параллельные зрители одного фильма греют один и тот же кеш. Обрати внимание на 206 в proxy_cache_valid: куски приезжают именно частичными ответами.

Зачем это в работе

Практическое правило простое: из всего перечисленного по умолчанию нужно ровно ничего. sendfile уже включён, tcp_nopush даёт мелочь, а aio, directio, limit_rate и slice включают под конкретную задачу, которую сначала видно в метриках.

Признак, что задача есть: $request_time большой при маленьком $upstream_response_time - то есть время уходит на отдачу, а не на приложение. Как это померить, разбирает следующий урок.

Теперь сам

На сервере раздачи дистрибутивов включили limit_rate 1m на весь server. Через день жалуются, что сайт стал медленным - не скачивание, а обычные страницы. Что произошло?

limit_rate без limit_rate_after режет ответ с первого байта, включая HTML, css и картинки: страница на 300 КБ теперь едет треть секунды вместо мгновения. Правильно - вешать ограничение на location с файлами и добавлять limit_rate_after, чтобы мелочь проскакивала на полной скорости.

Главное

Настраивай передачу больших файлов по измеренному ограничению. sendfile, временные файлы, предел скорости и кеширование частей решают разные задачи. Сначала проверь действующий конфиг и путь данных, затем измерь эффект одной настройки на характерном размере файла и скорости клиента.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.