Мы в «Латере» занимаемся созданием биллинга для операторов связи и рассказываем на Хабре о разработке своего продукта, а также публикуем интересные технические переводные материалы. И сегодня мы представляем вашему вниманию адаптированный перевод одной из глав книги «Архитектура open-source-приложений», в которой описываются предпосылки появления, архитектура и организация работы популярного веб-сервера nginx.

Значение многопоточности


В наши дни интернет проник повсюду, и очень сложно представить себе, что даже 10-15 лет назад всемирная сеть была куда менее развитой. Интернет эволюционировал от простых HTML-сайтов с кликабельным текстом, работающих на веб-серверах NCSA и Apache, в постоянно работающую среду коммуникации, которую используют миллиарды людей по всему миру. Число постоянно подключенных к сети устройств растет, и интернет-ландшафт меняется, способствуя перетеканию в онлайн целых отраслей экономики. Онлайн-сервисы становятся все более сложными, а для их успешной работы требуется возможность мгновенного получения нужной информации. Аспекты безопасности онлайн-бизнеса также существенно изменились. Поэтому нынешние сайты гораздо сложнее, чем ранее, и в общем случае требуется куда больше инженерных усилий для обеспечения их устойчивости и масштабирования.

Одним из главных вызовов для архитекторов сайтов во все времена была многопоточность. С начала эры веб-сервисов степень многопоточности постоянно растет. Сегодня популярный сайт может одновременно обслуживать сотни тысяч и даже миллионы пользователей, и этим никого не удивить. Еще не так давно многопоточность была нужна для работы с медленными ADSL или dial-up-подключениями. Теперь же многопоточность нужна для работы с мобильными устройствами и новыми архитектурами приложений, которые требуют постоянного и быстрого соединения — клиент должен получать обновления твитов, новостей, информации из ленты соцсетей и т.п. Еще один важный фактор, влияющий на многопоточность — это изменившееся поведение браузеров, которые для ускорения загрузки сайта открывают от четырех до шести одновременных соединений к нему.

Представьте простой Apache-сервер, который генерирует короткие ответы в 100 Кбайт — простая веб-страница с текстом или изображениями. На генерацию и отрисовку страницы может уходить доля секунды, но на ее передачу клиенту потребуется 10 секунд при наличии полосы пропускания 80 кбит/с. Веб-сервер сможет относительно быстро «вытянуть» 100 килобайт контента, а затем 10 секунд он будет медленно пересылать их клиенту. А теперь представьте, что у вас 1000 одновременно подключенных клиентов, которые запросили один и тот же контент. Если для каждого клиента требуется выделение 1 Мб дополнительной памяти, то всего понадобится 1 гигабайт памяти для того, чтобы отправить 1000 клиентов 100 килобайт контента.

В случае постоянных соединений проблема обработки многопоточности встает еще более остро, поскольку для того, чтобы избежать задержек, связанных с установлением нового HTTP-соединения, клиенты будут оставаться подключенными.

Чтобы обрабатывать возросшие объёмы нагрузки, связанные с расширением аудитории интернета и, как следствие, повышением уровней многопоточности, фундамент функциональности сайта должен состоять из очень эффективных блоков. В этом уравнении важны все компоненты — железо (CPU, память, диски), сетевая емкость, архитектура приложения и хранилища данных — однако клиентские запросы принимаются и обрабатываются именно веб-сервером. Поэтому он должен обладать способностями к нелинейному масштабированию с растущим числом одновременных соединений и обрабатываемых в секунду запросов.

Проблемы Apache


Веб-сервер Apache до сих пор занимает видное место в интернете. Корни этого проекта уходят в начало 1990-х годов, и изначально его архитектура была заточена под существовавшие тогда системы и аппаратное обеспечение, а также общую степень развития интернета. Тогда веб-сайт, как правило, представлял из себя отдельный физический сервер, на котором работал единственный экземпляр Apache. К началу двухтысячных стало очевидно, что модель с единственным физическим сервером не может быть эффективно реплицирована для удовлетворения нужд растущих веб-сервисов. Несмотря на то, что Apache является неплохой платформой для дальнейших разработок, изначально он был спроектирован для создания копии веб-сервера для каждого нового соединения, что в современных условиях не позволяет добиться необходимой масштабируемости.

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

Традиционные основанные на работе с потоками или процессами модели обработки одновременных соединений подразумевают обработку каждого соединения с помощью отдельного процесса или потока и блокирование операций ввода/вывода. В зависимости от приложения такой подход может быть крайне неэффективным с точки зрения затрат ресурсов процессора и памяти. Создание отдельного процесса или потока требует подготовки новой среды запуска, включая выделение памяти стека и кучи, а также создания нового контекста выполнения. На все это тратится дополнительное процессорное время, что в итоге может приводить к проблемам с производительностью из-за избыточных переключений контекста. Все эти проблемы в полной мере проявляются при использовании веб-серверов старой архитектуры, таких как Apache.



Практическое сравнение работы двух популярнейших веб-серверов опубликовано на Хабре в этом материале.

Обзор архитектуры веб-сервера nginx


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

Nginx активно использует мультиплексирование и нотификации событий, назначая конкретные задачи отдельным процессам. Соединения обрабатываются с помощью эффективного цикла выполнения с помощью определенного количества однопоточных процессов, называемых worker’ами. Внутри каждого worker nginx может обрабатывать многие тысячи одновременных соединений и запросов в секунду.

Структура кода


Worker в nginx включает ядро и функциональные модули. Ядро nginx отвечает за поддержание цикла выполнения и исполнения подходящих секций кода модулей на каждом шаге обработки процесса. Модули предоставляют большую часть функциональности уровня приложений. Также модули читают и пишут в сеть и хранилище, трансформируют контент, осуществляют исходящую фильтрацию и, в случае работы в режиме прокси, передают запросы вышестоящим серверам.

Модульная архитектура nginx позволяет разработчикам расширять набор функций веб-сервера без необходимости модификации кода его ядра. Существует несколько разновидностей модулей nginx — модули ядра, модули событий, фазовые обработчики, протоколы, фильтры, балансировщики нагрузки, обработчики переменных и т.п. При этом nginx не поддерживает динамически загружаемые модули, то есть они компилируются вместе с ядром на стадии создания сборки. Разработчики планируют добавить функциональность загружаемых модулей в будущем.

Для организации различных действий, связанных с приемом, обработкой и управлением сетевыми соединениями и загрузкой контента, nginx использует механизмы нотификаций и несколько механизмов улучшения производительности дискового ввода/вывода в ОС Linux, Solaris и BSD-системах — среди них kqueue, epoll и event ports.

Высокоуровневое представление архитектуры nginx показано на рисунке ниже:



Модель работы worker-процессов


Как было отмечено выше, nginx не создает процесс или поток для каждого соединения. Вместо этого специальный worker обрабатывает прием новых запросов с общего «слушающего» сокета и запускает высокоэффективный цикл выполнения внутри каждого worker-процесса — это позволяет обрабатывать тысячи соединений для одного worker’а. Каких-то специальных механизмов распределения соединений между разными worker-процессами в nginx нет, эта работа выполняется в ядре ОС. В процессе загрузки создается набор слушающих сокетов, а затем worker постоянно принимает, считывает и пишет в сокеты в процессе обработки HTTP-запросов и ответов.

Самой сложной частью кода «воркеров» nginx является описание цикла выполнения. Он включает всевозможные внутренние вызовы и активно использует концепцию асинхронной обработки задач. Асинхронные операции реализованы посредством модульности, оповещений о событиях, а также широкого использования колбэк-функций и доработанных таймеров. Главная цель всего этого — по максимуму уйти от использования блокировок. Единственным случаем, когда nginx может их применять, является ситуация недостаточной для работы worker-процесса производительности дискового хранилища.

Поскольку nginx не создает процессы и потоки для каждого соединения, в подавляющем большинстве случаев веб-сервер очень консервативно и крайне эффективно работает с памятью. Кроме того он сохраняет циклы процессора, поскольку в случае nginx отсутствует паттерн постоянного создания и уничтожения процессов и потоков. Nginx проверяет состояние сети и хранилища, инициализирует новые соединения, добавляет их в цикл выполнения, а затем асинхронно обрабатывает до «победного конца», после чего соединение деактивируется и исключается из цикла. Благодаря этому механизму, а также вдумчивому использованию системных вызовов и качественной реализации поддерживающих интерфейсов вроде распределителей памяти (pool и slab), nginx позволяет добиться низкой или средней загрузки CPU даже в случае экстремальных нагрузок.

Использование нескольких worker-процессов для обработки соединений также делает веб-сервер хорошо масштабируемым для работы с несколькими ядрами. Эффективное использование многоядерных архитектур обеспечивается созданием одного worker-процесса для каждого ядра, а также позволяет избежать блокировок и трешинга потоков. Механизмы контроля ресурсов изолированы внутри однопоточных worker-процессов — такая модель также способствует более эффективному масштабированию физических устройств хранения, позволяет добиваться более высокой утилизации дисков и избегать блокирования дискового ввода/вывода. В итоге ресурсы сервера используются эффективнее, а нагрузка распределяется между несколькими worker-процессами.

Для разных паттернов загрузки процессора и диска число worker-процессов nginx может изменяться. Разработчики веб-сервера рекомендуют системным администраторам пробовать различные варианты конфигурации, чтобы получить наилучшие результаты в плане производительности. Если паттерн можно описать как «интенсивную загрузку CPU» — например, в случае обработки большого количества TCP/IP-соединений, осуществления компрессии или использовании SSL, то число «воркеров» должно совпадать с количеством ядер. Если же нагрузка в основном падает на дисковую систему — например, при необходимости загрузки и выгрузки из хранилища крупных объёмов контента — то число worker-процессов может быть в полтора-два раза больше количества ядер.

В следующих версиях веб-сервера разработчики nginx планируют решить проблему возникновения ситуаций блокировки дискового I/O. На момент написания этой главы в случае недостаточной производительности хранилища при осуществлении дисковых операций конкретного worker-процесса, для него может быть заблокирована возможность чтения или записи. Чтобы свести такую вероятность к минимуму, можно использовать различные комбинации директив конфигурационных файлов и существующих механизмов — например, опции sendfile и AIO обычно позволяют серьезно повысить производительность хранилища.

Еще одна проблема существующей модели worker-процессов связана с ограниченной поддержкой встроенных скриптов. В случае стандартной версии nginx доступно лишь встраивание Perl-скриптов. Такая ситуация объясняется просто — главной проблемой является вероятность того, что встроенный сценарий будет заблокирован в ходе выполнения операции или неожиданно завершится. В обоих случаях worker-процесс зависнет, что может затронуть тысячи соединений разом.

Роли процессов nginx


Nginx запускает несколько процессов в памяти — один master-процесс и несколько «воркеров». Также существует несколько службных процессов — например, менеджер и загрузчик кэша. В версиях nginx 1.x все процессы однопоточные. Все они используют для взаимодействия друг с другом механизмы разделения памяти. Master-процесс запускается под пользователем root. Служебные и worker-процессы работают без привилегий суперпользователя.

Master-процесс отвечает за следующие задачи:

  • чтение и валидация конфигурации;
  • создание, связывание и закрытие сокетов;
  • старт, прерывание и поддержка сконфигурированного количества worker-процессов;
  • реконфигурация без прерывания работы сервиса;
  • контроль постоянных двоичных обновлений (запуск новых «бинарников» и откат на предыдущую версию в случае необходимости);
  • повторное открытие лог-файлов;
  • компиляция встроенных Perl-скриптов.



Внутреннее устройство nginx описывалось на Хабре в этой статье

Worker-процессы принимают и обрабатывают поступающие от клиентов соединения, предоставляют функциональность reverse proxy и фильтрации, а также делают почти все, что должен делать nginx. В общем случае, чтобы отследить текущее состояние веб-сервера, системному администратору нужно взглянуть на воркеры, поскольку именно они его [состояние] лучше всего отражают.

Процесс загрузчика кэша отвечает за проверку элементов, находящихся в кэше на диске, а также за обновление размещенной в памяти базы метаданными. Загрузчик готовит экземпляры nginx к работе с уже хранящимися на диске файлами. Он проходит по директориям, изучает метаданные контента в кэше, обновляет необходимые элементы в разделяемой памяти, а затем завершает работу.

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

Краткий обзор кэширования в nginx


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

Процесс помещения контента в кэш проходит следующим образом: когда nginx считывает ответ с вышестоящего сервера, контент сначала записывается во временный файл вне структуры директорий кэша. Когда веб-сервер заканчивает обработку запроса, он меняет имя временного файла и перемещает его в директорию кэша. Если директория временных файлов размещается на другой файловой системе, то файл будет скопирован, поэтому рекомендуется размещать временную и кэш-директорию на одной файловой системе. Кроме того, с точки зрения безопасности хорошим решением в случае необходимости очистки файлов будет и их удаление из кэша, поскольку существуют сторонние расширения для nginx, которые могут предоставлять удаленный доступ к кэшированному контенту.

Конфигурация nginx


На создание конфигурационной системы nginx Игоря Сысоева вдохновил опыт работы с Apache. Разработчик считал, что для веб-сервера необходима масштабируемая конфигурационная система. И главная проблема масштабируемости возникала при необходимости поддержки большого количества сложных конфигураций с множеством виртуальных серверов, директорий и наборов данных. Поддержка и масштабирование относительно крупной веб-инфраструктуры может превратиться в настоящий ад.

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

Конфигурация nginx хранится в нескольких текстовых файлах, которые обычно располагаются в директориях /usr/local/etc/nginx или /etc/nginx. Главный конфигурационный файл обычно называется nginx.conf. Чтобы сделать его более читабельным, части конфигурации можно разнести по разным файлам, которые затем включаются в главном. При этом важно заметить, что nginx не поддерживает файлы .htaccess — вся конфигурационная информация должна располагаться в централизованном наборе файлов.

Изначальное чтение и проверка конфигурационных файлов осуществляется master-процессом. Скомпилированная форма конфигурации для чтения доступна worker-процессам после их выделения из master-процесса. Конфигурационные структуры автоматически разделяются механизмами управления виртуальной памятью.

Существует несколько различных контекстов для блоков и директив main, http, server, upstream, location (mail, для mail proxy). К примеру, нельзя поместить блок location в блок директив main. Также, чтобы не добавлять лишнюю сложность, в nginx нет конфигурации «глобального веб-сервера». Как говорит сам Сысоев:

Локации, директории и другии блоки в конфигурации глобального веб-сервера — это то, что мне никогда не нравилось в Apache, поэтому они никогда не появлялись в nginx.

Синтаксис и форматирование конфигурации nginx следуют стандарту оформления кода C (“C-style convention”). Несмотря на то, что некоторые директивы nginx отражают определенные части конфигурации Apache, в целом настройка двух веб-серверов серьезно отличается. К примеру, в nginx поддерживаются правила перезаписи, а в случае Apache для этого администратор вручную должен будет адаптировать legacy-конфигурацию. Различается и реализация «движка» перезаписи.

Nginx также поддерживает несколько полезных оригинальных механизмов. К примеру — переменные и директива try_files. В nginx переменные используются для реализации мощного механизма контроля run-time-конфигурации веб-сервера. Они могут использоваться с различными конфигурационными директивами для обеспечения дополнительной гибкости в описании условий обработки запросов.

Директива try_files изначально создавалась в качестве замены условных операторов if, а также для быстрого и эффективного сопоставления разных URL и контента.

Внутреннее устройство nginx


Nginx состоит из ядра и целого ряда модулей. Ядро отвечает за создание основы веб-сервера, работу функциональности web- и reverse-прокси. Также оно отвечает за использование сетевых протоколов, построение среды запуска и обеспечение беспроблемного взаимодействия между разными модулями. Однако большая часть функций, связанных с протоколами и приложениями, реализуется с помощью модулей, а не ядра.

Соединения обрабатываются nginx с помощью трубы или цепи модулей. Другими словами, для каждой операции есть модуль, который выполняет нужную работу — например, компрессию, модификацию контента, выполнение серверных включений, взаимодействие с внешними серверами через FastCGI или uwsgi-протоколы, или общение с memcahed.

Существует пара модулей, которые размещаются между ядром и «функциональными» модулями — это http и mail-модули. Они обеспечивают дополнительный уровень абстракции между ядром и низкоуровневыми компонентами. С их помощью реализована обработка последовательностей событий, связанных с определенным сетевым протоколом вроде HTTP, SMTP или IMAP. Вместе с ядром эти высокоуровневые модули отвечают за поддержание верного порядка вызовов соответствующих функциональных модулей. В настоящий момент HTTP-протокол реализован в качестве части http-модуля, однако в будущем разработчики планируют выделить его в отдельный функциональный модуль — это продиктовано необходимостью поддержки других протоколов (например, SPDY).

Большинство существующих модулей дополняют HTTP-функциональность nginx, но модули событий и протоколов также используются и для работы с почтой (mail). Модули событий предоставляют механизм оповещений о событиях для различных ОС — например, kqueue или epoll. Выбор модуля, используемого nginx, зависит от конфигурации сборки и возможностей операционной системы. Модули протоколов позволяют nginx работать через HTTPS, TLS/SSL, SMTP, POP3 и IMAP.

Вот так выглядит типичный цикл обработки HTTP-запроса:

  1. Клиент отправляет HTTP-запрос.
  2. Ядро в соответствии со сконфигурированной локацией для запроса nginx выбирает нужный фазовый обработчик.
  3. В случае включенной прокси-функциональности модуль балансировки нагрузки выбирает для целей проксирования вышестоящий сервер.
  4. Фазовый обработчик заканчивает свою работу и передает буфер вывода первому фильтру.
  5. Первый фильтр передает вывод второму фильтру.
  6. Второй фильтр передает вывод третьему фильтру (и так далее).
  7. Итоговый ответ пересылается клиенту.

Вызов модулей в nginx можно настраивать, он осуществляется с помощью колбэков с указателями на исполняемые функции. Минус здесь заключается в том, что если разработчик хочет написать собственный модуль, то ему нужно будет четко прописать, как и где он должен запускаться. К примеру, вот в каких точках это может происходить:
  • До чтения и обработки конфигурационного файла.
  • В момент завершения инициализации главной конфигурации.
  • После инициализации сервера (хоста/порта).
  • Когда серверная конфигурация сливается с основной.
  • Когда стартует или завершается master-процесс.
  • В момент старта или завершения нового worker-процесса.
  • В момент обработки запроса.
  • В процессе фильтрации заголовка и тела ответа.
  • При выборе начальной и повторной инициализации запроса к вышестоящему серверу.
  • В процессе обработки ответа от вышестоящего сервера.
  • В момент завершения взаимодействия с этим сервером.

Внутри воркера последовательность действий, ведущая в цикл обработки, где генерируется ответ, выглядит следующим образом:

  • Старт ngx_worker_process_cycle().
  • События обрабатываются с помощью механизмов ОС (например, epoll или kqueue).
  • События принимаются, отправляются соответствующие действия.
  • Процесс/прокси запрашивает заголовок и тело.
  • Контент ответа (заголовок, ответ) генерируется и отправляется клиенту.
  • Запрос финализируется.
  • Таймеры и события повторно инициализируются.

Более детализированное описание обработки HTTP-запроса можно представить так:

  1. Инициализация обработки запроса.
  2. Обработка заголовка.
  3. Обработка тела.
  4. Вызов соответствующего обработчика.
  5. Прохождение фаз обработки.

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

После прочтения заголовка HTTP-запроса, nginx просматривает связанную конфигурацию виртуального сервера. Если виртуальный сервер найден, то запрос проходит шесть фаз:

  1. Фаза перезаписи сервера.
  2. Фраза поиска местоположения (location).
  3. Перезапись местоположения.
  4. Фаза контроля доступа (access control).
  5. Фаза работы try_files.
  6. Фаза записи логов.

В процессе создания контента в ответ на запрос, nginx передает его различным обработчикам контента. Сначала запрос может попасть к так называемым безусловным обработчикам вроде perl, proxy_pass, flv, mp4. Если запрос не подходит ни к одному из этих обработчиков контента, то он по цепочке передается следующим обработчикам: random index, index, autoindex, gzip_static, static.

Если специализированный модуль вроде mp4 или autoindex не подходит, то контент рассматривается в качестве директории на диске (то есть, в качестве статического) и за него отвечает контент-обработчик static.

После этого контент передается фильтрам, которые работают по определенной схеме. Фильтр получает вызов, начинает работать, вызывает следующий фильтр и так до момента вызова последнего фильтра в цепочке. Существуют фильтры заголовков и тела. Работа фильтра заголовка состоит из трех основных шагов:

  1. Определение необходимости действий в ответ на запрос.
  2. Обработка запроса.
  3. Вызов следующего фильтра.

Фильтры тела трансформируют сгенерированный контент. Среди их возможных действий:

  • Серверные включения.
  • Фильтрация XSLT.
  • Фильтрация изображений (наример, ресайзинг картинок на лету).
  • Модификация кодировки.
  • Gzip-компрессия.
  • Кодирование фрагментов (chunked encoding).

После прохождения цепочки фильтров ответ передается в модуль записи. Также существуют два специальных фильтра — copy и postpone. Первый из них отвечает за наполнение буферов памяти релевантным контентом ответов, а второй используется для подзапросов.

Подзапросы — это очень важный и очень мощный механизм для обработки запросов и ответов. С помощью подзапросов nginx может вернуть результат для разных URL, запрошенных клиентом. Некоторые веб-фреймворки для решения этой задачи используют внутренние редиректы, однако nginx идет дальше — фильтры не только выполняют разные подзапросы и комбинируют их вывод в один общий ответ, но подзапросы также могут быть иерархичными и вложенными. То есть подзапрос может выполнять собственный подзапрос («под-подзапрос»), а тот, в свою очередь, может инициировать «под-под-подзапрос».

Подзапросы могут указывать на файлы на диске, другие обработчики или вышестоящие серверы. Они крайне полезны для вставки дополнительного контента при использовании данных из первоначального запроса. К примеру, SSI-модуль (server side include) использует фильтр для парсинга содержимого возвращенного документа, а затем заменяет директивы include контентом из указанных URL-адресов. Точно так же можно создать фильтр, который превращает все содержимое документа в URL, а затем добавляет к URL сам новый документ.

Также в nginx есть модули балансировки нагрузки и upstream-модули. Последние используются для подготовки контента к отправки вышестоящему серверу и получения ответов от него. В этом случае не происходит вызовов фильтров вывода. Upstream-модуль устанавливает колбэки, которые нужно вызвать, когда вышестоящий сервер будет готов к записи или чтению. Существуют колбэки для реализации следующей функциональности:

  • Организация буфера запроса для отправки вышестоящему серверу.
  • Повторная инициализация соединения с сервером (она происходит перед созданием запроса).
  • Обработка первых битов ответа и сохранение указателей на данные, полученные с сервера.
  • Прерывание запросов (происходит при неожиданном отключении клиента).
  • Финализация запроса после того, как nginx закончит чтение с вышестоящего сервера.
  • Обрезание тела ответа (удаление трейлера).

Модули балансировки нагрузки добавляются к обработчику proxy_pass для обеспечения возможности выбора вышестоящего сервера — в случае, если их более одного. Механизмы работы с вышестоящими серверами и балансировки нагрузки позволяют выявлять неисправные серверы и перенаправлять запросы к функционирующим узлам.

Также в nginx есть интересные модули, которые предоставляют дополнительный набор переменных для использования в конфигурационном файле. В nginx переменные главным образом создаются и обновляются в различных модулях, но есть и два модуля, которые целиком посвящены переменным: geo и map. Модуль geo используется для облегчения отслеживания клиентов по IP-адресам. Он может создавать случайные переменные, которые зависят от IP-адреса клиента. Второй модуль, map, позволяет создавать переменные из других переменных, что облегчает маппинг имен хостов и других runtime-переменных.

Механизмы распределения памяти в worker-процессах nginx были созданы с опорой на опыт Apache. Высокоуровневое описание работы с памятью в nginx звучит так: для каждого соединения необходимые буферы памяти динамически выделяются, линкуются и используются для хранения и изменения заголовка и тела запроса или ответа, а затем освобождаются при завершении соединения. Nginx пытается по-максимуму избегать копирования данных в памяти, большая часть из них обрабатывается с помощью переменных указателей без вызова memcpy.

Задача управления распределением памяти решается с помощью специального распределителя пула nginx. Зоны разделяемой памяти используются для приема мьютекс, метаданных кэша, кэша SSL-сессий и информации, связанной с управлением полосой пропускания (лимиты). Для управления распределением памяти в nginx реализован slab-распределитель. Безопасное использование разделяемой памяти осуществляется за счет механизмов блокировки (мьютексы и семафоры). Для организации сложных структур данных в nginx используется реализация красно-черных деревьев. Они применяются для сохранения метаданных кэша в разделяемой памяти, отслеживания не-regex определения местоположений и для некоторых других задач.

Дополнительные материалы по работе с nginx:

Комментарии (10)


  1. evg_krsk
    16.12.2015 15:22
    +7

    Мне кажется, или именно такая статья с такими картинками относительно недавно была на хабре?


    1. NatalyM
      16.12.2015 16:05
      +1

      По идее в статье есть ссылки на материалы с Хабра, где были представлены эти картинки – вот например в конце статьи, да и после самих картинок. То есть, выходит, что статьи такой еще не было (я не вижу по крайней мере), а картинки уже были


    1. monah_tuk
      16.12.2015 17:40
      +1

      Тоже какое-то ощущение дежавю.


  1. UncleAndy
    16.12.2015 16:18
    +3

    Наблюдаю за развитием nginx, практически, с самого начала. Думаю, я был одним из первых его пользователей на продакшене. :) Один из тех продуктов, про который хочется сказать что в нем прекрасно все. :)


    1. dom1n1k
      17.12.2015 03:10

      offtop давайте составим список таких продуктов


  1. Synoptic
    16.12.2015 16:53
    +2

    Есть полные переводы обеих книг тут.


  1. lexore
    17.12.2015 13:48

    Что-то мне подсказывает, что вот эта картинка изначально была цветной.


    1. Error_403_Forbidden
      17.12.2015 15:14

      Из всей статьи заинтересовало только это? Однако…


      1. lexore
        17.12.2015 15:19

        Ну, это ваше личное предположение, о том, что меня заинтересовало. Статья большая, поэтому я остправил себе ссылку для чтения, когда будет время. А про картинку я могу написать уже сейчас. Глядишь, к тому моменту когда я начну чтение, автор уже поставит цветную.


        1. Error_403_Forbidden
          18.12.2015 17:38

          Мне больше ч/б нравится. Надеюсь, не поставит цветную.