# теория · шаг 3 из 5
nginx, Apache, IIS: чем они разные
Коротко
Apache и nginx по-разному отвечают на два вопроса. Соединение: у Apache его
обслуживает процесс или поток, и их конечное число - восемь медленных клиентов
кладут сайт с восемью воркерами; у nginx тысячи соединений живут в одном цикле
событий, и семьсот медленных ничего не меняют. Конфиг: Apache складывает
пересекающиеся секции и читает .htaccess на каждом запросе, nginx выбирает
один блок и заменяет им унаследованное. IIS - отдельный мир Windows и .NET.
Если с Apache дела не имел - тебе хватит «Правило» и последнего блока про выбор.
Восемь клиентов с плохим интернетом. Не атака, не нагрузка - просто восемь человек, у которых запрос идёт по сети медленно. Что станет с сайтом?
Apache prefork (8 воркеров): не ответил, таймаут 5 с
Apache event (8 потоков): не ответил, таймаут 5 с
nginx (1 воркер): ответ за 0,001 с
У nginx тот же замер повторён на семистах медленных соединениях - ответ всё те же 0,001 секунды, и в системе по-прежнему два процесса.
На что это похоже
Apache в классическом виде - это касса на посетителя: пришёл человек - открыли кассу, ушёл - закрыли. Пока он ищет кошелёк, касса занята и никого больше не обслуживает. Касс столько, сколько разрешил владелец; кончились - очередь стоит на улице.
nginx - один кассир, который никогда никого не ждёт. Пока посетитель ищет кошелёк, кассир пробивает следующего, а к первому вернётся, когда тот будет готов. Отсюда и разница: у Apache потолок - число касс, у nginx - объём работы, а не число людей в зале.
Вторая разница - в конфиге, и она устроена так же зеркально: Apache читает правила по дороге и складывает их, nginx выбирает одно и работает по нему.
Механизм: две модели обслуживания
Правило
| Apache | nginx | IIS | |
|---|---|---|---|
| соединение стоит | процесса (prefork) или потока (worker, event) |
записи в списке одного воркера | потока из пула, очередь держит HTTP.sys |
| конфиг | секции по каталогам, правила складываются | блоки по адресу, побеждает один | графический интерфейс и web.config |
| правила рядом с сайтом | .htaccess, читается на каждый запрос |
нет ничего подобного | web.config в каталоге |
| модули | грузятся из конфига (LoadModule) |
вкомпилированы или динамические .so |
ставятся в систему |
| где живёт | везде | везде | только Windows |
Замер на стенде: у Apache из конфига загружено 10 модулей, у nginx 30 флагов сборки плюс 14 динамических файлов в образе. Отсюда практическое следствие из третьего раздела курса: у Apache «модуля нет» лечится строкой в конфиге, у nginx - установкой пакета или пересборкой.
Разбор: восемь медленных клиентов
Стенд: Apache 2.4.68 с MaxRequestWorkers 8 (в варианте event - восемь
потоков) и nginx с одним воркером и worker_connections 1024. Клиент
подключается и отправляет заголовки, но не дописывает их до конца - обычное
поведение мобильной сети, а не атака. Параллельно идёт один нормальный запрос.
| медленных клиентов | Apache prefork | Apache event | nginx |
|---|---|---|---|
| 4 | 0,002 с | 0,002 с | 0,001 с |
| 7 | 1,567 с | 0,001 с | - |
| 8 | не ответил | не ответил | 0,001 с |
| 100 | - | - | 0,001 с |
| 700 | - | - | 0,001 с |
Обрыв ровно на восьмой связи - это и есть модель: незаконченный запрос держит процесс (prefork) или поток (event), а их ровно восемь. Девятому клиенту некому ответить, и сайт «лежит», хотя нагрузки нет никакой.
Счётчики процессов под той же нагрузкой:
Apache prefork: 5 процессов в покое -> 9 под нагрузкой
Apache event: 11 потоков, число не меняется
nginx: 2 процесса, число не меняется
Важная тонкость про event, из-за которой его часто переоценивают: он вынес в
отдельный поток простаивающие keepalive-соединения, но не чтение запроса.
Пока заголовки не дочитаны, поток занят - и порог оказался тем же, восьмым.
Эта разница и есть причина, по которой nginx вообще написали: в 1999 году задача называлась «десять тысяч соединений на одной машине», и модель «процесс на соединение» её не решала ни при каком объёме памяти.
Разбор: заголовки на границе каталога
Второе различие видно на одном замысле, записанном дважды: общий заголовок на
сайт плюс свой - для каталога /sub/.
<Directory /www>
Header set X-Level "root"
Header set X-Common "общий"
</Directory>
<Directory /www/sub>
Header set X-Level "sub"
</Directory>
add_header X-Level "root" always;
add_header X-Common "общий" always;
location /sub/ {
add_header X-Level "sub" always;
}
Apache: X-Level: sub X-Common: общий
nginx: X-Level: sub
Apache для /sub/ собрал правила из обеих секций: свой X-Level перекрыл
общий, а X-Common остался. nginx выбрал один блок - location /sub/, - и его
add_header заменил унаследованный набор целиком.
Это не частный случай заголовков, а общее правило nginx, которое встретится ещё
не раз: наследуется целиком или никак. Так же ведут себя proxy_set_header
и списки allow/deny.
Практический вывод для переезда: каждый блок, где появился свой add_header,
обязан повторить общие заголовки - либо один раз написать
add_header_inherit merge; (nginx 1.29.3), и тогда поведение станет ближе к
привычному по Apache.
Разбор: .htaccess после переезда
На Apache файл в каталоге меняет поведение без перезагрузки - замер: положили
.htaccess с одной строкой, следующий же ответ пришёл с новым заголовком. Это
удобство и есть причина, по которой хостинги дают .htaccess вместо доступа к
конфигу.
У nginx такого механизма нет вовсе, и это осознанное решение: за него платят чтением файлов на каждом запросе по всему пути каталогов. Но опасность другая - что nginx сделает с уже лежащим файлом:
код 200, тело: Header set X-From-Htaccess "да"
Файл отдаётся как обычная статика. После переезда со старого хостинга в корне
сайта остаются .htaccess, .env, .git - и всё это открыто, пока не закрыто
явно (двенадцатый раздел). Первое, что делают после переноса, - проверяют
запросом, а не глазами.
Что ломается без этого
Расчёт «клиентов столько же, значит и памяти столько же». У Apache память и
потолок соединений связаны: каждый клиент - процесс или поток со своим стеком,
и MaxRequestWorkers приходится держать таким, чтобы парк влез в оперативную
память. У nginx эта связь разорвана: соединение стоит записи в списке, а память
растёт от работы - от буферов, кеша и тел ответов. Переносить настройки
«в лоб» бессмысленно, у чисел разный смысл.
Надежда на MPM event. Он вынес простаивающие keepalive-соединения в отдельный поток, и его часто считают ответом на медленных клиентов. Замер показал обратное: порог остался тем же, восьмым, потому что незаконченный запрос по-прежнему держит поток. Против медленного чтения помогает не смена MPM, а сервер перед приложением - тот самый буфер из первого урока главы.
Конфиг, переписанный построчно. <Directory> и location похожи ровно до
первого пересечения: в Apache секции складываются в порядке от общего к
частному, в nginx выигрывает один блок по своим правилам приоритета (четвёртый
раздел). Правило из Apache «более частная секция дополняет общую» здесь не
работает.
Ожидание, что «положу файл - и подействует». Всё, что в Apache решалось
.htaccess, в nginx решается конфигом и перезагрузкой. Для сайтов, которые
раздают пользователям каталоги, это меняет схему работы целиком.
Переезд с IIS. Там кроме конфига есть привязка к системе: аутентификация Windows, приложения на .NET в пуле приложений, права через ACL файловой системы. nginx перед .NET-приложением ставят, но заменять им IIS целиком означает переносить и то, что жило в интеграции с доменом.
Зачем это в работе
Короткий ответ на вопрос «что выбрать»:
- nginx - когда нужен фронт: статика, TLS, балансировка, лимиты, кеш. Ниша, ради которой он и написан, - много одновременных соединений при малой памяти.
- Apache - когда нужен
.htaccessдля чужих сайтов (классический хостинг) или модуль, которого больше нигде нет;mod_phpвнутри процесса сегодня почти везде заменён на php-fpmРазбирается в разделе 7, глава «PHP и FastCGI»: Как nginx разговаривает с PHP - отдельную службу для PHP, - к которой одинаково ходят оба сервера. - IIS - когда стек Windows: .NET, аутентификация домена, управление через графический интерфейс.
- Caddy - когда хочется сертификаты «из коробки» и конфиг в пять строк; цена - меньше рычагов, когда понадобится тонко.
- HAProxy, Envoy, Traefik - это уже не веб-серверы, а балансировщики и маршрутизаторы: статику они не отдают, зато у них своё в наблюдаемости и динамической конфигурации.
Связка «nginx впереди, Apache сзади» - до сих пор живая: nginx держит соединения и отдаёт статику, Apache исполняет старое приложение с его модулями. И знание фаз nginx помогает читать чужие конфиги в обе стороны.
Теперь сам
Сайт на Apache prefork с MaxRequestWorkers 150 вечерами перестаёт отвечать,
хотя процессор загружен на десять процентов, а в access_log в эти минуты
почти пусто. Коллега предлагает поднять MaxRequestWorkers до 500. Что тут не
так и куда смотреть?
Ответ: пустой access_log - главная улика. Строка пишется, когда запрос
завершён; если соединения висят на медленном чтении, они держат процессы и
в логе не появляются вовсе. Загруженность процессора при этом низкая - работы
нет, есть ожидание. Поднимать MaxRequestWorkers опасно: каждый процесс prefork
несёт свою память (а с mod_php - ещё и интерпретатор), и 500 процессов
кончатся не отказом в обслуживании, а свопом или OOM. Смотреть надо на число
занятых воркеров против числа завершённых запросов (mod_status), а лечится
это не числом касс, а тем, чтобы медленных клиентов принимал кто-то другой:
nginx впереди дочитывает запрос целиком и отдаёт бэкенду готовый.
Главное
Главное различие - в обслуживании соединения. У Apache оно стоит процесса
(prefork) или потока (worker, event), и потолок жёсткий: замер показал
обрыв ровно на восьмом медленном клиенте при восьми воркерах, причём event не
спас - он вынес в отдельный поток простаивающие keepalive, но не чтение
запроса. У nginx соединение стоит записи в списке одного воркера: семьсот
медленных клиентов не изменили ни времени ответа, ни числа процессов. Второе
различие - конфиг: Apache складывает пересекающиеся секции по каталогам и
читает .htaccess на каждом запросе, nginx выбирает один блок и заменяет
унаследованное (замер: /sub/ получил от Apache и свой заголовок, и общий, а
от nginx - только свой). Оставшийся после переезда .htaccess nginx отдаёт как
статику с кодом 200. IIS - мир Windows и .NET; Caddy - простота и автоматические
сертификаты; HAProxy, Envoy и Traefik - балансировщики, а не веб-серверы.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий