About Blog Dev | Alfa Romeo SZ Conkeror wishlist

All articles, tagged with “wsgi”

WSGI серверы кратко

За последние несколько дней обнаружилась (для меня) уйма интересных WSGI серверов. Я уже довольно давно использую (естественно, для Джанги) Apache mod_wsgi для продакшена и CherryPy’евский WSGI-сервер для разработки. Но недавно обнаруженный fapws2 заинтересовал меня и я наконец-то собрался его скомпилировать (основная загвоздка была в необходимости обновления libevent), потом моё внимание обратили на cogen, и вот сегодня уже — на spawning.

И я решил взять и погонять всех сразу apachebenchmark’ом. Тестировал просто — “ab -c 50 -n 500”, ничего особенно не тюнинговал, тестирование на абсолютную объективность и точность не претендует. Всех конкурентов запускал так, чтоб они могли скушать оба ядра процессора (иначе это было бы не спортивно со стороны Spawning’а, который запускает несколько процессов и может использовать все ядра).

Итак, протестированные герои:

  • Apache2 mod_wsgi 2.0 daemon mode
  • Twisted
  • CherryPy
  • Spawning
  • Cogen
  • Fapws2

Каждый из них работает как веб-сервер для джанги с byteflow (в качестве БД использован дамп этого самого блога). Каждый запущен в двух экземплярах, сидит за nginx’ом, исключая Spawning, у которого запущено два процесса и сидит он сам.

Вот результаты.

Лидеры — fapws2 и совсем немножечко медленее — cogen. На погрешность я бы не списывал, потому что два дня назад такая же ситуация была, и при каких условиях ни тестирую — fapws2 самую чуточку быстрее. Что характерно для лидеров — у них даже самые долгие запросы в 2 секунды укладываются, не то, что у других.

Аутсайдеры — CherryPy со своими 5,5 секундами на самом длинном запросе и Spawning, который так хвалили, со своими 4 секундами на длинный запрос и 80 Мб скушанного ОЗУ — это против 32 у фапвса и 40 у когена!

Про Твистед и Апач можно сказать, что Твистед в принципе немного быстрее, но смысла никакого использовать всё равно нету. Если хочется скорости — есть fapws2 или cogen, если хочется огромного количества фич — есть Апач, который почти всегда есть… В общем, не вижу смысла.

Между cogen и fapws2 тоже можно выбрать: cogen написан на чистом питоне (он использует py-epoll), а fapws2, использующий libevent, имеет внутри кусок C, и потому его необходимо компилировать (к примеру, для винды это — чистейшее мучение, на винде я бы использовал коген). Но fapws2 явно несколько меньше ОЗУ хочет, что приятно в стеснённых условиях VPS, ну и немножечко, но быстрее. ;-)

Так что буду я, похоже, на fapws2 переползать. Тем более у моего VPS целых 4 ядра, зря пропадают с апачем только… :-)

Django performance: Apache vs Nginx - en

Just a week ago I have compared performance and stability of nginx working with Django through mod_wsgi and fastcgi. Comparison revealed that performance with fast local DB (i.e. time of DB work is negligibly small) is almost identical and all the difference is in used resources.

Today at last I have time to look, what will be, when database is located at other computer and WiFi connection between application and DB worsening situation. :-) I.e. sense of my today’s actions is looking at situation, when DB is slow (this is interesting for me after Manlio’s commentary in previous post). Additionally I wanted to look at Apache’s behavior.

Before doing that I runned lightweight test (ab -n 100 -c 20) on Apache (with local database), which showed up that Apache don’t want to use my two cores. :-( Nor prefork, neither worker don’t used second core and time between requests was around 28 ms, which is two times to nginx’ 14 ms. Logic thoughts said that heavy-weight Apache in any case is slower than nginx — second core will not improve performance in two times (so says nginx’ 24 ms when working with one core :-).

Further PostgreSQL was launched at another laptop. Apache was tested in both versions, prefork and worker and displayed no difference, so I’ve stopped on worker.

First — ab -n 1000 -c 20:

  • Apache — ~37 ms. Very stable, difference in time between 5 runs was lesser than 1 ms.
  • nginx + mod_wsgi — ~50 ms. Expected (as Manlio said, nginx is blocked while working with application, which is blocked by request to DB).
  • nginx + fastcgi prefork — ~28 ms. I can’t believe it is so faster than Apache! :-)

Second test — ab -n 3000 -c 500 — is not very distinguished from first. Apache and fastcgi — same result, mod_wsgi raised to 55 ms.

At that moment I thought that mod_wsgi is only suited for application without database (or when delays for its work is negligibly small). But, thought over, I made knight’s move — raised number of workers in nginx. :-) With 16 workers (tested after — 8 is enough) and 500 concurrent connections delay between answers is 28 ms. Now I can believe in fastcgi result and Apache is heavy and fat, as usual. ;-) Thought, every nginx’ process, which works with Django, eats around 15 mb of RAM. However apache and fastcgi (threaded, forked) want bigger amount of memory.

Everyone can do summary for himself, the only one thing I can say unambiguously — nginx + mod_wsgi is very interesting combination.

Django performance: Apache vs Nginx

Неделю назад я сравнивал производительность и устойчивость работы nginx’а с Django с помощью mod_wsgi и fastcgi. Сравнение показало, что скорость работы при наличии быстрой локальной (читай - практически не оказывающей влияние) БД практически не отличается, отличается только количество используемых ресурсов.

А сегодня я наконец-то собрался посмотреть, что же будет, когда база данных находится на другом компе, а связь по wifi между веб-сервером и БД усугубляет проблему. :-) То есть весь смысл сегодняшних моих мучений - посмотреть на ситуацию с тормозящей базой данных (стало интересно после комментария Манлио). Заодно и хотелось посмотреть, как себя ведёт Apache.

Перед этим я таки запустил пару раз лёгкий тест (ab -n 100 -c 20) на Апач (с локальной базой данных), который показал, что апач не хочет использовать два моих ядра ни в какую. :-( Ни prefork, ни worker не использовали второе ядро и запрос в среднем занимал 28 мс, что в два раза дольше, чем nginx’овый показатель - 14 мс. Логически поразмышляв, можно понять, что тяжёлый Апач в любом случае работает медленнее nginx’а - второе ядро в два раза не ускорит (что и говорит показатель в 24 мс у nginx’а при работе с одним ядром :-).

Дальше PostgreSQL был запущен на другом ноуте. Апач я мерял как в prefork версии, так и в worker.

Первый вариант - ab -n 1000 -c 20:

  • apache - ~37 мс. Стабильно, в пределах 5 запусков разницы не было даже в миллисекунду.
  • nginx + mod_wsgi - ~50 мс. Ожидаемо.
  • nginx + fastcgi prefork - ~28 мс. В мозгу не укладывается, что оно настолько быстрее Апача! :-)

Второй вариант - при ab -n 3000 -c 500 - не слишком отличается. Апач и фастцги - такие же, мод_всги вырос до 55 мс.

В этот момент мне показалось, что mod_wsgi годится только когда нету БД (или задержками на её работу можно пренебречь). Однако, поразмыслив, я сделал ход конём - увеличил количество воркеров в нгинксе. :-) При 16 воркерах (проверено позже - 8 достаточно) и 500 одновременных запросов один отклик приходит в среднем раз в 28 мс. Теперь и результат фастцги укладывается, и апач выглядит толстым и тяжёлым, как обычно. ;-) Правда, каждый процесс nginx’а, работающий с джангой, кушает порядка 15 мегабайт. Хотя это в любом случае меньше, чем апач и fastcgi.

Выводы каждый может сделать сам для себя, но nginx + mod_wsgi однозначно - очень интересная комбинация.

Nginx + Django: mod_wsgi vs FastCGI - en

(Translation of my previous post).

Yesterday I have finally sorted out my trouble with compilation of nginx’ mod_wsgi and got it working (how much means slash in our life ;-).

Configuration to get Django application running is quite simple — django.wsgi, which is used for Apache’s mod_wsgi, fits perfectly. I’ll not describe all configuration, because code is unstable and needs testing and is’s contra-indicated to run it on production now.

Lets do the fun — testing. :-) Simple page, 15 queries (PostgreSQL on same pc), 2 workers for nginx (I have tried 3 and 4 — they both are slighty slower, for 2-4 ms). Two variants of testing queries (ab -n 1000 -c 20 and ab -n 10000 -c 500) and three variants of servers (mod_wsgi, prefork fastcgi, threaded fastcgi). Hardware (this is not so interesting, because performance is interesting only in comparison, but why not to show it?) — Core 2 Duo T7300 and 2 Gb of RAM.

First — ab -n 1000 -c 20 (around of 10-12 runs for every variant):

  • mod_wsgi takes 14.2-14.3 ms per query, quite stable performance
  • prefork fastcgi takes 12.5-16.5 ms (mostly near of 12 ms, but raises from time to time), eats bigger amount of RAM — I have an xmobar1 showing usage of RAM and mod_wsgi has a two-three percents (percent is 20 megs) lesser usage
  • threaded fastcgi takes 24-25 ms per query — it uses only one core of CPU. I have tried to get upstream working in nginx — it works, but uses only 1 process for some reason :-(

I.e. in most cases for such load FastCGI is slighty faster (and uses somewhat bigger amount of resources). But… lets go further? ;)

Second — ab -n 10000 -c 500 (here I got 3-4 runs for every variant):

  • mod_wsgi takes 13-14 ms. Pretty stable result. Each worker consumes 21/15 megs of RAM (VSZ/RSS)
  • prefork fastcgi takes 15.5-17 ms per request, but it runs from 40 to 50 serving instances, each consuming 16-20 VSZ (10-13 RSS) megs of RAM! xmobar says that usage raises up to 50% (by leaps, usually around 45-48%) — compare to 33% for mod_wsgi! Additional 300 mbytes of RAM.
  • threaded fastcgi — most “interesting” variant. With this level of concurrency it just dies. With -c 100 — dies. It lives with -c 50 with slighty lower speed than with -c 20, but process eats near of 300 mb of VSZ.

What I can say here? Lets wait for stable mod_wsgi release! :-) Thanks, Manlio, for this piece of code. :-)

1

xmobar — small statusbar, written on Haskell. Displays system state and other various information

Nginx + Django: mod_wsgi vs FastCGI

Вчера вечером таки связался с автором mod_wsgi (до этого были какие-то проблемы - он говорит, что мне отвечал, но у меня даже в спамбоксе пусто было) и скомпилировал nginx с mod_wsgi (ха-ха, как много решают слеши в нашей жизни ;-).

Запуск джанговского приложения под nginx’ом не вызвал абсолютно никаких проблем - использовался тот же файлик django.wsgi, который я приводил раньше для апача. Больше о настройке решил ничего не писать, потому как код ещё не стабильный и требует тестирования, потому использование где-то в реально жизни пока больному не показано.

Но тут начинается веселье - тестирование. ;-) Простая страничка, 15 запросов (PostgreSQL на этом же компе), инфы по этим запросам приходят мелочи (ещё хочу потестировать, чтоб было инфы побольше, а постгрес был на другом компе). 2 воркера (пробовал и 3, и 4 - выходит медленнее в любом варианте, на 2-4 мс). Два варианта запросов (ab -n 1000 -c 20 и ab -n 10000 -c 500) и три варианта серверов (mod_wsgi, prefork fastcgi, threaded fastcgi). Железо (всё равно интересно только в сравнении на одном железе и софте, потому конфигурация несущественна, но всё же) - Core 2 Duo T7300 и 2 Gb RAM.

При ab -n 1000 -c 20 (на каждый вариант сервера пришлось порядка 10-12 тестирований):

  • mod_wsgi стабильно выдаёт 14.2-14.3 мс на запрос
  • prefork fastcgi выдаёт 12.5-16.5 мс (в основном около 12, но иногда подскакивает), жрёт больше рамы - у меня xmobar1 показывает количество съеденной памяти, при mod_wsgi там на пару процентов (процент - 20 мегов) меньше всегда
  • threaded fastcgi выдаёт 24-25 мс на запрос - он использует только одно ядро, я пытался настроить в нгинксе upstream - он работает, но использует почему-то только 1 процесс

Т.е. в большинстве случаев при такой нагруженности фастцги выходит немного быстрее (хотя и кушает немножко больше ресурсов). Но… идём дальше? ;)

При ab -n 10000 -c 500 (тут вышло по 3-4 запуска):

  • mod_wsgi выдаёт 13-14 мс. Каждый воркер хавает примерно 21/15 мегов памяти (VSZ/RSS)
  • prefork fastcgi выдаёт 15.5-17 мс на запрос, но при этом запускается от 40 до 50 обслуживающих процессов, каждый из которых кушает 16-20 VSZ (10-13 RSS) мегов памяти! По xmobar’у расход выходит до 50% (скачками, обычно около 45-48) относительно 33% у wsgi. Это лишних 300 мегов оперативки!
  • threaded fastcgi - самый интересный вариант. При таком количестве одновременных запросов он умирает. При -c 100 - тоже умирает. При -c 50 - живёт, но скорость выходит чуть ниже, чем при -c 20, а рабочий процесс хавает до 300 мегов VSZ.

Что тут можно сказать? Ждём, когда mod_wsgi станет стабильным! :-)

1 -

xmobar - это такой статусбар на хаскеле, показывает состояние системы и вообще чего мне захочется

Apache + mod_wsgi + Django

Меня тут попросили описать то, как я запускаю джанговские приложения в апаче. Я решил не растягивать резину в долгий ящик и просто привести свой конфиг с комментариями. :)

<VirtualHost *>
    ServerAdmin piranha@piranha.org.ua
    ServerName piranha.org.ua
    ServerAlias www.piranha.org.ua

    # директива говорит о том, что это конкретное приложение будет исполняться
    # в процессе-демоне с названием piranha
    WSGIProcessGroup piranha
    # Собственно описание этого демона. 2 процесса, максимум 1000 запросов.
    # Сайт не нагруженный, больше и не надо. :)
    WSGIDaemonProcess piranha user=piranha group=www-data threads=2 maximum-requests=1000
    # Главная, практически, директива. Файлик с описанием приложения. См. ниже.
    WSGIScriptAlias / /home/piranha/web/byteflow/byteflow/django.wsgi

    # Решил оставить, чтоб не забывали про него. :)
    # Кеширование картинок и прочих статических файлов.
    <IfModule mod_expires.c>
        <FilesMatch "\.(jpg|gif|png|css|js)$">
            ExpiresActive on
            ExpiresDefault "access plus 3 days"
        </FilesMatch>
    </IfModule>

    # Описание расположения статических файлов.
    Alias "/admin-media/" "/usr/local/lib/python2.4/site-packages/django/contrib/admin/media/"
    <Location "/admin-media/">
        SetHandler None
    </Location>

    Alias "/media/" "/home/piranha/web/byteflow/media/"
    <Location "/media/">
        SetHandler None
    </Location>

    # Логи. ;)
    LogLevel warn
    CustomLog /home/piranha/web/logs/piranha.access.log combined
    ErrorLog /home/piranha/web/logs/piranha.error.log
</VirtualHost>

А вот тот самый файлик, в котором описывается, как запускать приложение:

import sys
import os
import os.path

sys.path.insert(0, os.path.dirname(__file__))
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

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

Кратко и незамысловато. Годится для любого проекта в силу независимости от места расположения. :)

Вот и всё. Файлик django.wsgi лежит в директории проекта, джанга лежит в пути Python‘а (у меня вот в /usr/local/, потому как последний trunk и пакета для него, естественно, нету), всё работает прекрасно.

P.S.И, естественно, апач надо релоадить (apache2ctl graceful) после изменений в конфиге или в питон-коде приложения.

Nginx и WSGI

Сегодня наткнулся на просто невероятную вещь - mod_wsgi для nginx’а. На английском упоминаний нету вообще нигде, но не сомневаюсь, что они скоро появятся. :)

UPD. Он, конечно, совсем новый и ещё не юзабельный для продакшена, но, судя по всему, пока разработчик порядочно активен - только что добавился TODO

mod_wsgi

Всё, перевёл все свои виртуалхосты, использующие питон, на mod_wsgi, который куда лучше и проще настраивается, чем mod_python.

Кроме того, он позволяет запускать процессы в таком себе daemon-режиме, благодаря чему теперь мой меркуриал запущен из-под моего юзера - а это значит, что репозитории, которые в нём лежат, одновременно и доступны для записи, и принадлежат мне (и без всяких предоставлений юзеру www-data прав на запись). Очень удобно.

Меркуриал, кстати, невероятно рулит. Позволяет через браузер ходить по репозиторию (и смотреть не только последние версии, как svn), clone/pull проходит на порядок быстрее, чем в svn’е, а скорость annotate сравнить вообще нельзя - оно же всё локально происходит. :)