Как работает HTTP-сервер nginx::Журнал СА 10.2008
www.samag.ru
Журнал «БИТ. Бизнес&Информационные технологии»      
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
1001 и 1 книга  
19.03.2018г.
Просмотров: 6836
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 7364
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4614
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3162
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3966
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3969
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6471
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3314
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3593
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7451
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10814
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12528
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14233
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9265
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7211
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5519
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4750
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3568
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3277
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3509
Комментарии: 1
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3164
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Как работает HTTP-сервер nginx

Архив номеров / 2008 / Выпуск №10 (71) / Как работает HTTP-сервер nginx

Рубрика: Веб /  Веб

Дмитрий Васильев

Как работает HTTP-сервер nginx

Уже долгое время Apache является наиболее популярным HTTP-сервером с открытым исходным кодом. Но он может быть слишком громоздким для некоторых pадач. И здесь на сцену выходят новые игроки – легковесные, асинхронные HTTP-серверы, одним из которых является nginx.

Вот уже более восьми лет я использую HTTP-сервер Apache, и в большинстве случаев он меня во всем устраивает. Но недавно, установив его на один из небольших серверов с Ubuntu Linux, я подумал, что Apache не очень целесообразно использует ресурсы сервера. И с этой мыслью решил попробовать какой-нибудь альтернативный вариант. Я уже давно слышал о высокопроизводительных асинхронных серверах Lighttpd (произносится lighty, http://www.lighttpd.net) и nginx (произносится engine x, http://sysoev.ru/nginx), но до этого момента не использовал их на практике. Надо также заметить, что по статистике Netcraft на октябрь 2008 года Lighttpd и nginx занимают, в рейтинге соответственно, 5-е и 6-е места: http://survey.netcraft.com/Reports/200810.

Теперь, когда у меня было два варианта, оставалось самое сложное – выбрать наиболее подходящий для моего случая. Это сложный выбор, т.к. оба имеют практически одинаковые возможности (хотя nginx также может использоваться как почтовый прокси-сервер, я не учитывал это в сравнении). Оба используются на высоко посещаемых сайтах, например, YouTube использует Lighttpd, а Rambler – nginx. Оба имеют достаточно хорошую документацию, в том числе nginx имеет документацию на русском. В итоге для себя я остановился на nginx по следующим причинам:

  •  Многие источники (например, http://hostingfu.com/article/nginx-vs-lighttpd-for-a-small-vps) отмечают, что Lighttpd имеет проблемы со стабильностью и утечки памяти. Даже если эти проблемы остались в прошлом, похоже, что автор не уделял им достаточно внимания.
  •  Nginx, в отличие от Lighttpd, имеет две официальные ветки разработки (стабильную и экспериментальную), что, на мой взгляд, говорит о большей заботе автора о конечных пользователях и качестве проекта в целом.
  •  Мне хотелось иметь возможность использовать сервер с языком Python (http://www.python.org) с помощью стандартного интерфейса WSGI (http://ru.wikipedia.org/wiki/WSGI). При этом для nginx существует дополнительный модуль mod_wsgi, а в Lighttpd это можно делать только через шлюз FastCGI > WSGI.

Принципы работы

Прежде чем обратиться к рассмотрению непосредственно сервера nginx, рассмотрим, чем отличается асинхронный (событийный) подход от параллельной обработки соединений в отдельных процессах, или потоках.

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

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

 Недостатки:

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

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

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

 Недостатки:

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

Как можно заметить, оба подхода имеют свои достоинства и недостатки. Чтобы объединить достоинства и уменьшить недостатки из обоих подходов, в настоящее время для асинхронных сетевых приложений наиболее популярен гибридный подход, при котором несколько асинхронных приложений работают параллельно в отдельных процессах, или потоках. Теперь рассмотрим, как это работает в nginx.

Особенности nginx

Nginx разрабатывается Игорем Сысоевым (http://sysoev.ru) с весны 2002 года. Первая публичная версия вышла осенью 2004 года. На данный момент сервер находится в активной разработке с точки зрения функциональности, но нет никаких нареканий с точки зрения стабильности. Последняя стабильная версия на данный момент – 0.6.32 (http://sysoev.ru/nginx/nginx-0.6.32.tar.gz).

Архитектурно nginx – это асинхронный сервер, который использует один главный процесс для приема соединений и несколько рабочих процессов для их обработки. Рабочие процессы выполняются от непривилегированного пользователя. Асинхронная диспетчеризация может осуществляться как старыми вызовами select() и poll(), так и с использованием современных подходов специфичных для различных операционных систем: kqueue (для FreeBSD, начиная с версии 4.1), epoll (для Linux, начиная с версии 2.6), rt signals (для Linux, начиная с версии 2.2.19), /dev/poll (для Solaris, начиная с версии 7) и event ports (для Solaris, начиная с версии 10). Также для оптимизации производительности используются исключающие лишнее копирование данных системные вызовы sendfile(), sendfile64() или sendfilev() и сведены к минимуму операции копирования данных внутри сервера.

Далее рассмотрим, как собрать и установить сервер, и подробнее остановимся на конфигурировании некоторых сценариев работы.

Сборка и установка

Хотя nginx уже доступен в пакетах для последних версий Ubuntu Linux, я решил собирать его из исходников, потому что хотел использовать более свежую стабильную версию и модуль mod_wsgi для поддержки WSGI-протокола Python. Если вам не нужно собирать nginx с mod_wsgi, вы можете пропустить все места, где он упоминается.

Итак, для сборки нам понадобится исходный код nginx, исходный код библиотеки совместимых с Perl регулярных выражений (PCRE) и исходный код модуля mod_wsgi. Здесь мы используем самые последние, на данный момент, версии mod_wsgi и библиотеки PCRE. При использовании более старых версий PCRE версия не должна быть ниже 4.4:

$ wget http://sysoev.ru/nginx/nginx-0.6.32.tar.gz

$ tar -xzf nginx-0.6.32.tar.gz

$ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.8.tar.bz2

$ tar -xjf pcre-7.8.tar.bz2

$ mv pcre-7.8 pcre

$ wget -O mod_wsgi.tar.gz http://hg.mperillo.ath.cx/nginx/mod_wsgi/archive/tip.tar.gz

$ tar -xzf mod_wsgi.tar.gz

$ mv mod_wsgi-8994b058d2db mod_wsgi

Здесь я также переименовал директории для PCRE и mod_wsgi, чтобы в дальнейшем использовать для конфигурации один скрипт, не изменяя его. Автор mod_wsgi выбрал подход с применением патчей, чтобы успевать за изменениями в nginx, и поэтому мы должны приложить патч для нашей версии nginx. Запишем его как mod_wsgi_nginx-0.6.32.patch:

--- src/ngx_http_wsgi_handler.c 2008-03-26 22:35:15.000000000 +0300

+++ src/ngx_http_wsgi_handler.c 2008-10-06 16:55:07.000000000 +0400

@@ -71,7 +71,7 @@

if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_HEAD) {

/* XXX not sure */

- rc = ngx_http_discard_body(r);

+ rc = ngx_http_discard_request_body(r);

if (rc != NGX_OK && rc != NGX_AGAIN) {

return rc;

И затем приложим:

$ patch -d mod_wsgi -p0 < mod_wsgi_nginx_0.6.32.patch

Для сборки Nginx с SSL также необходимо установить библиотеку OpenSSL и для использования модуля ngx_http_gzip_module библиотеку zlib. Для сборки mod_wsgi понадобится установить пакет python-dev:

$ sudo apt-get install libssl-dev

$ sudo apt-get install zlib1g-dev

$ sudo apt-get install python-dev

$ touch nginx.sh

$ chmod a+x nginx.sh

$ vi nginx.sh

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

#! /bin/sh

./configure \

--prefix=/var/lib/nginx \

--sbin-path=/usr/sbin/nginx \

--conf-path=/etc/nginx/nginx.conf \

--pid-path=/var/run/nginx.pid \

--error-log-path=/var/log/nginx/error.log \

--http-log-path=/var/log/nginx/access.log \

--lock-path=/var/lock/nginx \

--http-client-body-temp-path=/var/lib/nginx/client_body \

--http-proxy-temp-path=/var/lib/nginx/proxy \

--http-fastcgi-temp-path=/var/lib/nginx/fastcgi \

--user=www-data \

--group=www-data \

--without-select_module \

--without-poll_module \

--without-http_ssi_module \

--without-http_geo_module \

--without-http_referer_module \

--without-http_memcached_module \

--without-http_limit_zone_module \

--without-http_empty_gif_module \

--without-http_browser_module \

--without-http_upstream_ip_hash_module \

--with-http_ssl_module \

--with-http_gzip_static_module \

--with-pcre=../pcre \

--add-module=../mod_wsgi

По умолчанию nginx устанавливается в директорию /usr/local/nginx и использует поддиректории для файлов конфигурации и различных временных файлов, но я привык придерживаться стандарта иерархии файловой системы (http://www.pathname.com/fhs), и поэтому в начале скрипта идут опции переназначения различных директорий. Затем идут опции установки пользователя и группы, под которыми будут работать рабочие процессы. В случае если данные пользователь и группа не созданы в вашей системе, их надо будет создать вручную. После этого находятся опции, включающие и отключающие различные модули, в том числе отключение поддержки системных вызовов select() и poll(), т.к. в моем случае, на Linux 2.6, будет использоваться вызов epoll(). Если вы не знаете какой системный вызов может использоваться в вашей системе, оставьте это решение скрипту конфигурации, который выберет наиболее оптимальный вариант. Соответственно если вам нужны другие пути к файлам и директориям, другой пользователь и группа, или другие модули, вы можете внести изменения в эти секции. После того как все готово со скриптом конфигурации, можно начать конфигурацию:

$ cd nginx-0.6.32

$ ../nginx.sh

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

 

Configuration summary

+ using PCRE library: ../pcre

+ using system OpenSSL library

+ md5 library is not used

+ sha1 library is not used

+ using system zlib library

 

nginx path prefix: "/var/lib/nginx"

nginx binary file: "/usr/sbin/nginx"

nginx configuration prefix: "/etc/nginx"

nginx configuration file: "/etc/nginx/nginx.conf"

nginx pid file: "/var/run/nginx.pid"

nginx error log file: "/var/log/nginx/error.log"

nginx http access log file: "/var/log/nginx/access.log"

nginx http client request body temporary files: "/var/lib/nginx/client_body"

nginx http proxy temporary files: "/var/lib/nginx/proxy"

nginx http fastcgi temporary files: "/var/lib/nginx/fastcgi"

 

Теперь можно начать компиляцию:

$ make

Если компиляция прошла успешно, устанавливаем nginx:

$ sudo make install

При установке для конфигурации выше будет создана директория /var/lib/nginx, бинарный файл сервера nginx будет установлен в директорию /usr/sbin (в случае присутствия старого файла он переименовывается в nginx.old), будет создана директория /etc/nginx, в которую будет перенесена конфигурация по умолчанию, и будут созданы директории /var/log/nginx и /var/lib/nginx с нужными правами доступа.

Запуск и управление

В простейшем случае мы можем запустить nginx следующим образом:

$ sudo /usr/sbin/nginx

После первого запуска можно зайти по адресу http://localhost/ и увидеть страницу приветствия. Для остановки сервера можно выполнить:

$ sudo killall nginx

Конечно, такой способ управления лучше всего использовать только для первого тестирования, а для обычного использования и в последующем автоматического запуска лучше написать скрипт управления и положить его в директорий /etc/init.d под именем nginx, не забывая дать права на исполнение:

#! /bin/sh

#

# /etc/init.d/nginx: start and stop nginx http server

#

 

 

PID_FILE=/var/run/nginx.pid

CAT=/bin/cat

NGINX=/usr/sbin/nginx

START_STOP_DAEMON=/sbin/start-stop-daemon

 

. /lib/lsb/init-functions

 

 

do_start()

{

$START_STOP_DAEMON --start --quiet --pidfile $PID_FILE --exec $NGINX

RETVAL=$?

 

if [ $RETVAL = 0 ]; then

log_success_msg "Server started at pid" $($CAT $PID_FILE)

elif [ $RETVAL = 1 ]; then

log_failure_msg "Server already running at pid" $($CAT $PID_FILE)

else

log_failure_msg "Error starting server"

fi

 

return $RETVAL

}

 

do_stop()

{

$START_STOP_DAEMON --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PID_FILE --exec $NGINX

RETVAL=$?

 

if [ $RETVAL = 0 ]; then

log_success_msg "Server stopped"

elif [ $RETVAL = 1 ]; then

log_failure_msg "Server already stopped"

else

log_failure_msg "Error stopping server"

fi

 

return $RETVAL

}

 

 

is_running()

{

if [ -f $PID_FILE ]; then

kill -n 0 $($CAT $PID_FILE)

if [ $? = 0 ]; then

return 1

else

return 0

fi

fi

return 0

}

 

 

case "$1" in

start)

log_begin_msg

do_start

log_end_msg $?

;;

 

stop)

log_begin_msg

do_stop

log_end_msg $?

;;

 

status)

log_begin_msg

is_running

if [ $? = 0 ]; then

log_success_msg "Server not running"

log_end_msg 1

else

log_success_msg "Server running at pid" $($CAT $PID_FILE)

log_end_msg 0

fi

;;

 

 

restart)

log_begin_msg

do_stop

if [ $? = 0 ] || [ $? = 1 ]; then

do_start

fi

log_end_msg $?

;;

 

 

reload)

log_begin_msg

is_running

if [ $? = 0 ]; then

log_failure_msg "Server not running"

log_end_msg 1

else

$NGINX -t

if [ $? = 0 ]; then

kill -HUP $($CAT $PID_FILE)

if [ $? = 0 ]; then

log_success_msg "Server configuration reloaded"

log_end_msg 0

else

log_failure_msg "Error while reloading configuration"

log_end_msg 1

fi

else

log_failure_msg "Configuration errors found"

log_end_msg 1

fi

fi

;;

 

*)

log_success_msg "Usage: /etc/init.d/nginx {start|stop|status|restart|reload}"

exit 3

;;

esac

 

exit $?

Дадим скрипту нужные права:

$ sudo chmod a+x /etc/init.d/nginx

И теперь можно управлять nginx через наш скрипт, используя команды start, stop, status, restart и reload. Чтобы nginx запускался при старте системы можно воспользоваться следующей командой:

$ sudo update-rc.d nginx defaults

Эта команда создаст ссылки на скрипт /etc/init.d/nginx в каталогах, соответствующих различным уровням запуска: /etc/rc0.d – /etc/rc6.d.

Настраиваем статический сайт

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

Вот пример основного файла конфигурации для статических сайтов:

user www-data www-data;

 

worker_processes 4;

 

error_log /var/log/nginx/error.log info;

pid /var/run/nginx.pid;

 

events {

worker_connections 1024;

}

 

http {

include /etc/nginx/mime.types;

default_type application/octet-stream;

charset utf-8;

server_tokens off;

sendfile on;

gzip on;

gzip_http_version 1.0;

gzip_comp_level 6;

gzip_proxied any;

gzip_disable "MSIE [1-6]\.(?!.*SV1)";

gzip_buffers 16 8k;

gzip_types text/plain text/html text/css

application/x-javascript text/xml application/xml

application/javascript text/js

application/xml+rss text/javascript application/atom+xml;

ssl_session_cache shared:SSL:10m;

ssl_session_timeout 10m;

 

include /etc/nginx/example.ru.conf

}

 Рассмотрим опции по порядку:

  • Опция user описывает, от имени какого пользователя и группы будут выполняться рабочие процессы.
  • Опция worker_processes определяет количество рабочих процессов. Количество рабочих процессов – параметр, который влияет на производительность и в основном зависит от ожидаемой нагрузки на сервер и требуемой функциональности сайтов. В простейшем случае может быть только один рабочий процесс, но если используется компрессия данных, или SSL, то их количество может быть равно количеству процессоров или в два раза большему числу. В данном случае я выбрал 4 рабочих процесса, т.к. пример со статическим сайтом использует и компрессию, и SSL и запускается на двухпроцессорной машине. В случае если используются не совсем свойственные nginx синхронные модули, как например mod_wsgi, нужно выбрать количество рабочих процессов в зависимости от ожидаемого количества одновременных запросов и скорости их обработки.
  • Опции error_log и pid описывают соответственно путь к файлу журнала ошибок вместе с уровнем логгинга и путь к файлу, в котором будет храниться идентификатор главного процесса сервера.
  • Секция events описывает опции, связанные с обработкой событий. Опция worker_connections описывает ограничение на количество одновременно обрабатываемых рабочими процессами соединений. Таким образом, в случае статического сайта максимальное количество одновременных соединений с сервером можно рассчитать по формуле: worker_processes * worker_connections. Также в этой секции можно выбрать метод обработки событий, например use epoll, и другие настройки, связанные с обработкой событий.
  • Секция http описывает конфигурацию HTTP-сервера и всех сайтов. Опции include и default_type описывают каталог MIME-типов и тип по умолчанию соответственно. Опция charset определяет кодировку, которая будет добавлена в заголовок ответа Content-Type. Если ее не указывать, браузеры будут использовать собственные кодировки по умолчанию как кодировку контента. Опция server_tokens управляет выводом номера версии сервера в ответах. Опция sendfile включает использование системного вызова, оптимизирующего посылку файлов. Набор опций, начинающихся на gzip, описывает параметры сжатия ответов. Набор опций, начинающихся на SSL, описывает настройки SSL-сессий. Опция include подключает другой файл конфигурации, в данном случае непосредственно конфигурацию сайта.

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

server {

listen 80;

server_name example.ru *.example.ru;

error_log /var/log/nginx/example.ru/error.log info;

access_log /var/log/nginx/example.ru/access.log;

location / {

root /home/www/example.ru/data/;

index index.html;

if ($host != "example.ru") {

rewrite ^(.*) http://example.ru$1 permanent;

}

}

}

server {

listen 443;

server_name example.ru;

error_log /var/log/nginx/example.ru/error.log info;

access_log /var/log/nginx/example.ru/access.log;

ssl on;

ssl_certificate /etc/nginx/cert/example.ru.pem;

ssl_certificate_key /etc/nginx/cert/example.ru.pem;

auth_basic "Example admin place";

auth_basic_user_file /home/www/example.ru/.htpasswd;

location / {

root /home/www/example.ru/data/admin/;

index index.html;

}

}

В данном случае файл /etc/nginx/example.ru.conf описывает две версии одного сайтаобычную HTTP-версию и HTTPS-версию, защищенную паролем. Секции server описывают конфигурацию виртуальных серверов.

Рассмотрим опции подробнее:

  • Опция listen определяет адрес и порт, на котором сервер будет принимать запросы. Здесь также можно задать дополнительные опции, управляющие приемом соединений. В том числе с помощью этой опции можно объединить конфигурацию HTTP- и HTTPS-серверов в одной секции, хотя в примере этого не сделано.
  • Опция server_name задает имя и псевдонимы сайта.
  • Опции error_log и access_log определяют путь к файлу журнала ошибок с уровнем логгирования и журналу запросов соответственно.
  • Секция location объединяет конфигурационные параметры в зависимости от URI запроса.
  • Опции root и index описывают корневую директорию сайта и имя индексного файла по умолчанию.
  • Опции if и rewrite используются для изменения URI запроса. В данном примере все запросы для других доменов перенаправляются на example.ru.
  • Опции, начинающиеся с ssl_, описывают путь к SSL-сертификату и приватному ключу соответственно.
  • Опции, начинающиеся с auth_basic, описывают текст комментария при вводе пароля и путь к файлу со списком паролей соответственно, в случае использования простой HTTP-авторизации. Файл со списком паролей может быть создан утилитой htpasswd из пакета сервера Apache. На данный момент nginx не поддерживает других методов авторизации кроме простой HTTP-авторизации.

Настраиваем HTTP-прокси

Часто HTTP-сервер является лишь посредником (прокси), стоящим перед другим HTTP-сервером. Например, такая конфигурация нужна, если один из сайтов сделан с применением технологии, которая уже имеет свой HTTP-сервер, или посредник используется как балансировщик нагрузки для нескольких стоящих за ним серверов. В nginx эта функциональность поддерживается модулем ngx_http_proxy_module.

Также с помощью модуля ngx_http_memcached_module nginx можно использовать совместно с Memcached (http://www.danga.com/memcached) для кэширования контента. Рассмотрим пример простого сайта, который перенаправляет запросы на сервер, сделанный с использованием технологии Zope 3 (http://www.zope.org). Сначала добавим следующие опции в секцию http файла /etc/nginx/nginx.conf:

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

include /etc/nginx/zope3.example.ru.conf

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

server {

listen 80;

server_name zope3.example.ru;

error_log /var/log/nginx/zope3.example.ru/error.log info;

access_log /var/log/nginx/zope3.example.zope3.ru/access.log;

error_page 502 503 504 /maintenance.html;

location /maintenance.html {

alias /home/www/zope3.example.ru/data/index.html;

}

location / {

proxy_pass http://127.0.0.1:8080/++skin++example/sites/example/++vh++http:zope3.example.ru:80/++/;

}

}

 Рассмотрим не описанные выше опции:

  • Опция error_page задает URI, который будет показываться для заданных кодов ошибок. В данном случае это ошибки, связанные с недоступностью вспомогательного сервера, или невозможностью обработать запрос.
  • Опция alias задает замену для указанного пути. Таким образом для страницы сайта /maintenance.html будет возвращено содержимое файла /home/www/zope3.example.ru/data/index.html, который может содержать страницу с описанием того, почему сервер в данный момент не доступен.
  • Опция proxy_pass задает адрес и путь на вспомогательном сервере, на который будет отображаться путь на сайте. Таким образом, в случае доступа к http://example.zope3.ru/page.html пользователю будет возвращен результат обработки запроса вспомогательным сервером по адресу http://127.0.0.1:8080/++skin++example/sites/example/++vh++http:zope3.example.ru:80/++/page.html.

Настраиваем PHP

На данный момент наиболее оптимальным способом связать nginx и PHP является протокол FastCGI. При этом PHP должен работать в отдельном процессе, что не является особой проблемой, так как PHP уже имеет собственный FastCGI-демон. Для управления демоном PHP можно использовать следующий скрипт, который в свою очередь можно сохранить как /etc/init.d/php-fastcgi и дать ему права на исполнение:

#! /bin/sh

 

EXEC_AS_USER=www-data

 

FCGI_HOST=127.0.0.1

FCGI_PORT=9000

 

PHP_FCGI_CHILDREN=5

PHP_FCGI_MAX_REQUESTS=1000

 

DAEMON=/usr/bin/php-cgi

PIDFILE=/var/run/php-fastcgi.pid

PHP_CONFIG_FILE=/etc/php5/cgi/php.ini

START_STOP_DAEMON=/sbin/start-stop-daemon

 

export PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS

DAEMON_ARGS="-q -b $FCGI_HOST:$FCGI_PORT -c $PHP_CONFIG_FILE"

 

. /lib/lsb/init-functions

 

do_start()

{

$START_STOP_DAEMON --start --quiet --pidfile $PIDFILE --exec $DAEMON --test || return 1

$START_STOP_DAEMON --start --quiet --pidfile $PIDFILE --exec $DAEMON --background --make-pidfile \

--chuid $EXEC_AS_USER --startas $DAEMON -- $DAEMON_ARGS || return 2

}

 

do_stop()

{

$START_STOP_DAEMON --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE # --name $DAEMON

RETVAL="$?"

[ "$RETVAL" = 2 ] && return 2

$START_STOP_DAEMON --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON

[ "$?" = 2 ] && return 2

rm -f $PIDFILE

return "$RETVAL"

}

 

case "$1" in

start)

log_begin_msg

do_start

log_end_msg $?

;;

stop)

log_begin_msg

do_stop

log_end_msg $?

;;

restart)

log_begin_msg

do_stop

if [ $? = 0 ] || [ $? = 1 ]; then

do_start

fi

log_end_msg $?

;;

*)

echo "Usage: php-fastcgi {start|stop|restart}"

exit 3

;;

esac

После старта демона он начнет принимать запросы по адресу 127.0.0.1:9000, и для сайта можно использовать следующий файл конфигурации:

server {

listen 80;

server_name php.example.ru;

 

error_log /var/log/nginx/php.example.ru/error.log info;

access_log /var/log/nginx/php.example.ru/access.log;

 

location / {

root /home/www/php.example.ru/data/;

index index.html;

}

 

location ~ \.php$ {

fastcgi_pass 127.0.0.1:9000;

fastcgi_index index.php;

include /etc/nginx/fastcgi_params;

fastcgi_param SCRIPT_FILENAME /home/www/php.example.ru/data$fastcgi_script_name;

}

}

 Кроме уже известных опций, здесь есть секция, которая определяет действия для всех путей, оканчивающихся на .php:

  • Опция fastcgi_pass определяет адрес FastCGI-сервера. В нашем случае это адрес, где запущен демон PHP.
  • Опция fastcgi_index задает имя индексного файла для FastCGI.
  • Опцией include мы подключаем файл с параметрами, которые будут передаваться в FastCGI-запросах. К сожалению, мы не можем один раз подключить эти параметры на более верхнем уровне, т.к. следующая опция fastcgi_param, которая в свою очередь задает еще один дополнительный параметр, отменяет все определения параметров более высокого уровня.

Настраиваем Python с WSGI

WSGI является протоколом, который связывает HTTP-сервер и приложение на Python. На данный момент уже есть большое количество серверов и приложений, работающих по этому протоколу, что позволяет использовать их как взаимозаменяемые компоненты. В примере я подключу к nginx известный трекер ошибок Trac (http://trac.edgewall.org). Прежде всего нам нужно создать файл с описанием параметров, передаваемых по WSGI. Файл можно записать как /etc/nginx/wsgi_params по аналогии с fastcgi_params:

wsgi_var REQUEST_METHOD $request_method;

wsgi_var QUERY_STRING $query_string;

 

wsgi_var CONTENT_TYPE $content_type;

wsgi_var CONTENT_LENGTH $content_length;

 

wsgi_var SERVER_NAME $server_name;

wsgi_var SERVER_PORT $server_port;

 

wsgi_var SERVER_PROTOCOL $server_protocol;

 

wsgi_var REQUEST_URI $request_uri;

wsgi_var DOCUMENT_URI $document_uri;

wsgi_var DOCUMENT_ROOT $document_root;

 

wsgi_var SERVER_SOFTWARE $nginx_version;

 

wsgi_var REMOTE_ADDR $remote_addr;

wsgi_var REMOTE_PORT $remote_port;

wsgi_var SERVER_ADDR $server_addr;

 

wsgi_var REMOTE_USER $remote_user;

После этого необходимо добавить в /etc/nginx/nginx.conf в секцию http опции:

wsgi_temp_path /var/lib/nginx/wsgi;

include /etc/nginx/wsgi_params;

Теперь сделаем WSGI-скрипт для подключения Trac и положим его как /home/www/wsgi.example.ru/wsgi.py, не забывая сделать исполняемым:

#! /usr/bin/env python2.4

 

import os

 

os.environ['TRAC_ENV'] = "/home/www/wsgi.example.ru/trac"

os.environ['PYTHON_EGG_CACHE'] = "/var/tmp"

 

import trac.web.main

application = trac.web.main.dispatch_request

И последний момент – конфигурация сайта:

server {

listen 80;

server_name wsgi.example.ru;

 

error_log /var/log/nginx/wsgi.example.ru/error.log info;

access_log /var/log/nginx/wsgi.example.ru/access.log;

 

location / {

wsgi_pass /home/www/wsgi.example.ru/wsgi.py;

}

}

Здесь опция wsgi_pass определяет имя скрипта, который будет выполняться в рамках рабочего процесса. Соответственно, так как скрипты выполняются синхронно в рамках рабочих процессов, для оптимизации производительности сайта с WSGI, возможно, придется увеличить значение опции worker_processes в nginx.conf.

Заключение

Я постарался охватить широкий спектр вопросов, связанных с nginx. Конечно, многие детали пока остались за кадром, но о них можно прочитать на следующих сайтах: http://sysoev.ru/nginx и http://wiki.codemongers.com/Main. Надеюсь, статья помогла вам расширить кругозор и выбрать правильный HTTP-сервер, подходящий для ваших задач.

Приложение

Протокол WSGI

До определенного момента для связи веб-приложения, написанного на Python и HTTP-сервера, использовалось множество подходов. Например, это могли быть протоколы CGI и FastCGI или модуль mod_python для Apache. Также многие приложения, например Zope, использовали жестко интегрированные HTTP-серверы. Стандартный протокол WSGI (http://www.python.org/dev/peps/pep-0333) был впервые предложен в декабре 2003 года и на данный момент поддерживается подавляющим большинством серверов и веб-приложений, написанных на Python. Протокол подробно описывает порядок передачи параметров приложению, передачи ответа серверу и обработку ошибок. Кроме того, учитываются расширения, специфичные для различных серверов. Простейшее приложение с использованием WSGI может выглядеть так:

def application(environ, start_response):

status = '200 OK'

response_headers = [('Content-type','text/plain')]

start_response(status, response_headers)

return ['Hello world!\n']

Таким образом, протокол позволяет, например, начать отлаживать веб-приложение, используя стандартный пакет wsgiref (появился в Python 2.5), и затем перейти на mod_wsgi (с nginx, или Apache) или HTTP-сервер из асинхронного каркаса Twisted.


Комментарии отсутствуют

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

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru