основы работы с FastCgi
Временами программируя сайты на Python 'е, я использовал CGI и особо не задумывался о скорости выполнения приложений. Попытки добиться максимальной скорости загрузки методом оптимизации кода были практически напрасны. Предположив, что при значительной нагрузке на сайт будут ощущаться проблемы, а именно задержки, загрузка процессора, памяти и т.п., а также ознакомившись поглубже с использованием CGI (Common Gataway Interface), я решил практически отказаться от его использования.
Весь принцип CGI заключается в том, что каждый раз при обращении к скрипту происходит запуск интерпретатора, а это занимает определенное время на выполнение приложения. В поисках лучшего варианта было решено использовать более оптимальное решение типа mod_python или fastcgi. Они представляют собой приложения, которые при взаимодействии с веб-сервером запускают интерпретатор в память, и при обращении к какому-либо скрипту происходит его запуск через интерпретатор, находящийся в памяти.
Если немного углубиться в подробности, то mod_python - это модуль для веб-сервера Apache, а fastcgi - это протокол. Оба делают практически одно и то же - ускоряют выполнение скриптов на сервере, обрабатывают многочисленные запросы. Я долго выбирал, что именно установить и использовать. В итоге я решил остановить свой выбор на приложении, которое первым установится и настроится без особых мучений, что и будет отвечать предъявляемым мною требованиям.
Сначала с помощью нескольких команд был установлен модуль mod_apache, который содержит в себе python-библиотеки. Его работоспособность проверялась на стандартном примере. Однако вскоре возникли вопросы по более тонкой подстройке - крайне сложно было понять принцип работы модуля. Поиск на форумах не давал нужного результата, и в итоге модуль был удален. На смену ему пришел второй вариант - fastcgi, который и оправдал мои надежды.
Далее я опишу основные этапы установки для Linux-систем (в моем случае это был Linux Slackware 10.2). Все действия я производил на веб-сервере Apache версии 1.3.33.
С сайта www.fastcgi.com загружаются два файла - fcgi-2.4.0.tar.gz и mod_fastcgi-2.4.2.tar.gz, на момент написания статьи это были последние версии, предложенные на сайте. Вы можете установить и бинарную версию, входящую в состав вашего дистрибутива. Первый архив необходим для общей функциональности протокола, второй - для работы именно с Apache. Также на сайте имеется весьма толковый FAQ, из которого я утянул весьма хороший конфиг под веб-сервер Apache.
Архив fcgi-2.4.0.tar.gz содержит исходный код протокола, библиотеки для работы с протоколом на разных языках программирования. Среди них отсуствовал модуль для работы с Python. Вскоре выяснилось, что этих модулей очень много. Предложенные на сайте модули мне не подошли (читай - не понравились). После непродолжительных поисков лучшего варианта был выбран модуль с сайта http://svn.saddi.com/py-lib/trunk/fcgi.py. Сборка fastcgi (в нашем примере это содержимое архива fcgi-2.4.0.tar.gz)представляет собой стандартную магическую комбинацию, которая знакома каждому, кто собирал программы из исходных текстов:
./configure
make
make install
Последнее действие выполняется с привилегиями пользователя root для корректной установки приложения в систему.
Архив mod_fastcgi-2.4.2.tar.gz устанавливается по инструкции. Хотя на самом деле у меня не получилось установить этот модуль, пришлось загрузить бинарную сборку с другого источника.
Если все установлено и ошибок нет, перейдем к настройке Apache. Если вы установили бинарную сборку mod_fastcgi и/или fastcgi, то, возможно, mod_fastcgi автоматически пропишется в конфигурации веб-сервера (это могут сделать скрипты дистрибутива, Debian, например). Если этого не произошло или вы собирали из исходников – добавим нужные директивы вручную.
В главный конфигурационный файл Apache, в моем случае '/etc/apache/httpd.conf', дописываем следующее:
Include /etc/apache/mod_fastcgi.conf
Этим мы указывем "индейцу" на то, что следует обратиться к данному файлу и включить конфигурационные параметры этого файла в работу сервера. Далее пример файла mod_fastcgi.conf:
LoadModule fastcgi_module libexec/apache/mod_fastcgi.so
FastCgiIpcDir /tmp/fast
<IfModule mod_fastcgi.c>
FastCgiServer /var/www/cgi-bin/fcgi.py
<Directory /var/www/cgi-bin>
SetHandler fastcgi-script
</Directory>
</IfModule>
Основные моменты конфигурационного файла:
- LoadModule - загружает модуль mod_fastcgi;
- FastCgiIpcDir - указывает на директорию, куда fastcgi может складывать нужные ему файлы во время работы;
- FastCgiServer - загружает указанный скрипт в память изначально;
- <Directory /var/www/fcgi> - указывает на директорию, в которой находятся скрипты, которые будут загружены в память по запросу (первый запрос имеет небольшую задержку, в отличие от последующих). Необходимо чтобы Apache был сконфигурирован так, чтобы путь директории совпадал с каталогом, который указан в конфигурационном файле как DocumentRoot(например /var/www).
После всех этих действий можно попробовать запустить/перезапустить веб-сервер. Если возникнут ошибки в запуске сервера, то вам будут сообщены строки, которые необходимо будет откорректировать.
Теперь настало время испробовать в действии Fastcgi. Поместите загруженный файл fcgi.py в корневую папку, где находятся ваши скрипты. Далее поместите следующий скрипт в директорию, которая указана в конфигурационном файле (я буду указывать ее как /var/www/cgi-bin):
#!/usr/local/bin/python
from fcgi import WSGIServer
def app(environ,start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
yield 'Hello world!'
WSGIServer(app).run()
При обращении к данному скрипту произойдет следующее: fcgi загрузит в память данный скрипт, запустит его, выведет результат 'Hello World!'. Если попробовать изменить что-либо в скрипте, текст, например, то при повторном обращении ничего не произойдет, так как скрипт находится в памяти. Для того чтобы обновить результат, необходимо убрать из памяти запущенный скрипт командой killall index.py или перегрузить веб-сервер, может, есть еще какой-либо вариант, который упрощает все эти действия, но я такового не знаю.
Простое написано, теперь надо перейти к более сложному. К примеру, надо сделать что-либо динамическое. Скрипту передаем значения, скрипт их выводит.
from fcgi import WSGIServer
def func1(parametr):
return 'Scriptu peredano znachenie = %s' %parametr
def app(environ,start_response):
import cgi
string=cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,keep_blank_values=1)
start_response('200 OK', [('Content-Type', 'text/html')])
try:
env = string.keys()[0]
except:
env = 'None'
if string.has_key('func1'):
yield '%s' %func1(string['func1'].value)
elif env =='func2':
yield 'Func 2'
else:
yield 'None'
WSGIServer(app).run()
Скрипту можно передать следующее - script.py?func1=value и script.py?funс2. В результате чего первый запрос выдаст переданное значение, второй просто выведет текст. Запросы можно комбинировать в зависимости от поставленных задач, для этого нужно более подробно разобраться с возможностями cgi.FieldStorage.
На мой взгляд, с помощью основных методов работы с fastcgi, описанных мною выше, можно создать достаточно работоспособный сайт/движок для него, который будет вполне успешно работать.
Михаил Борисов aka Niro
Весь принцип CGI заключается в том, что каждый раз при обращении к скрипту происходит запуск интерпретатора, а это занимает определенное время на выполнение приложения. В поисках лучшего варианта было решено использовать более оптимальное решение типа mod_python или fastcgi. Они представляют собой приложения, которые при взаимодействии с веб-сервером запускают интерпретатор в память, и при обращении к какому-либо скрипту происходит его запуск через интерпретатор, находящийся в памяти.
Если немного углубиться в подробности, то mod_python - это модуль для веб-сервера Apache, а fastcgi - это протокол. Оба делают практически одно и то же - ускоряют выполнение скриптов на сервере, обрабатывают многочисленные запросы. Я долго выбирал, что именно установить и использовать. В итоге я решил остановить свой выбор на приложении, которое первым установится и настроится без особых мучений, что и будет отвечать предъявляемым мною требованиям.
Сначала с помощью нескольких команд был установлен модуль mod_apache, который содержит в себе python-библиотеки. Его работоспособность проверялась на стандартном примере. Однако вскоре возникли вопросы по более тонкой подстройке - крайне сложно было понять принцип работы модуля. Поиск на форумах не давал нужного результата, и в итоге модуль был удален. На смену ему пришел второй вариант - fastcgi, который и оправдал мои надежды.
Далее я опишу основные этапы установки для Linux-систем (в моем случае это был Linux Slackware 10.2). Все действия я производил на веб-сервере Apache версии 1.3.33.
С сайта www.fastcgi.com загружаются два файла - fcgi-2.4.0.tar.gz и mod_fastcgi-2.4.2.tar.gz, на момент написания статьи это были последние версии, предложенные на сайте. Вы можете установить и бинарную версию, входящую в состав вашего дистрибутива. Первый архив необходим для общей функциональности протокола, второй - для работы именно с Apache. Также на сайте имеется весьма толковый FAQ, из которого я утянул весьма хороший конфиг под веб-сервер Apache.
Архив fcgi-2.4.0.tar.gz содержит исходный код протокола, библиотеки для работы с протоколом на разных языках программирования. Среди них отсуствовал модуль для работы с Python. Вскоре выяснилось, что этих модулей очень много. Предложенные на сайте модули мне не подошли (читай - не понравились). После непродолжительных поисков лучшего варианта был выбран модуль с сайта http://svn.saddi.com/py-lib/trunk/fcgi.py. Сборка fastcgi (в нашем примере это содержимое архива fcgi-2.4.0.tar.gz)представляет собой стандартную магическую комбинацию, которая знакома каждому, кто собирал программы из исходных текстов:
./configure
make
make install
Последнее действие выполняется с привилегиями пользователя root для корректной установки приложения в систему.
Архив mod_fastcgi-2.4.2.tar.gz устанавливается по инструкции. Хотя на самом деле у меня не получилось установить этот модуль, пришлось загрузить бинарную сборку с другого источника.
Если все установлено и ошибок нет, перейдем к настройке Apache. Если вы установили бинарную сборку mod_fastcgi и/или fastcgi, то, возможно, mod_fastcgi автоматически пропишется в конфигурации веб-сервера (это могут сделать скрипты дистрибутива, Debian, например). Если этого не произошло или вы собирали из исходников – добавим нужные директивы вручную.
В главный конфигурационный файл Apache, в моем случае '/etc/apache/httpd.conf', дописываем следующее:
Include /etc/apache/mod_fastcgi.conf
Этим мы указывем "индейцу" на то, что следует обратиться к данному файлу и включить конфигурационные параметры этого файла в работу сервера. Далее пример файла mod_fastcgi.conf:
LoadModule fastcgi_module libexec/apache/mod_fastcgi.so
FastCgiIpcDir /tmp/fast
<IfModule mod_fastcgi.c>
FastCgiServer /var/www/cgi-bin/fcgi.py
<Directory /var/www/cgi-bin>
SetHandler fastcgi-script
</Directory>
</IfModule>
Основные моменты конфигурационного файла:
- LoadModule - загружает модуль mod_fastcgi;
- FastCgiIpcDir - указывает на директорию, куда fastcgi может складывать нужные ему файлы во время работы;
- FastCgiServer - загружает указанный скрипт в память изначально;
- <Directory /var/www/fcgi> - указывает на директорию, в которой находятся скрипты, которые будут загружены в память по запросу (первый запрос имеет небольшую задержку, в отличие от последующих). Необходимо чтобы Apache был сконфигурирован так, чтобы путь директории совпадал с каталогом, который указан в конфигурационном файле как DocumentRoot(например /var/www).
После всех этих действий можно попробовать запустить/перезапустить веб-сервер. Если возникнут ошибки в запуске сервера, то вам будут сообщены строки, которые необходимо будет откорректировать.
Теперь настало время испробовать в действии Fastcgi. Поместите загруженный файл fcgi.py в корневую папку, где находятся ваши скрипты. Далее поместите следующий скрипт в директорию, которая указана в конфигурационном файле (я буду указывать ее как /var/www/cgi-bin):
#!/usr/local/bin/python
from fcgi import WSGIServer
def app(environ,start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
yield 'Hello world!'
WSGIServer(app).run()
При обращении к данному скрипту произойдет следующее: fcgi загрузит в память данный скрипт, запустит его, выведет результат 'Hello World!'. Если попробовать изменить что-либо в скрипте, текст, например, то при повторном обращении ничего не произойдет, так как скрипт находится в памяти. Для того чтобы обновить результат, необходимо убрать из памяти запущенный скрипт командой killall index.py или перегрузить веб-сервер, может, есть еще какой-либо вариант, который упрощает все эти действия, но я такового не знаю.
Простое написано, теперь надо перейти к более сложному. К примеру, надо сделать что-либо динамическое. Скрипту передаем значения, скрипт их выводит.
from fcgi import WSGIServer
def func1(parametr):
return 'Scriptu peredano znachenie = %s' %parametr
def app(environ,start_response):
import cgi
string=cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ,keep_blank_values=1)
start_response('200 OK', [('Content-Type', 'text/html')])
try:
env = string.keys()[0]
except:
env = 'None'
if string.has_key('func1'):
yield '%s' %func1(string['func1'].value)
elif env =='func2':
yield 'Func 2'
else:
yield 'None'
WSGIServer(app).run()
Скрипту можно передать следующее - script.py?func1=value и script.py?funс2. В результате чего первый запрос выдаст переданное значение, второй просто выведет текст. Запросы можно комбинировать в зависимости от поставленных задач, для этого нужно более подробно разобраться с возможностями cgi.FieldStorage.
На мой взгляд, с помощью основных методов работы с fastcgi, описанных мною выше, можно создать достаточно работоспособный сайт/движок для него, который будет вполне успешно работать.
Михаил Борисов aka Niro
Сетевые решения. Статья была опубликована в номере 03 за 2007 год в рубрике sysadmin