ЛабораторияСравнение производительности Django-проектов, размещенных на виртуальном хостинге с FastCGI и WSGI

battle

Для создания работоспособного виртуального хостинга, который мог бы предоставлять клиентам возможность размещать Django-проекты, мы изучили три основных способа их размещения: с использованием mod_python web-сервера Apache2, FastCGI и mod_wsgi.

Родной модуль mod_python был отвергнут сразу, поскольку он не позволяет запускать сценарии от имени выбранного пользователя. Остальные два метода изначально казались равнопривлекательными, хотя про mod_wsgi на профессиональных форумах отзываются заметно лучше.

Установка и настройка:

Чем привлекает FastCGI? Он прост в настройке, принципы работы с ним хорошо известны и его внедрение не представляет никаких сложностей. Для нормальной работы django-приложения достаточно правильным образом сконфигурировать VirtualHost web-сервера Apache2 и написать простой сценарий запуска для FastCGI:

  #user defined
  ServerAdmin admin@django-test.locum.ru
  ServerName django-test.locum.ru
  #end
  DocumentRoot "/home/versus/projects/django-test.locum.ru"
  SuexecUserGroup versus customers
  AddType fastcgi-script .fcgi
  Alias /media/ /home/versus/projects/django-test.locum.ru/media/
  ScriptAlias / /home/versus/projects/django-test.locum.ru/django.fcgi/ 

  CustomLog "/var/log/apache2/django-test.locum.ru.custom.log" combined
  ErrorLog "/var/log/apache2/django-test.locum.ru.error.log"

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

#!/usr/bin/python
import os
import sys
from flup.server.fcgi import WSGIServer
from django.core.handlers.wsgi import WSGIHandler 

sys.path.insert(0, '/home/versus/projects/django-test.locum.ru/app/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 

WSGIServer(WSGIHandler()).run()

Основным преимуществом FastCGI является, пожалуй, возможность устанавливать переменные Django прямо в файле конфигурации Apache. Теоретически это дает возможность иметь один на всех сценарий запуска проекта. Кроме того, изменения в любом файле проекта сразу же становятся видны: какое-либо кеширование отсутствует.
Процедура запуска WSGI во многом идентична FastCGI: в систему необходимо установить соответствующий пакет с mod_wsgi и так же, как и в предыдущем случае, создать необходимые конфигурационные файлы.

  #user defined
  ServerAdmin admin@django-test.locum.ru
  ServerName django-test2.locum.ru
  #end 

  DocumentRoot "/home/versus/projects/django-test2.locum.ru"
  Alias /media/ /home/versus/projects/django-test2.locum.ru/media/ 

  WSGIDaemonProcess django-test2 user=versus group=customers threads=2
  WSGIProcessGroup django-test2 

  WSGIScriptAlias / /home/versus/projects/django-test2.locum.ru/django.wsgi 

  CustomLog "/var/log/apache2/django-test.locum.ru.custom.log" combined
  ErrorLog "/var/log/apache2/django-test.locum.ru.error.log"

Каталог, содержащий статические документы, обрабатывается непосредственно web-сервером.

#!/usr/bin/python
import os
import sys 

sys.path.insert(0, '/home/versus/projects/django-test2.locum.ru/app/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' 

import django.core.handlers.wsgi 

application = django.core.handlers.wsgi.WSGIHandler()

В этой ситуации все необходимые переменные необходимо устанавливать уже в файле сценария запуска, поэтому придется создавать отдельные файлы для каждого django-проекта. С одной стороны, это не очень хорошо — появляется дублирование и возможны проблемы с неправильной конфигурацией. С другой стороны, такой подход дает большую гибкость.
WSGI кеширует модули python, поэтому изменения в проекте вступают в силу не сразу, а только либо после перезагрузки web-сервера (что недопустимо в коммерческой эксплуатации), либо при изменении timestamp конфигурационного файла.

Тестируем производительность

Так какой же способ быстрее? Для ответа на этот вопрос мы взяли стандартное django-приложение, которое отображает всего одну страничку текста и картинку.

Тестовый Django-проект

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

#!/bin/bash 

for i in `seq 1 1000`; do
	wget -O /dev/null "http://django-test2.locum.ru/" > /dev/null 2> /dev/null
done

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

WSGI FastCGI
Количество запросов 1000 1000
Время исполнения 00:06.648 02:55.243
Системное время 00:01.484 00:01.672

WSGI — Наш выбор!Разница получилась больше, чем в 20 раз! После этого эксперимента мы однозначно выбрали mod_wsgi в качестве сервера для django-проектов. Конечно, пришлось учесть особенности такого подхода: в любой момент прямо с панели управления хостингом можно отдать команду на перезапуск сервера (touch для сценария запуска) и восстановить содержимое индивидуального сценария по умолчанию на тот случай, если пользователь случайно что-то неправильно написал.

<VirtualHost 127.0.0.1>

#user defined

ServerAdmin admin@django-test.locum.ru

ServerName django-test.locum.ru

#end

DocumentRoot «/home/versus/projects/django-test.locum.ru»

SuexecUserGroup versus customers

AddType fastcgi-script .fcgi

Alias /media/ /home/versus/projects/django-test.locum.ru/media/

ScriptAlias / /home/versus/projects/django-test.locum.ru/django.fcgi/

CustomLog «/var/log/apache2/django-test.locum.ru.custom.log» combined

ErrorLog «/var/log/apache2/django-test.locum.ru.error.log»

</VirtualHost>

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

#!/usr/bin/python

import os

import sys

from flup.server.fcgi import WSGIServer

from django.core.handlers.wsgi import WSGIHandler

sys.path.insert(0, ‘/home/versus/projects/django-test.locum.ru/app/’)

os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘settings’

WSGIServer(WSGIHandler()).run()

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

Процедура запуска WSGI во многом идентична FastCGI: в систему необходимо установить соответствующий пакет с mod_wsgi и также, как и в предыдущем случае создать необходимые конфигурационные файлы.

<VirtualHost 127.0.0.1>

#user defined

ServerAdmin admin@django-test.locum.ru

ServerName django-test2.locum.ru

#end

DocumentRoot «/home/versus/projects/django-test2.locum.ru»

Alias /media/ /home/versus/projects/django-test2.locum.ru/media/

WSGIDaemonProcess django-test2 user=versus group=customers threads=2

WSGIProcessGroup django-test2

WSGIScriptAlias / /home/versus/projects/django-test2.locum.ru/django.wsgi

CustomLog «/var/log/apache2/django-test.locum.ru.custom.log» combined

ErrorLog «/var/log/apache2/django-test.locum.ru.error.log»

</VirtualHost>

Так же, как и в предыдущем случае, каталог, содержащий статические документы, обрабатывается непосредственно web-сервером.

#!/usr/bin/python

import os

import sys

sys.path.insert(0, ‘/home/versus/projects/django-test2.locum.ru/app/’)

os.environ[‘DJANGO_SETTINGS_MODULE’] = ‘settings’

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

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

WSGI кеширует модули python, поэтому изменения в проекте вступают в силу не сразу, а только либо после перезагрузке web-сервера (что недопустимо в коммерческой эксплуатации), либо при изменении timestamp конфигурационного файла.

Тестируем производительность

Так какой же способ быстрее? Для ответа на этот вопрос мы взяли стандартное django-приложение, которое отображает всего одну страничку текста и картинку.

  1. Тест не о чем.

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

    Потом, почему для проверки fastcgi режима не используется штатный враппер вокруг флапа ./manage.py funcfcgi? Если списывать на специфичную область применения, то это никак не отражено и не прокомментировано.

    Далее, в предложенном варианте, fastcgi работает в cgi режиме, что в принципе противоречит заданному тестовому раскладу и вводит читателей (и писателя) в заблуждение.

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

    И зачем было придумывать свой велосипед со «стрелялкой» в виде wget, a не были использованы традиционные, проверенные и более точные инструменты.

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

    Так же складывает негативное впечатление о профессионализме всей компании.

    Желаю удачи, и внимательной работы над ошибками.

  2. Смирнов Роман:

    Александр, большое спасибо за профессиональный комментарий!
    Вы правы, тестируются два протокола в абсолютно конкретном, одинаковом и специфичном окружении — в том, которое установлено на конкретных серверах. Желание устроить «замануху», поверьте, было далеко не главным. Все-таки наша первоочередная задача — обеспечивать надежность и производительность технологий, которые мы предоставляем.
    При тестировании мы использовали рекомендуемые разработчиками фреймворка конфигурации FastCGI и WSGI. Вполне возможно, что при других настройках и в другом окружении есть смысл использовать что-то другое. Но, на наш взгляд, если речь идет о предоставлении услуг, то логично выбирать проверенные и стабильные варианты настройки, которые рекомендуют создатели фреймворка.
    Что касается режима работы FastCGI, то тут играет решающую роль настройка самих серверов. У нас сценарии FastCGI по ряду причин запускаются как CGI, а не через сокет, поэтому пока выбирать не приходится.
    Мы не ставили перед собой задачу всестороннего тестирования производительности django на всех программно-аппаратных конфигурациях. Есть конкретный сервер, конкретные настройки и тест, который покажет отличие одного подхода от другого. Если вы считаете, что у работы через WSGI есть недостатки перед FastCGI и последний может работать быстрее, предлагайте свои решения, мы будем признательны.

  3. Александр:

    На каких тарифных планах возможно использование django?

  4. Смирнов Роман:

    Django-приложения запускаются на всех наших тарифных планах, более подробно ознакомиться с тарифными планами вы можете кликнув по ссылке

  5. Артём:

    Почему лаборатория так давно не обновляется? Замануха, или нет, а мне было очень приятно увидеть, что на хостинге ведётся анализ работы. Отличный проект у вас, в плане удобств для разработчика.