Apache vs Nginx: Расставим точки над ё.
Источник: http://slonik-v-domene.livejournal.com/141951.html
Наступивший январь порадовал нас очередным сравнением теплого с мягким Apache vs Nginx как платфом для работы с PHP.
Перед тем как комментировать заметку рекомендую все же дочитать ее до конца и осилить разбор полетов. Если желания читать нет, краткая суть: автор сравнения провел тесты неверно, без понимания сути происходящего. К реальности все его выводы не имеют никакого отношения вовсе.
Теперь объяснение, почему так.
Я потрудился перепроверить полученные результаты на собственном стенде. Выбранная система - Ubuntu 12.04.3 LTS, ядро - Linux 3.8.0-29-generic x86_64. Установка проведена методом "Yes → Yes → Ok → Restart".
Из стандартных репозиториев были доустановлены пакеты:
apache2-mpm-prefork 2.2.22-1ubuntu1.4 libapache2-mod-php5 5.3.10-1ubuntu3.9 nginx-full 1.1.19-1ubuntu0.5 php5-fpm 5.3.10-1ubuntu3.9
Хотя в этом и не было никакого смысла (один-единственный отдаваемый файл и так был бы закеширован) по настоятельной просьбе был создан Ram-disk размером 64М:
mkfs -q /dev/ram1 65536 mount /dev/ram1 /opt/www/example.com
Конфигурация сервисов:
/etc/nginx/sites-available/example.com
server { listen 8080; root /opt/www/example.com/htdocs; index index.html; server_name example.com; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; } # location / # { # proxy_pass http://127.0.0.1:80/; # } }
Для тестирования nginx+Apache/mod_php использовалась закомментированная часть файла конфигурации.
/etc/php5/fpm/pool.d/www.conf
pm.max_children = 250 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 10 pm.max_requests = 0
/etc/apache2/apache2.conf
<IfModule mpm_prefork_module> StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 250 MaxRequestsPerChild 0 </IfModule>
/etc/apache2/sites-available/example.com
<VirtualHost *:80> ServerName example.com ServerAlias www.example.com DocumentRoot /opt/www/example.com/htdocs <Directory /> Options FollowSymLinks AllowOverride None </Directory> ErrorLog ${APACHE_LOG_DIR}/example.com-error.log CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined </VirtualHost>
Если вы не видите в списке значение какого-либо параметра, значит оно оставлено без изменений из конфигурации "по умолчанию".
Сам файл:
/opt/www/example.com/htdocs/index.php
<?php for($i = 0; $i < 1000; ++$i) { echo "Hello, World! $i "; }
Тесты проведены утилитой ab с различной конкурентностью. Проводилось пять замеров, два самых медленных результата отбрасывались, данные по остальным трем замерам осреднялись. Стоит отметить, что при использовании php-fpm количество переданных данных было меньше из-за разницы в количестве передаваемых данных по протоколу FastCGI. Так как разница в объеме трафика составила около 1%, этим расхождением можно смело пренебречь.
Чтобы исключить сайд-эффекты от недостатка памяти и вычислительной мощности, тестирование велось на сервере с заведомо достаточным количеством оперативной памяти и CPU.
Apache:
Total transferred: 180820000 bytes HTML transferred: 178900000 bytes
Nginx:
Total transferred: 180490000 bytes HTML transferred: 178900000 bytes
Concurrency Level: 10
Apache: 1407.41 [#/sec] Nginx/fpm-unix: 1108.12 [#/sec] Nginx/fpm: 1102.07 [#/sec] Nginx/apache: 1040.58 [#/sec]
Concurrency Level: 50
Apache: 1273.71 [#/sec] Nginx/fpm-unix: 1106.68 [#/sec] Nginx/fpm: 1083.58 [#/sec] Nginx/apache: 1009.34 [#/sec]
Concurrency Level: 100
Apache: 1288.83 [#/sec] Nginx/fpm-unix: 1095.26 [#/sec] Nginx/fpm: 1085.20 [#/sec] Nginx/apache: 989.68 [#/sec]
Concurrency Level: 200
Apache: 1054.37 [#/sec] Nginx/fpm-unix: 1045.21 [#/sec] Nginx/fpm: 993.68 [#/sec] Nginx/apache: 978.78 [#/sec]
Мы видим следующие вещи:
- при возрастании конкурентности уменьшаются как разница в результатах, так и скорость ответа
- nginx в любой конфигурации при небольшой и средней конкурентности медленнее apache/mod_php
- nginx+fpm через unix socket быстрее nginx+fpm через tcp socket
- nginx+apache/mod_php работает сопоставимо с nginx+fpm
На этом статью можно было бы закончить и дать всем желающим возможность сделать далеко идущие очевидные и при этом неправильные выводы. Тем не менее, я прокомментирую полученные результаты.
Почему так и с какой стати nginx работает медленее?
При использовании nginx+fpm мы имеем два разных сервера: nginx на порту 8080 и fpm на порту 9000. Нетрудно догадаться, что nginx работает как прокси для сервера fpm, сначала принимая запрос извне и затем отправляя его к серверу fpm по протоколу FastCGI. Если же используется apache/mod_php, запросы обрабатываются непосредственно на сервере без проксирования куда-либо.
Очевидно, что при всех тех же самых условиях двузвенная система (ab ↔ apache) будет работать быстрее чем трехзвенная (ab ↔ nginx ↔ fpm), отсюда и полученные результаты.
Если же мы используем unix socket, накладные расходы на транспортировку данных между nginx и fpm уменьшаются, причем особенно хорошо это заметно при большой конкурентности. Это и понятно - unix socket по сути - двунаправленный пайп, фактически, данные копирутся из одного буфера в другой без задействования сетевой подсистемы.
Почему при увеличении конкуренции разница уменьшается?
Потому, что становится важным тот факт что система тратит ресурсы на шедулинг процессов (и fpm и apache создают необходимое количество процессов для обработки запросов), а также то, что возрастает вычислительная нагрузка на процессор и систему виртуальной памяти - на это тоже тратятся ресурсы.
Стоит ли отказаться от Nginx-fpm в пользу Apache/mod_php?
Короткий ответ: Да. Нет. В зависимости от задач.
Длинный ответ: даже в самом простом случае кроме запуска PHP требуется отдавать и статику (html, css, js, картинки и т.п). Nginx с этой задачей справляется куда как лучше чем Apache. Кроме того, nginx в состоянии одновременно обслуживать очень большое количество подключений, что также недоступно в случае использования Apache. Поэтому роль nginx как правило заключается балансировке нагрузки, отдаче статики, проксированию запросов к PHP на внутренние сервера, а самое главное - к работе с медленными клиентами. В этом случае логично поднять php-fpm и обрабатывать запросы к php через него.
Если же требуется сложная работа с реврайтами, дополнительными модулями apache, фильтрами содержимого и подобными вещами и это требуется делать вместе с модулем php, имеет смысл поставить Apache/mod_php. При этом вы должны очень хорошо понимать, что вы делаете и какой результат хотите получить.
Выставлять ничем не прикрытый Apache в мир, прочтя англоязычную статью и захотев получить прирост 1-10% по скорости ответа - очень, очень плохая идея. Не делайте так.
Менее очевидный вывод
Apache, как парзер протокола HTTP и запускальщик модулей, написан хорошо. В нем с его архитектурой "один-процесс-на-одного-клиента" практически нечего улучшать, поэтому все его альтернативы (например, php-fpm) работают с сопоставимой скоростью. В ряде задач требуется именно такой подход (например, для обработки изображений "на лету"), поэтому Apache с соответствующим модулем - хороший и правильный выбор.
Любителям "оптимизаций"
Чудес не бывает. Все сервера с архитектурой вида "1 запрос - 1 процесс" ведут себя практически одинаково: у них сопоставимые скорости работы и примерно похожее поведение под возрастающей нагрузкой. Выбор конечного решения должен основываться не на мифическом приросте производительности в 6-10%, а прежде всего на технологическом удобстве (удобстве разработки, деплоймента, необходимости дополнительной обработки запроса и т.п.)
Обсуждение