Nginx

Материал из support.qbpro.ru
Версия от 12:44, 17 декабря 2013; imported>Supportadmin

Глава 14 из книги "Архитектура приложений с открытым исходным кодом", том 2.

Оригинал: The Architecture of Open Source Applications: nginx

Автор: Andrew Alexeev,

Дата публикации: 17 мая 2012 г.

Перевод: А.Кикоть

Дата перевода: 08 апреля 2013 г.

nginx (произносится, как "engine x") - это web-сервер с открытым исходным кодом, написанный российским разработчиком Игорем Сысоевым. С момента опубликования в 2004 году nginx фокусировался на высокой производительности, высокоэффективных параллельных вычислениях и минимизации использования оперативной памяти. Такие дополняющие функции web-сервера возможности, как балансировка нагрузки, кэширование, контроль доступа, контроль пропускной способности и умение эффективно интегрироваться с различными приложениями позволили nginx стать хорошим выбором для web-сайтов с современной архитектурой. В настоящее время nginx занимает второе место среди самых популярных web-серверов с открытым исходным кодом.

14.1. Почему высокоэффективные параллельные вычисления так важны?

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

Одной из самых больших проблем при выборе архитектуры web-сайта всегда был параллелизм. С момента появления web-сервисов необходимость в одновременном выполнении различных операций постоянно растёт. Необходимость одновременного обслуживания популярными web-сайтами сотен тысяч или даже миллионов пользователей - вовсе не редкость. Десятилетие назад главной причиной параллелизма была медленная скорость клиентов, использующих ADSL- или dial-up-соединения. В настоящее время параллелизм обусловлен сочетанием мобильных клиентов и новой архитектуры приложений, которые обычно основываются на поддержании постоянного подключения, что позволяет клиенту получать свежие новости, твиты, новостные ленты друзей и т.п. Ещё одним важным фактором, приведшим к увеличению важности параллелизма, стало изменение поведения современных браузеров, которые открывают от 4 до 6 соединений к web-сайту для ускорения загрузки страницы.

Чтобы проиллюстрировать проблему медленных клиентов представьте себе простой web-сервер на основе Apache, который генерирует относительно короткий ответ размером 100 КБ - web-страницу с текстом или изображением. Генерация страницы и ответ на запрос могут занять доли секунды, но занимают 10 секунд из-за скорости передачи клиенту, имеющему скорость доступа 80 Кбит/с (10 КБ/с). То есть, web-сервер будет сравнительно быстро подготавливать содержимое страницы в 100 КБ и затем оставаться занятым ещё 10 секунд из-за медленной передачи клиенту. А теперь представьте, что у вас есть 1000 подключённых клиентов, которые одновременно запросили получение аналогичных страниц. Если на каждого клиента выделять всего по 1 МБ оперативной памяти, то это привело бы к необходимости выделения 1000 МБ (около 1 ГБ) оперативной памяти для передачи 100 КБ информации. В реальности, типовой web-сервер на базе Apache обычно выделяет более 1 МБ на одно соединение, а эффективная скорость мобильных клиентов, к сожалению, десятки кбит/с. Ситуация с отправкой информации медленным клиентам может быть в какой-то степени улучшена путём увеличения буферов обмена сокетов ядра операционной системы, но это не универсальное решение и может иметь нежелательные побочные эффекты.

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

Следовательно, чтобы справиться с возросшей нагрузкой, связанной с увеличивающейся аудиторией и, как следствие, требованиями к параллелизму, а также справляться с этим и далее, web-сайт должен основываться на ряде очень эффективных "строительных" блоков. Другие части этого уравнения, такие как аппаратная часть (ЦПУ, ОЗУ, НЖМД), пропускная способность сети, системное программное обеспечение и архитектура системы хранения, очень важны, но именно программное обеспечение web-сервера принимает и обрабатывает соединения клиентов. То есть, web-сервер должен быть способен к нелинейному масштабированию с ростом числа одновременных соединений и количества запросов в секунду.

Apache не подходит?

Apache - это доминирующий сейчас в Интернете web-сервер, берущий начало в 1990-х годах. Первоначально его архитектура соответствовала операционным системам и аппаратному обеспечению того времени, соответствовала и состоянию Интернета, где было принято для каждого web-сайта выделять физический сервер с единственным экземпляром Apache. К началу 2000-х годов стало очевидно, что модель с выделенным web-сервером не может удовлетворять растущие потребности web-сервисов. Несмотря на прочную основу для будущего развития, заложенную в Apache, его архитектура предусматривала запуск своей копии для каждого нового соединения, что не подходило для нелинейной масштабируемости web-сайта. В итоге Apache стал web-сервером общего назначения и сосредоточился на увеличении количества разнообразных функций и сторонних расширений для обеспечения универсальной применимости к практически любому виду web-разработки. Однако, за всё необходимо платить: столь богатый и универсальный инструментарий в рамках одной программы снижает её возможности к масштабированию из-за увеличенного использования ЦПУ и памяти на каждое соединение.

Таким образом, аппаратная часть сервера, его операционная система и сетевые ресурсы перестали быть основной проблемой для развития web-сайта, что привело web-разработчиков по всему миру к поиску более эффективных средств организации web-серверов. Около десяти лет назад Daniel Kegel, ведущий разработчик программного обеспечения, объявил, что "настало время, когда web-серверы должны обрабатывать десять тысяч клиентских соединений одновременно" и предложил называть всё это облачными сервисами Интернета. Манифест "C10K" Кегеля (Daniel Kegel) обострил проблему оптимизации web-серверов для одновременной поддержки большого числа клиентских соединений и nginx при таком подходе оказался одним из лучших.

С целью преодоления проблемы C10K в 10'000 одновременных соединений в nginx была заложена другая архитектура, подразумевающая лучшую нелинейную масштабируемость, как по числу поддерживаемых одновременных соединений, так и по числу запросов в секунду. nginx основан на событийно-ориентированной модели (event-based), что позволяет ему не порождать новый процесс или поток для каждого запроса web-страницы, как это делает Apache. В результате возрастание нагрузки стало более равномерным, а использование ресурсов памяти и ЦПУ управляемым. nginx мог теперь обрабатывать десятки тысяч одновременных соединений на сервере с обычной аппаратной частью.

С выходом первой версии nginx стало понятно, что он должен применяться совместно с Apache для выдачи поддерживаемой nginx статической информации вроде HTML, CSS, JavaScript и изображений, что позволяло снизить нагрузку и время отклика серверов приложений на базе Apache. В ходе развития в nginx были добавлены интеграция с приложениями с помощью FastCGI, uswgi или SCGI протоколов и системами распределённого кеширования в оперативной памяти, такими как memcached. Также были добавлены другие полезные функции, такие как обратный прокси-сервер с балансировкой и кешированием. Эти дополнительные возможности превратили nginx в эффективный набор инструментов для построения масштабируемой web-инфраструктуры.

В феврале 2012 года был представлен релиз Apache 2.4.x. Несмотря на добавление в эту версию Apache новых модулей с ядром многопоточной обработки и прокси-сервером, направленными на повышение масштабируемости и производительности, ещё прошло слишком мало времени, чтобы говорить о соизмеримых производительности, параллелизме обработки и экономном использовании ресурсов в сравнении с web-сервером, изначально построенным на событийно-ориентированной модели. Было бы очень приятно увидеть лучшую масштабируемость в новой версии сервера приложений Apache, хотя и не понятно, как это поможет устранить узкие места на серверной стороне в типовых web-конфигурациях nginx + Apache.

Есть ли ещё преимущества при использовании nginx?

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

В последние несколько лет web-архитекторы восприняли идею удаления зависимостей и отделения инфраструктры приложений от web-сервера. Однако, то, что раньше существовало в виде web-сайта, основанного на LAMP (Linux, Apache, MySQL, PHP или Perl), теперь может не только основываться на LEMP ("E" означает "enginx"), но и всё чаще встречается в виде web-сервера с интегрированной инфраструктурой или на том же наборе приложений и баз данных, но взаимодействующих на иных принципах.

nginx очень хорошо подходит для этого, так как обеспечивает весь необходимый функционал: снижение нагрузки при обработке одновременных запросов, снижение времени отклика, поддержка SSL (Secure Socket Layer), работа со статической информацией, сжатие и кеширование, управление отказом обслуживания соединений и запросов и даже HTTP-потоковое вещание мультимедийной информации - всё это делает nginx более эффективным для применения в качестве первого принимающего запорсы web-сервера. Он также реализует непосредственную интеграцию с memcached/Redis или другими NoSQL-решениями для повышения производительности при одновременной обработке большого количества пользователей.

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

Первая строка исходного кода nginx была написана в 2002 году. В 2004 году он был выпущен под лицензией "BSD 2-Clause License". С тех пор количество пользователей nginx постоянно растёт, предлагаются новые идеи, представляются отчёты об ошибках, формируются предложения и замечания - всё это вместе чрезвычайно полезно и выгодно для всего сообщества.

Исходный код nginx является оригинальным и был полностью написан "с нуля" на языке программирования Си. nginx был портирован на множество архитектур и операционных систем, включая Linux, FreeBSD, Solaris, Mac OS, AIX и Microsoft Windows. nginx основывается на своих собственных библиотеках и стандартных модулях, имеющих очень мало внешних зависимостей помимо библиотеки языка C, за исключением zlib, PCRE и OpenSSL, которые могут быть исключены во время сборки при необходимости или по лицензионным соображениям.

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

14.2. Обзор архитектуры Nginx

Традиционные процессно- или потоко-ориентированные модели подразумевают при одновременном обслуживании соединений порождение нового процесса или потока на каждое соединение и его блокирование при сетевых операциях или операциях ввода/вывода. В зависимости от способа применения такие модели могут быть крайне неэффективными с точки зрения использования ЦПУ и оперативной памяти. Порождение нового процесса или потока влечёт за собой подготовку новой среды окружения с выделением в оперативной памяти кучи (heap), стека и нового контекста исполнения. ЦПУ тратит дополнительное время на создание этих объектов, что, в конечном итоге, может привести к снижению производительности из-за частого переключения контекста исполнения. Все перечисленные выше проблемы проявляются в web-серверах со старой архитектурой, таких как Apache. Это компромисс между богатым функционалом и оптимальным использованием ресурсов сервера.

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

nginx для мультиплексирования и извещения о событиях использует один главный процесс, а исполнение конкретных задач назначает отдельным подчинённым процессам. Обработка соединений выполняется в высокоэффективных циклах обработки событий, помещённых в потоки. Такие потоки называются "исполнители" (workers), а их количество ограничено. В рамках каждого "исполнителя" nginx может обрабатывать тысячи одновременных подключений и запросов в секунду.

Структура исходного кода

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

Модульная архитектура nginx позволяет разработчикам расширять набор функций без изменения его ядра. Модули nginx подразделяются на несколько типов: модули ядра (core modules), обработчики событий (event modules), обработчики фазы (phase handlers), модули реализации протоколов (protocols), обработчики именованных переменных (variable), фильтры, модули перенаправления запросов на вышестоящие серверы (upstreams) и балансировщики нагрузки (load balancers). В настоящее время nginx не поддерживает динамически загружаемые модули. То есть, модули компилируются вместе с ядром в один исполнимый файл на этапе сборки. Однако, поддержка загружаемых модулей и ABI запланирована на следующие major-релизы. Более подробную информацию о роли различных модулей можно найти в разделе 14.4.

При обработке операций, связанных с приёмом, обработкой и управлением сетевыми подключениями, извлечением данных, а также при дисковых операциях ввода/вывода, nginx для повышения производительности использует специфические механизмы уведомления о событиях, такие как kqueue, epoll и event ports, доступные в операционных системах Linux, Solaris и семействе BSD. Цель состоит в максимальном использовании возможностей операционной системы для обеспечения своевременной обратной связи, по своей природе асинхронной, при обработке входящего/исходящего трафика, дисковых операций, чтения или записи в сокеты, организации тайм-аутов и т.п. Используемые в nginx различные методы мультиплексирования и ускоренного ввода/вывода в значительной степени оптимизированы для каждой Unix-подобной операционной системы, на которой он запускается.

Обзорная схема архитектуры nginx представлена на рисунке 14.1

Дополнительные материалы