HOWTO Высокопроизводительный сервер с PHP

Материал из Gentoo Linux Wiki

Перейти к: навигация, поиск

Содержание

[править] Преамбула

Сервер nginx — высокопроизводительный сервер, разработанный Игорем Сысоевым. В этой статье я хочу показать, как его настроить для работы с PHP под системой Gentoo.

[править] Почему не Apache?

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

Хотите доказательств? Пожалуйста!

Задача получить от браузера запрос на статический файл и отдать его. Посмотрим, как с этой задачей справляются разные серверы (Apache 2.0, Apache 2.2, nginx).

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

[править] Тестируем Apache 2.0.58-r2

Замечание: К сожалению, для чистоты эксперимента не хватает версии 1.3.37 — ее убрали из портэжэй, как устаревшую.

Для начала надобно apache установить.

# emerge apache

Затем создадим простой файл /var/www/localhost/htdocs/index.html с идиотским содержанием. Запустим сервер, (убедимся, что он отдает нужную нам белиберду с помощью какого-нибудь браузера, хоть текстового).

# /etc/init.d/apache2 start

Теперь погоняем сервер на 100 000 запросов с десятым уровнем конкуренции:

# ab2 -n 100000 -c 10 http://localhost/

 Document Path:          /
 Document Length:        11607 bytes
 Concurrency Level:      10
 Time taken for tests:   55.728441 seconds
 Complete requests:      100000
 Failed requests:        0
 Write errors:           0
 Total transferred:      1184483796 bytes
 HTML transferred:       1160781900 bytes
 Requests per second:    1794.42 [#/sec] (mean)
 Time per request:       5.573 [ms] (mean)
 Time per request:       0.557 [ms] (mean, across all concurrent requests)
 Transfer rate:          20756.40 [Kbytes/sec] received

Все запросы были без ошибок обработаны, производительность сервера составляет 1794 запроса в секунду.

[править] Тестируем Apache 2.2.4-r12

Вероятно, в Вашей системе он замаскирован, поэтому заставим систему игнорировать маску и установим апач, не забыв снести старый.

# /etc/init.d/apache2 stop
 # emerge -C apache
 # echo 'www-servers/apache' >> /etc/portage/package.keywords
 # echo 'app-admin/apache-tools' >> /etc/portage/package.keywords
 # emerge apache
 # /etc/init.d/apache2 start

Параметры теста, естественно, не меняются:

# ab2 -n 100000 -c 10 http://localhost/

 Document Path:          /
 Document Length:        11607 bytes
 Concurrency Level:      10
 Time taken for tests:   59.41774 seconds
 Complete requests:      100000
 Failed requests:        0
 Write errors:           0
 Total transferred:      1184459220 bytes
 HTML transferred:       1160758035 bytes
 Requests per second:    1693.72 [#/sec] (mean)
 Time per request:       5.904 [ms] (mean)
 Time per request:       0.590 [ms] (mean, across all concurrent requests)
 Transfer rate:          19591.18 [Kbytes/sec] received

Имеем 1694 запроса в секунду, т.е. используя apache 2.2 каждую секунду мы можем обработать на 100 запросов меньше, чем в случае с apache 2.0, а это плохо.

[править] Тестируем nginx 0.5.26

А теперь опробуем nginx с настройками по умолчанию.

Замечание: Вообще-то один параметр, возможно, понадобится подкрутить, а именно worker_connections. По умолчанию ему присвоено значение 8192 и, возможно, в логах ошибок сервера будет сообщение о том, что этот параметр превышает число активных дескрипторов файла на процесс (в моем случае 1024).

Устанавливаем nginx и оставляем дистрибутив апача, т.к. в него входит программа ab2 (в оригинале ab), с помощью которой мы тестируем наши веб-серверы.

# /etc/init.d/apache2 stop
# emerge nginx
# /etc/init.d/nginx start

Запускаем тест:

# ab2 -n 100000 -c 10 http://localhost/

 Document Path:          /
 Document Length:        11607 bytes
 Concurrency Level:      10
 Time taken for tests:   36.327400 seconds
 Complete requests:      100000
 Failed requests:        0
 Write errors:           0
 Total transferred:      1182000000 bytes
 HTML transferred:       1160700000 bytes
 Requests per second:    2752.74 [#/sec] (mean)
 Time per request:       3.633 [ms] (mean)
 Time per request:       0.363 [ms] (mean, across all concurrent requests)
 Transfer rate:          31774.80 [Kbytes/sec] received

Производительность — 2753 запроса в секунду. На тысячу запросов больше, чем у apache-2.0.58. Ну хорошо, на 959. И это без всяких оптимизирующих настроек, вроде кэширования файлов в memcached во имя сокращения дисковых операций. И это на виртуальной машине под Pentium 4 3.0 GHz и памятью 512 мегабайт (на хост-машине винда и два гига памяти). Короче, надеюсь, что убедил в скорости nginx.

[править] Рассказ о nginx

Подробности о работе этого сервера на конференции РИТ рассказал сам Игорь Сысоев и есть видео (с омерзительным звуком), выложенное на сайте РИТ.

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

[править] Установка nginx

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

  • Внешняя динамика
  • Проксирование
  • FastCGI

[править] Внешняя динамика

Фактически это статика, основанная на публикации. Есть некоторая CMS, работающая с некоторой СУБД, с которой работают конечные пользователи (редакторы, оптимизаторы и др.). Есть система публикации, которая на основе информации из этой СУБД генерирует дерево файлов. В этом случае мы получаем самый быстрый в мире сайт, причем, чем чище и аккуратнее верстка, тем сайт быстрее. Так же, чем мощнее железо, тем сайт быстрее. Если использовать кэширование memcached, сайт еще быстрее. Чем больше памяти, тем больше можно закэшировать, тем еще быстрее. Однако, динамики нет, хоть контент создается динамически — мы не можем себе позволить блог или форум, используя такой метод. Про порталы я вообще молчу.

[править] Проксирование

Какой бы навороченный сайт не был, в нем всегда найдется место для статических (чуть не написал переменных) файлов. Изображения, видеоролики, аудиозаписи, файл robots.txt — все это статика. И даже если мы храним изначально какие-нибудь картинки в базе данных, грех их не кэшировать на диске (и в памяти, если она того позволяет). Вот для всей этой статики подойдет nginx. Определите пути, где вы храните статику и расскажите об этом nginx'у.

Предыдущий абзац был практическим советом. Что такое проксирование, я рассказывать не буду. Не буду так же рассказывать, как его организовывать с помощью nginx — во-первых, это просто, а во-вторых, об этом хорошо написано в документации. Вкратце: внутри контейнера server создаете контейнер location, задаете путь или регулярное выражение для запрашиваемого URL и описываете IP-адрес и порт сервера, который готов обработать запросы. Так же можно отправлять серверу какие-либо заголовки.

В nginx есть возможность делать ветвление запросов, например:

  • найти файл на диске
  • если файл на диске не найден, перенаправить запрос на сервер А
  • если сервер А вернул ошибку, перенаправить запрос на сервер Б
  • ...
  • если ничего не помогает, вернуть ошибку

[править] FastCGI

Для поддержки FastCGI необходимо пересобрать nginx с опцией fastcgi:

# USE="fastcgi" emerge nginx

или, чтобы emerge правильно обрабатывал опцию --newuse:

# echo 'www-servers/nginx fastcgi' >> /etc/portage/package.use
 # emerge nginx

Что такое FastCGI вообще, я объяснять не буду — это уже объяснено. Тонкости настройки FastCGI под nginx так же хорошо документированы.

[править] Установка самого свежего nginx

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

# mkdir /usr/local/portage
 # mkdir /usr/local/portage/www-servers
 # mkdir /usr/local/portage/www-servers/nginx
 # mkdir /usr/local/portage/www-servers/nginx/files
 # cp /usr/portage/www-servers/nginx/* /usr/local/portage/www-servers/nginx/
 # cp /usr/portage/www-severs/nginx/files/* /usr/local/portage/www-servers/nginx/files/
 # echo PORTDIR_OVERLAY = '/usr/local/portage' >> /etc/make.conf
 # cd /usr/local/portage/www-servers/nginx

Для экономии времени предлагаю воспользоваться самым свежим ебилдом (в моем случае nginx-0.6.8.ebuild) и скопировать его содержимое в новый файл с именем последней версией с сайта http://sysoev.ru/ (в моем случае nginx-0.6.9.build)

# cp nginx-0.6.8.ebuild nginx-0.6.9.ebuild

Внимательно изучив ебилд и параметры конфигурации nginx, я пришел к выводу, что наш новый ебилд редактировать не надо вообще! Эта команда скачает дистрибутив (который на данный момент весит меньше, чем 500К), вычислит его сумму и запишет эту информацию в файл Manifest.

# ebuild nginx-0.6.9.ebuild digest
 # emerge -pv nginx

 These are the packages that would be merged, in order:

 Calculating dependencies... done!

 [ebuild  N    ] www-servers/nginx-0.6.9  USE="pcre perl zlib -debug -fastcgi -flv -imap -ssl -status -webdav" 0 kB [1]

 Total: 1 package (1 new), Size of downloads: 0 kB
 Portage overlays:
   [1] /usr/local/portage

Вот мы и рассказали emerge, как устанавливать nginx самой свежей версии. Проверим, как он это понял и заодно добавим поддержку модулей fastcgi, status и flv (если вам не нужно flv вещать, я не настаиваю на flv):

# echo 'www-servers/nginx fastcgi status flv' >> /etc/portage/package.use
 # emerge nginx
 # /etc/init.d/nginx start

У меня все заработало без проблем. А у вас?

[править] Установка PHP

[править] PHP и FastCGI

Есть три пути работы PHP в режиме FastCGI:

  • Тупо
  • Используя замечательную программу spawn-fcgi, поставляемую вместе с сервером lighthttpd
  • Используя более замечательный патч php-fpm

Рассмотрим все три случая.

Замечание: В любом случае PHP надо собрать с поддержкой CGI и добавить параметр force-cgi-redirect. Ну и другие вещи, которые вам понадобятся. Спешу заметить, что ненужные вещи лучше не собирать. Мне например абсолютно не нужна поддержка spl, berkdb, gdbm, ncurses, readline, reflection и проч.

# echo 'dev-lang/php -berkdb -gdbm -ncurses -readline -reflection -spl cgi force-cgi-redirect' >> /etc/portage/package.use

[править] Демонизация PHP (тупой способ использования FastCGI)

Соберем PHP.

# emerge php

После сборки у вас появится файл php-cgi. Запустите его. Никаких ошибок нет? Ничего не пишет? Значит, работает. Нажмите <Ctrl>+<C>, чтобы завершить процесс. Демонизируется PHP с помощью параметра -b:

# php-cgi -b 127.0.0.1:9000

Эта команда запускает встроенный FastCGI сервер PHP, слушающий соединения на интерфейсе 127.0.0.1 и порте 9000. Ничего сверхъестественного. Здесь более подробно описан процесс демонизации PHP, однако в скрипте для запуска, который приводит автор, есть дефект: зачем-то добавлен параметр -q, заставляющий PHP работать в тихом режиме, т.е. не отсылать заголовки. Используя этот параметр про функцию header() можете забыть. Доказательство:

 localhost portage # echo "<?header('Location: yo')?>" | php-cgi
 Status: 302
 X-Powered-By: PHP/5.2.4-pl2-gentoo
 Location: yo
 Content-type: text/html

 localhost portage # echo "<?header('Location: yo')?>" | php-cgi -q
 localhost portage #

Плюсы и минусы этого подхода описаны здесь в колонке php "out of the box"

[править] Использование утилиты spawn-fcgi

Чтобы использовать утилиту spawn-fcgi, нам придется установить сервер lighthttpd с поддержкой FastCGI:

# echo 'www-servers/lighttpd fastcgi' >> /etc/portage/package.use
 # emerge lighttpd

Отредактируйте файл /etc/conf.d/spawn-fcgi под свои нужды — там каждая строчка ясна и прокомментирована — и запустите этот процесс.

# /etc/init.d/spawn-fcgi start
 # ps ax | grep php-cgi
 18322 ?        Ss     0:00 /usr/bin/php-cgi
 18323 ?        S      0:00 /usr/bin/php-cgi
 18324 ?        S      0:00 /usr/bin/php-cgi
 18325 ?        S      0:00 /usr/bin/php-cgi
 18326 ?        S      0:00 /usr/bin/php-cgi
 18327 ?        S      0:00 /usr/bin/php-cgi

Более подробное описание утилиты spawn-fcgi вы найдете здесь. Плюсы и минусы там же в колонке spawn-fcgi + spawn-php.sh + daemontools.

[править] Гвоздь программы — патч php-fpm

Сначала его преимущества в колонке php-fpm. Как видите, довольно много плюсов. Только вот мэйнтейнеры об этом патче мало что знают, поэтому придется опять писать свой ебилд, прости Господи!

Замечание: На момент создания этой статьи PHP версии 5.2.4 официально еще не вышел, однако ебилд для него уже есть и он не замаскирован! Считаю это недоразумением и буду использовать PHP версии 5.2.3.

Замаскируем еще невыпущенную версию PHP (в данный момент у них после версии написано _pre):

# echo '>=dev-lang/php-5.2.4_pre' >> /etc/portage/package.mask

Убедимся, что emerge нас понял и будет ставить, если потребуют, нужную нам версию:

# emerge -pv php
 These are the packages that would be merged, in order:

 Calculating dependencies... done!
 [ebuild  N    ] dev-lang/php-5.2.3-r3

Теперь можно всячески издеваться над ебилдом, но не забываем создать оверлей:

# mkdir /usr/local/portage/dev-lang
 # mkdir /usr/local/portage/dev-lang/php
 # mkdir /usr/local/portage/dev-lang/php/files
 # cp /usr/portage/dev-lang/php/* /usr/local/portage/dev-lang/php/
 # cp /usr/portage/dev-lang/php/files/* /usr/local/portage/dev-lang/php/files/
 # cd /usr/local/portage/dev-lang/php

To be continued...

Личные инструменты