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

Поток запросов
- Сервером прослушиваются новые запросы на подключение.
- При поступлении новый запрос принимается сервером, создается специализированный процесс, и запрос назначается в обработку.
- Процесс остается в ожидании или блокируется до завершения внешних операций, таких как дисковый или сетевой ввод-вывод. Это случается многократно во время обработки запроса.
- По завершении запроса процесс остается в ожидании, планируется ли клиентом запустить новый запрос, это поддерживаемое подключение. Если подключение клиентом закрывается или случается тайм-аут, сервером процесс завершается и прослушиваются новые запросы на подключение.
Архитектура Nginx
Nginx создана на четырех основных компонентах:
- Ведущий процесс занимается загрузкой конфигурации сервера и созданием дочерних процессов — трех остальных компонентов.
- Загрузчиком кэша, прежде чем завершается его работа, загружается дисковый кэш в память.
- Диспетчер кэша периодически запускается, им удаляются ненужные или просроченные записи из дискового кэша, размер которого таким образом поддерживается пределах заданного лимита.
- Рабочим процессом управляются сетевые подключения, сетевой и дисковый ввод-вывод. Им выполняется вся работа. Когда запускается сервер, ведущим процессом на основе конфигурации сервера инициализируются рабочие процессы.

Событийный подход Nginx
В отличие от традиционных серверов, на Nginx для каждого входящего запроса не создается отдельного процесса или потока. Каждым рабочим процессом прослушиваются события, генерируемые новыми входящими запросами. Рабочими процессами же принимаются запросы на подключение и начинается обработка.
Однако, вместо того чтобы блокироваться или ожидать ответа во время сетевого и дискового ввода-вывода, рабочим процессом немедленно принимается другой запрос на подключение из входящего пула или продолжается обработка запросов, которыми завершен их дисковый и сетевой ввод-вывод и они остаются в ожидании дальнейшего выполнения.

Почему это быстрее?
В традиционных серверах, где для каждого запроса на подключение создается процесс, для каждого такого процесса требуются циклы процессора. Каждому процессу эти циклы процессора предоставляются переключениями контекста.
Переключению контекста требуется сохранение текущего состояния запущенного процесса для дальнейшего восстановления, а затем загрузки состояния другого процесса для его запуска. Переключение контекста, а также дополнительные накладные расходы и ресурсы, необходимые для создания процесса для каждого запроса на подключение, сказываются на общей производительности сервера.
В Nginx же все входящие запросы обрабатываются рабочими процессами, число которых фиксировано и равно количеству ядер процессора. Это чревато сокращением переключений контекста, ведь каждому рабочему процессу назначается ядро процессора.
А кроме того, таким образом избегаются дополнительное потребление ресурсов и накладные расходы на создание процессов, поскольку рабочие процессы создаются при запуске сервера. Так на Nginx обрабатываются сотни тысяч подключений каждым рабочим процессом.
Читайте также:
- Развертывание Kubernetes с пользовательским файлом index.html в поде Nginx с ConfigMap
- Как запустить несколько приложений React на одном порту Nginx с Docker
- 17 промежуточных программ для эффективной FastAPI-разработки
Читайте нас в Telegram, VK и Дзен
Перевод статьи Sid: How Nginx Handles Thousands of Concurrent Requests





