Apache или nginx что выбрать

ИТ База знаний

Полезно

— Онлайн генератор устойчивых паролей

— Онлайн калькулятор подсетей

— Руководство администратора FreePBX на русском языке

— Руководство администратора Cisco UCM/CME на русском языке

— Руководство администратора по Linux/Unix

Навигация

Серверные решения

Телефония

FreePBX и Asterisk

Настройка программных телефонов

Корпоративные сети

Протоколы и стандарты

Apache vs Nginx – сравнение и преимущества

На сегодняшний день двумя наиболее популярными веб-серверами с открытым исходным кодом для работы в Интернете являются HTTP-сервер Apache и Nginx. Более 50% веб-сайтов в мире работают на этих двух веб-серверах. В течение почти двух десятилетий веб-сервер Apache обслуживал около 60 процентов веб-сайтов в мире, пока не появился его конкурент Nginx (произносится как «engine-x»). В связи с резким ростом объемов трафика данных и количества пользователей всемирной паутины, Nginx был введен для преодоления ограничений производительности веб-серверов Apache. Nginx, разработанный для обеспечения более высокого уровня параллелизма, может быть развернут в качестве автономного веб-сервера и в качестве внешнего прокси-сервера для Apache и других веб-серверов. Прочитать про установку и настойку этих серверов можно в этой статье

Apache или nginx что выбрать. Смотреть фото Apache или nginx что выбрать. Смотреть картинку Apache или nginx что выбрать. Картинка про Apache или nginx что выбрать. Фото Apache или nginx что выбрать

Apache или nginx что выбрать. Смотреть фото Apache или nginx что выбрать. Смотреть картинку Apache или nginx что выбрать. Картинка про Apache или nginx что выбрать. Фото Apache или nginx что выбрать

Краткий обзор Apache

Модель «один сервер делает все» стала ключом к раннему успеху Apache. Однако по мере увеличения уровня трафика и увеличения количества веб-страниц и ограничения производительности настройка Apache на работу с реальным трафиком усложнялась.

Краткий обзор Nginx

Nginx также имеет богатый набор функций и может выполнять различные роли сервера:

Apache против Nginx: сравнение их богатых наборов функций

Простота

Разрабатывать и обновлять приложения на Apache очень просто. Модель «одно соединение на процесс» позволяет очень легко вставлять модули в любой точке логики веб-обслуживания. Разработчики могут добавлять код таким образом, что в случае сбоев будет затронут только рабочий процесс, выполняющий код. Обработка всех других соединений будет продолжаться без помех.

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

Производительность

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

Статический контент

Nginx работает в 2,5 раза быстрее, чем Apache, согласно тесту производительности, выполняемому до 1000 одновременных подключений. Другой тест с 512 одновременными подключениями показал, что Nginx примерно в два раза быстрее и потребляет меньше памяти. Несомненно, Nginx имеет преимущество перед Apache со статическим контентом. Поэтому, если вам нужно обслуживать одновременный статический контент, Nginx является предпочтительным выбором.

Динамический контент

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

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

Nginx не имеет возможности обрабатывать динамический контент изначально. Чтобы обрабатывать PHP и другие запросы на динамический контент, Nginx должен перейти на внешний процессор для выполнения и дождаться отправки визуализированного контента. Однако этот метод также имеет некоторые преимущества. Поскольку динамический интерпретатор не встроен в рабочий процесс, его издержки будут присутствовать только для динамического содержимого.

Поддержка ОС

Apache работает во всех операционных системах, таких как UNIX, Linux или BSD, и полностью поддерживает Microsoft Windows. Nginx также работает на нескольких современных Unix-подобных системах и поддерживает Windows, но его производительность в Windows не так стабильна, как на платформах UNIX.

Безопасность

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

Гибкость

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

Большинство необходимых функциональных возможностей основного модуля (например, прокси, кэширование, распределение нагрузки) поддерживаются обоими веб-серверами.

Поддержка и документация

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

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

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

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

Ngnix против Apache: Сравнение лицом к лицу

Подводя итог, вот табличное представление наборов функций:

Итак, что выберите? Apache или Nginx?

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

Источник

Apache против Nginx: плюсы и минусы для WordPress

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

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

По оценкам, из всего Интернета в совокупности Apache Server и Nginx вместе составляют 50% всего веб-трафика.

Отличия

Основное различие заключается в том, как обрабатываются соединения.

Проще говоря, Apache использует разветвленное многопоточное решение или keep-alive, которое поддерживает соединение для каждого пользователя.

С другой стороны, Nginx использует неблокирующий цикл событий, который объединяет соединения, работающие асинхронно через рабочие процессы.

Apache или nginx что выбрать. Смотреть фото Apache или nginx что выбрать. Смотреть картинку Apache или nginx что выбрать. Картинка про Apache или nginx что выбрать. Фото Apache или nginx что выбратьApache или nginx что выбрать. Смотреть фото Apache или nginx что выбрать. Смотреть картинку Apache или nginx что выбрать. Картинка про Apache или nginx что выбрать. Фото Apache или nginx что выбрать Apache или nginx что выбрать. Смотреть фото Apache или nginx что выбрать. Смотреть картинку Apache или nginx что выбрать. Картинка про Apache или nginx что выбрать. Фото Apache или nginx что выбрать

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

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

Во-первых, давайте посмотрим на два проекта и сделаем четкий обзор.

Apache

Nginx

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

Для статического контента это работает очень быстро. Что касается динамического контента, например PHP, Nginx не имеет возможности обрабатывать это с помощью модуля, как это делает Apache. Но это не помеха, поскольку для достижения этого используется FastCGI. Это очень хорошо работает в сочетании с пулами соединений php fpm и memcache.

Требования WordPress

Оба Apache и Nginx поддерживают php fpm. Это менеджер FastCGI, forked process manager для PHP, который может использоваться для обеспечения очень быстрого времени отклика. Выполняясь как демон на сервере, он будет инициализировать процессы, как только они потребуются.

Настройка PHP FPM с помощью Apache

Пользователи Ubuntu и Debian могут устанавливать необходимые пакеты с помощью aptitude через:

Теперь включите модуль в apache:

Затем в файле конфигурации /etc/apache2/conf-available/php7.0-fpm.conf добавьте следующее:

Кроме того, в вашем VirtualHost для WordPress (путь по умолчанию /etc/apache2/sites-available/000-default.con f) добавьте следующее:

Теперь перезапустите apache, и готово

Создайте файл с содержимым вида и откройте его в своем браузере. Теперь PHP будет работать с FPM.

Теперь проверьте свой блог WordPress. Обратили внимание на разницу?

Настройка PHP FPM с Nginx

Пользователи Ubuntu и Debian могут установить пакет следующим образом:

Теперь в вашем файле конфигурации (по умолчанию /etc/nginx/sites-available/default) в блоке сервера вам необходимо добавить конфигурацию FastCGI следующим образом:

Здесь мы используем фрагмент из Nginx, чтобы установить параметры cgi и передать fastcgi соединение сокета.

Затем убедитесь, что вы установили cgi.fix_pathinfo = 0 в php ini, поскольку настройка по умолчанию нарушает конфигурацию. Измените /etc/php/7.0/fpm/php.ini и установите:

Теперь вы можете сохранить файл и перезагрузить PHP FPM. Сделайте это через:

Наконец, мы можем проверить в своем браузере, чтобы подтвердить, что сервер теперь использует PHP FPM с Nginx.

Выполнение mod_rewrite в Nginx

Чтобы ваш блог WordPress работал с Nginx, просто добавьте следующее к части try_files вашей конфигурации Nginx:

Если вы используете каталог для своего блога WordPress, задайте следующее:

Перезапустите Nginx, и у вас будет работать перезапись URL.

Оптимальные настройки

У вас есть много вариантов оптимизации WordPress посредством кеширования на сервере с помощью memcache, varnish, а также на уровне приложения WordPress с помощью плагинов, которые легко позволят вам получить доступ к этому.

Кэш статического содержимого

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

Блок местоположения для этой конфигурации статических субдоменов будет выглядеть так:

Если вы хотите настроить кеширование по всему проекту, просто добавьте следующие четыре строки в свои конфигурации nginx.conf:

Важно: open_file_cache_errors будет кэшировать фактические ошибки 404, поэтому лучше отключить это, если вы используете балансировщик нагрузки.

Пулы подключения PHP-FPM

Вы можете настроить несколько конфигураций, например:

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

С помощью этого вы можете указать параметры конфигурации PHP-FPM, такие как pm.max_children, и вы также можете указать переменные окружения и установить здесь параметры имени пользователя и группы.

Балансировщик нагрузки Nginx

Если вы собираетесь получать много трафика, то вам, вероятно, захочется настроить балансировщик нагрузки для использования с настройкой php-fpm.

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

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

Примерная конфигурация будет выглядеть так. Сначала мы начинаем с модуля upstream:

Здесь каждый backend1.example.com имеет собственную конфигурацию Nginx, зеркало того, как сайт был до того, как он имел балансировщик нагрузки. Nginx будет выбирать, какой сервер использовать для каждого запроса.

Если у одного из наших бэкендов есть более быстрый жесткий диск, например SSD, или географически ближе к вашей основной пользовательской базе, вы можете установить вес так:

Кроме того, если вы считаете, что сервер может стать медленнее или вы беспокоитесь о тайм-аутах, то для этого тоже есть варианты конфигурации:

Затем нам нужно передать это серверу через прокси-сервер, используя backend upstream, который мы только что определили ранее:

Наконец, по этой теме, также для вашей справки приведено руководство nginx по обслуживанию статического содержимого и наилучшим параметрам конфигурации. Обратите внимание на использование tcp_nopush и sendfile для Mp3, например.

Миграция Apache в Nginx

Помимо чтения руководства Nginx и самостоятельного внесения изменений, вы можете использовать инструмент apache2nginx с открытым исходным кодом для перевода вашей конфигурации с Apache на Nginx.

Следуйте инструкциям по установке apache2nginx README, и после установки вы сможете перенести файлы конфигурации, просто выполнив:

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

Вывод

Для скорости и производительности Nginx является очевидным выбором вместо Apache, но это не означает, что Apache не может обрабатывать некоторый трафик. Если вы планируете перейти на первую страницу Reddit в ближайшее время, вероятно, вам стоит взглянуть на получение более эффективного решения с Nginx и PHP-FPM.

Миграция вашего WordPress в Nginx не очень сложна, и конфигурация для Nginx, очень проста и удобна в доступе по сравнению с Apache.

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

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

В будущем, возможно, больше хостов примет инструменты Nginx cPanel, такие как Engintron, которые также предоставляют Nginx для cPanel.

На данный момент, если вы хотите переключиться на WordPress с поддержкой Nginx, вам нужно будет настроить Linux VPN на DigitalOcean, AWS или на другом хостинг-провайдере.

Источник

Разница между nginx и apache с примерами

Во время собеседований на роль linux/unix администратора во многих IT-компаниях спрашивают, что такое load average, чем nginx отличается от apache httpd и что такое fork. В этой статье я постараюсь объяснить, что рассчитывают услышать в ответ на эти вопросы, и почему.

Здесь важно очень хорошо понимать основы администрирования. В идеальной ситуации при постановке задачи системному администратору выставляют ряд требований. Если же ситуация не идеальная, то, по сути, требование к администратору одно: «Хочу, чтобы всё работало». Иными словами, сервис должен быть доступен 24/7 и, если какое-то решение не удовлетворяет этим требованиям (масштабирование и отказоустойчивость относятся к доступности), то можно сказать, что администратор плохо сделал свою работу. Но если разные решения двух администраторов работают 24/7, как понять, какое из них лучше?

Хороший системный администратор при выборе решения при заданных требованиях ориентируется на два условия: минимальное потребление ресурсов и их сбалансированное распределение.

Вариант, когда одному специалисту нужно 10 серверов для выполнения задания, а второму всего 2, мы рассматривать не будем, что тут лучше – очевидно. Далее под ресурсами я буду понимать ЦПУ (cpu), ОЗУ (ram) и диск (hdd).

Давайте рассмотрим ситуацию: один администратор создал решение, которое требует 10% cpu, 5% ram и 10% hdd от всего вашего оборудования, а второй использовал для этого 1% cpu, 40% ram и 20% hdd. Какое из этих решений лучше? Тут все становится уже не так очевидно. Поэтому хороший администратор всегда должен уметь грамотно подобрать решение, исходя из имеющихся ресурсов.

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

До разработки приложения нужно вспомнить, какие средства нам предоставляет операционная система Linux (далее в статье все примеры только на основе этой ОС). В Linux у нас есть набор системных вызовов (т.е. функций в ядре ОС, которые мы можем вызвать напрямую из нашей программы, тем самым принудительно отдавая процессорное время ядру):

1) socket — выделяет место в буфере ядра ОС под наш сокет. Адрес выделенного места возвращается из функции в программу;
2) bind — позволяет менять информацию в структуре сокета, которую нам выделила ОС linux по команде socket;
3) listen – так же как и bind меняет данные в нашей структуре, позволяя указывать ОС, что мы хотим принимать подключения по этому сокету;
4) connect – говорит нашей ОС, что она должна подключиться к другому удаленному сокету;
5) accept – говорит нашей ОС, что мы хотим принять новое подключение от другого сокета;
6) read – мы просим ОС выдать нам из своего буфера определенное количество байт, которое она получила от удаленного сокета;
7) write – мы просим ОС послать определенное количество байт на удаленный сокет.

Для того, чтобы установить соединение, нам нужно создать сокет в памяти linux, прописать в нем нужные данные и выполнить подключение к удаленной стороне.

socket → bind → connect → read/write

Но если вы доверяете ОС сделать выбор исходящего порта за вас (а так же и ip адреса), то bind делать необязательно:

socket → connect → read/write

Для того, чтобы принимать входящие сообщения, нам нужно выполнить:

socket → bind → listen → accept → read/write

Теперь мы знаем достаточно для того, чтобы написать программу. Приступаем непосредственно к написанию, используя си. Почему си? Потому что в этом языке команды называются так же, как системные вызовы (за редким исключением, типа fork).

Компилируем и запускаем наш демон:

Смотрим, что получилось:

Процесс находится в состоянии sleep (S+ в команде ps).

Эта программа продолжит выполняться (получит процессорное время) только при появлении нового коннекта на порт 2222. Во всех остальных случаях программа никогда не получит процессорное время: она даже не будет требовать его от ОС и, следовательно, не будет влиять на load avarage (далее LA), потребляя только память.

С другой консоли запускаем первого клиента:

Открываем второе соединение:

По содержимому файла видно, что пришло только первое сообщение от первого клиента. Но при этом второе сообщение мы уже отправили, и оно где-то находится. Все сетевые подключения осуществляет ОС, значит и сообщение test client 2 сейчас в буфере операционной системы, в памяти, которая нам недоступна. Единственный способ забрать эти данные – обработать новое соединение командой accept, затем вызвать read.

Попробуем что-нибудь написать в первом клиенте:

Новое сообщение не попало в лог. Это происходит из-за того, что мы вызываем команду read только один раз, следовательно, в лог попадает только первое сообщение.

Попробуем закрыть наше первое соединение:

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

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

Программа не сильно отличается от предыдущей. Мы добавили еще один цикл перед командой read для того, чтобы забирать данные из сокета до тех пор, пока они туда поступают. Проверяем.

Компилируем и запускаем:

Проверяем, что получилось:

На этот раз все хорошо, мы забрали все данные, но проблема осталась: два соединения обрабатываются последовательно, по очереди, а это не подходит под наши требования. Если мы закроем первое соединение (ctrl + ]), то данные из второго соединения попадут сразу в лог:

Данные пришли. Но как обработать два соединения параллельно? Тут нам на помощь приходит команда fork. Что делает системный вызов fork в linux? Правильный ответ на этот вопрос на любом собеседовании – ничего. Fork – устаревший вызов, и в linux присутствует только для обратной совместимости. На самом деле, вызывая команду fork, вы вызываете системный вызов clone. Функция clone создает копию процесса и ставит оба процесса в очередь на процессор. Разница между ними в том, что fork копирует данные (переменные, буферы и т.п.) сразу в область памяти дочернего процесса, а clone копирует данные в дочерний процесс только при попытке их изменить (смотрите ограничения прав доступа к памяти в MMU). То есть, если вы вызываете fork 10 раз, а данные используете только для чтения, то вы получите 10 одинаковых копий данных в памяти. И это явно не то, что вам нужно, особенно в мультитредовых приложениях. Clone запускает копию вашего приложения, но не копирует данные сразу. Если вы запустите clone 10 раз, то у вас будет 10 исполняемых процессов с одним блоком памяти, и память будет копироваться только при попытке ее изменить дочерним процессом. Согласитесь, второй алгоритм намного эффективней.

В этой программе все то же самое — мы делаем accept, принимаем новое соединение. Далее мы запускаем fork. И если это мастер процесс (fork вернул pid созданного процесса), то мы закрываем текущее соединение в родительском процессе (оно доступно и в родителе, и в дочернем процессе). Если это дочерний процесс (fork вернул 0), то мы начинаем делать read с открытого сокета, который мы открыли командой accept в родительском процессе. По факту получается, что родительский процесс у нас только принимает соединения, а read/write мы делаем в дочерних процессах.

Компилируем и запускаем:

Очищаем наш лог файл:

Мы не закрываем оба соединения и можем туда еще что-то дописывать, смотрим наш лог:

Два соединения обрабатываются одновременно — мы получили желаемый результат.

Программа работает, но недостаточно быстро. Она сначала принимает соединение, а только потом запускает команду fork, и соединение обрабатывает только один процесс. Возникает вопрос: могут ли несколько процессов в ОС Linux работать с одним и тем же tcp портом? Пробуем.

Как видите, программа все еще не сильно изменилась, мы просто запускаем fork по циклу. В данном случае мы создаем два дочерних процесса, а только потом в каждом из них делаем accept на прием нового соединения. Проверяем.

Компилируем и запускаем:

Смотрим, что у нас в процессах:

Мы еще не подключились ни одним клиентом, а программа уже два раза сделала fork. Что же сейчас происходит с системой? Для начала мастер процесс: он находится в замкнутом цикле и проверяет, надо ли форкать еще процессы. Если мы будем делать это без остановки, то, по сути, будем постоянно требовать от ОС процессорное время, так как наш цикл должен исполняться всегда. Это значит, что мы потребляем 100% одного ядра – в команде ps значение 98.0%. Это же можно увидеть в команде top:

Если мы подключимся командой strace к родителю, то ничего не увидим, так как наш процесс не вызывает никакие функции ядра:

Что делают дочерние процессы? Тут начинается самое интересное. Судя по коду, все они после форка должны висеть в состоянии accept и ожидать новых соединений с одного и того же порта, в нашем случае 2222. Проверяем:

На данный момент они не требуют от ОС процессорного времени и потребляют только память. Но вот в чем вопрос: кто из них примет мое соединение, если я сделаю telnet? Проверяем:

Мы видим, что процесс, который был создан раньше (с меньшим pid), обработал соединение первым, и теперь находится в состоянии read. Если мы запустим второй telnet, то наше соединение обработает следующий процесс. После того, как мы закончили работать с сокетом, мы можем его закрыть и перейти снова в состояние accept (я этого делать не стал, чтобы не усложнять программу).

Остается последний вопрос: что нам делать с родительским процессом, чтобы он не потреблял столько cpu и при этом продолжал работать? Нам нужно отдать время другим процессам в добровольном порядке, то есть «сказать» нашей ОС, что какое-то время cpu нам не нужно. Для этой задачи подойдет команда sleep 1: если вы ее раскомментируете, то увидите в strace примерно такую, повторяющуюся раз в секунду, картину:

Наш процесс будет получать процессор примерно раз в секунду или, по крайней мере, требовать его от ОС.

Если вы всё еще не понимаете, к чему эта длинная статья, то посмотрите на apache httpd работающий в режиме prefork:

Дочерние процессы в accept:

Мастер процесс с секундной паузой:

При старте httpd мастер процесс плодит дочерние процессы, это легко увидеть если запустить strace на мастер процесс в момент старта:
Запустим веб сервер с такими настройками:

Эти настройки говорят о том, что каждый дочерний процесс будет обрабатывать только один запрос, затем процесс будет убиваться. Минимальное количество процессов в accept равно 9 и максимальное равно 10.

Если запустить strace на мастер процесс в момент старта, то мы увидим как мастер вызывает clone до тех пор, пока не достигнет MinSpareServers.

rt_sigaction(SIGSEGV, <0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGBUS, <0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGABRT, <0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGILL, <0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGFPE, <0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGTERM, <0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGWINCH, <0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGINT, <0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGXCPU, , NULL, 8) = 0
rt_sigaction(SIGXFSZ, , NULL, 8) = 0
rt_sigaction(SIGPIPE, , NULL, 8) = 0
rt_sigaction(SIGHUP, <0x7f999193de80, [HUP USR1], SA_RESTORER, 0x7f99901dd500>, NULL, 8) = 0
rt_sigaction(SIGUSR1, <0x7f999193de80, [HUP USR1], SA_RESTORER, 0x7f99901dd500>, NULL, 8) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13098
write(2, «[Wed Jan 25 13:24:39 2017] [noti». 114) = 114
wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
select(0, NULL, NULL, NULL, <1, 0>) = 0 (Timeout)
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13099
wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
select(0, NULL, NULL, NULL, <1, 0>) = 0 (Timeout)
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13100
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13101
wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
select(0, NULL, NULL, NULL, <1, 0>) = 0 (Timeout)
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13102
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13103
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13104
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13105
wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
select(0, NULL, NULL, NULL, <1, 0>) = 0 (Timeout)
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13106
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13107
wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
select(0, NULL, NULL, NULL, <1, 0>) = 0 (Timeout)

Смотрим как стартует апач – для этого можно просто смотреть ps axuf | grep [h]ttp каждую секунду, сразу после старта.

[root@www /]# date; ps axuf | grep [h]ttp
Wed Jan 25 14:12:10 EST 2017
root 13342 2.5 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd

[root@www /]# date; ps axuf | grep [h]ttp
Wed Jan 25 14:12:11 EST 2017
root 13342 1.6 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd

[root@www /]# date; ps axuf | grep [h]ttp
Wed Jan 25 14:12:11 EST 2017
root 13342 2.0 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd

[root@www /]# date; ps axuf | grep [h]ttp
Wed Jan 25 14:12:12 EST 2017
root 13342 1.7 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13357 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13358 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13359 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13360 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd

[root@www /]# date; ps axuf | grep [h]ttp
Wed Jan 25 14:12:13 EST 2017
root 13342 1.4 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13357 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13358 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13359 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13360 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13364 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
apache 13365 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
[root@www /]#

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

Апач нам ответил 403, смотрим процессы:

Как видим, процесс с минимальным pid обработал запрос и завершил свою работу:

Дочерних процессов у нас осталось 9, что вписывается в наш лимит MinSpareServers.

Пробуем опять отправить запрос:

На этот раз наш запрос обработал процесс

так как теперь у него минимальный pid.

Но у нас осталось 8 свободных дочерних процессов в accept, одного не хватает до MinSpareServers, поэтому мастер процесс нам создал новый процесс:

Давайте скажем нашей ОС, чтобы она не давала процессорное время мастер процессу апача:

Статус процесса изменился, теперь он не работает.

Проверяем, работает ли у нас веб сервер:

О да, все еще работает, веб сервер еще отвечает.

Смотрим что у нас с процессами:

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

Естественно дочерних процессов у нас осталось 8, так как новый 9й плодить некому, мастер остановлен.

Давайте для эксперимента отправим еще один http запрос:

Логично, что ситуация повторяется.

Давайте скажем нашей ОС, что мастер процесс может снова продолжить работу:

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

Как устроен nginx? Как вы уже поняли, системный вызов accept блокирует выполнение нашей программы до тех пор, пока не придет новое соединение. Получается, что мы не можем ожидать новое соединение и обрабатывать уже открытое соединение в одном процессе. Или?

Этот код выглядит чуть сложнее, чем предыдущие, но его довольно легко объяснить. Допустим, в процессе нужно обрабатывать максимум 30 соединений. Мы создаем массив из нулей. Как только к нам придет новое соединение, мы его обрабатываем, а адрес сокета записываем в этот массив. Перебирая весь массив и все наши сокеты, мы можем последовательно считывать с них информацию. Но как нам узнать о новом соединении без использования вызова accept? В linux для этого есть как минимум 3 функции: select, poll и epoll. А в freebsd для этого есть аналог функции epoll под названием kqueue (kernel queue). Что делают эти команды? select – самая старая функция, которая до сих пор используется для того, чтобы отдавать всё процессорное время ядру, запрашивая его только при определенных условиях (по аналогии с accept). Разница в том, что ядро вернет нам cpu, когда на указанных нами сокетах начнется любая активность. Так как при запуске программы открыт только один сокет, то и в select мы указываем один. Если мы подключимся телнетом к нашему демону, то в select мы должны указывать уже два сокета: мастер сокет на порт 2222 и тот, который к нам подключился. Чтобы было понятней, продемонстрирую:

В этот момент мы с другой консоли делаем telnet на порт 2222 в наш демон и смотрим на трейс:

Сначала команде select мы указывали сокет 4 (смотрите в квадратных скобках). По /proc мы узнали, что 4й файл-дескриптор — это сокет с номером 42651147. По netstat мы узнали, что сокет с таким номером — это наш сокет в состоянии listen порта 2222. Как только мы подключились к этому сокету, ОС произвела tcp handshake с нашим telnet клиентом и установила новое соединение, о чем известила приложение через select. Наша программа получила процессорное время и начала обрабатывать пустой массив с соединениями. Увидев, что это новое соединение, мы запустили команду accept, зная, что она точно не заблокирует выполнение программы, так как соединение уже присутствует. То есть фактически мы используем тот же accept, только в неблокирующем режиме.

После того, как мы выполнили соединение, мы снова отдали управление ядру linux, но сказали ему, что теперь мы хотим получать уведомление по двум сокетам — под номером 4 и 5, что очень хорошо видно в команде strace ([4 5]). Именно так работает nginx: он способен обрабатывать большое количество сокетов одним процессом. По существующим сокетам мы можем проводить операции read/write, по новым можем вызывать accept. Select — очень старый системный вызов, имеющий ряд ограничений: например, на максимальное количество коннектов (файл дескрипторов). Ему на смену пришел сначала более совершенный системный вызов poll, лишенный этих лимитов и работающий быстрее. Впоследствии появились epoll и kqueue (в freebsd). Более современные функции позволяют более эффективно работать с коннектами.

Какие из этих функций поддерживает nginx? Nginx умеет работать со всеми этими функциями.

Ссылка на документацию. В этой статье я не буду описывать, чем отличаются все эти функции, т.к. объем текста уже достаточно большой.

Nginx использует fork для того, чтобы создавать процессы и загружать все ядра на сервере. Но каждый отдельно взятый дочерний процесс nginx работает с множеством соединений так же, как в примере с select, только использует для этого современные функции (для linux по умолчанию это epoll). Смотрим:

Что делает родительский мастер процесс nginx?

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

Все взаимодействие между процессами nginx осуществляет через unix сокеты:

Перед тем как выбирать те или иные инструменты важно понимать, как именно они работают. Так в некоторых случаях выгоднее использовать только apache httpd без nginx – и наоборот. Но чаще всего эти продукты используются вместе, потому что распараллеливанием обработки сокетов в апаче занимается ОС (разные процессы), а распараллеливанием обработки сокетов в nginx занимается сам nginx.

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

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *