About Blog Dev | Alfa Romeo SZ Conkeror wishlist

Archive for December, 2007

OpenID refactoring

Хорошие новости - я порядочно переделал механизм работы с опенидом в блоге. Правда, сами внутренности openidconsumer почти не подверглись издевательствам, изменения прошли в основном в коде работы с пользователем. Но зато для пользователей поменялось всё порядочно.

Во-первых, теперь после попытки логина с неизвестным блогу OpenID’ом теперь не покажет две непонятные формы “введите логин/пароль”, а молча залогинит - создав по пути нового пользователя. Правда, может выкинуть на старую страничку - если вдруг система sreg отдаст email, уже существующий в базе (если она не отдаст email, то всё пойдёт по первому сценарию без привлечения пользователя к процессу).

Во-вторых, теперь в профиле есть ссылочка на список ассоциированных с пользователем OpenID’ов, где их можно удалять и добавлять новые.

Так что жизнь становится легче и удобнее с каждым часом. :D Велкам! ;-)

Дебаг Джанги

Как проходит дебаг джанги обычно? В 90% случаев хватает внимательно изучить желтенький джанговский трейсбек ошибки, со всеми переменными и кодом, ещё в 9% хватает расставить print‘ы, а в совсем запущенных случаях приходит на помощь winpdb.

Но после одной отличной новости можно значительно облегчить себе жизнь - перестать расставлять print’ы, перестать изучать трейсбеки досконально и отказаться от удалённого дебаггера, заодно показав язык Pylons’ам, в которых такая штука есть давно. :-)

Вообще я этот пост прочёл и пролистал, когда он появился неделю назад. А тут случайно наткнулся на него ещё раз и решил попробовать. Фантастика! :-) Встречайте - консоль прямо в трейсбеке. :) Я сделал скрин (250 кб) моих первых шагов в неизведанное. ;-)

Рекомендую. Офигенская штука. Сам по себе werkzeug небольшой, стартует быстро (быстрее джанги), проблем не вызывает и вообще… просто красота теперь. :)

Пользователь и его профиль

Известная штука, что у Django есть статическая (неизменяемая официально поощряемыми путями) модель User и костыль для дополнительных полей (которые может каким-либо образом использовать приложение) в виде настройки USER_PROFILE, указывающей на модельку-профиль. В результате использования такого костыля, если не делать дополнительных телодвижений, количество запросов возрастает (пример для данного блога, где каждому комментирующему ставится ссылка на его сайт) на число комментариев (даже не комментировавших, а комментариев!).

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

Потому, после продолжительных колебаний и сомнений, я решил сделать всё радикальнее - удалить всю модель UserProfile, применив вместо неё monkey patching к стандартной модели:

User.add_to_class('site', models.URLField(verify_exists=False, blank=True))
User.add_to_class('email_new', models.EmailField(blank=True))

User._meta.admin.fields += (
    ('Byteflow Extensions', {'fields': ('site', 'email_new')}),
    )

Конечно, главная проблема здесь - это то, что способ совершенно не стандартный и вряд ли кто-то будет ожидать, что табличка auth_user будет меняться. Но такой способ настолько выгоднее и удобнее, что я решил наплевать на эти трудности. :-)

И ещё одно - спасибо Амиту, который и показал конкретно, как это сделать. ;-)

Сортировка почты

Настраивал себе локально чтение почты (кое-какие потоки почты забираю вместо перенаправления на гмейл, проще жить выходит :-), ну и сортировку соответственно. Так как я не слишком люблю клиенты типа Тандербёрда или Сильфид, то основным способ у меня всегда был procmail. Но его правила порядочно раздражают: читаешь доки, читаешь, проходит три месяца - и всё забывается. :-) Ещё, пока читал почту Gnus’ом, фильтровал его внутренними правилами, которые конечно поинтереснее прокмейловых, но… привязаны к Гнусу.

Потому я решил поискать для себя что-то стороннее, но поинтереснее прокмейла. maildrop, имя которого раньше неоднократно встречал, не впечатлил синтаксисом. Промелькнула даже шальная мысль попробовать раскидывать почту правилами Exim’а, но это было бы ничуть не более портабельное решение, чем правила Гнуса.

Пересмотрел порядка десятка программ и наткнулся на очень интересную штуку - maildirproc. Самое большое её достоинство: она написана на питоне и правила раскидывания - тоже самый обычный питон, можно творить всё, что душе угодно. Кроме того, есть одна особенность - в отличии от MDA типа procmail’а и maildrop’а, эта штука ориентирована сугубо на сортировку почты для одного человека. Потому просто указывается место, где появляется почта (типа /var/mail/piranha), и программа делает с каждым пришедшим письмом разные непотребности в полном соответствии правилам (есть однократный запуск, когда раскидывается вся текущая почта, и постоянный, когда “почтовые места” проверяются ежесекундно).

Работает всё очень просто - программа входит в бесконечную итерацию, в каждый проход которой существует объект письма, над которым можно поиздеваться. Пример настройки можно посмотреть тут (совсем простой вариант, но там рядом есть ещё несколько вплоть до совершенного хардкора), все возможности можно увидеть здесь.

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 однозначно - очень интересная комбинация.