Разгоняем django сайт с помощью staticgenerator
Я неспешно переезжаю на VDS от gandi.net. Был дедик с объёмом памяти один гиг, а переезаю на 256 метров. Пока не знаю, удастся ли втиснуться. Конечно же, возникают вопросы, а можно ли убыстрить мои сайты, заставить их жрать меньше памяти. Сегодня ночью я сражался с web-brains, а точнее с byteflow, на котором они работают. Выяснилось, что более одного запроса в секунду apache/mod_wsgi демон не обрабатывает, хоть ты тресни. Я пока не понял, во что именно упирается byteflow, но это не важно в рамках данного сообщения. Решил я закешировать веб-мозги, да так шобы прям в усмерть закешировать. Как раз вчера один знакомый упоминал staticgenerator и я понял — самое время призвать на помощь его мощности статическогенерические.
Идея, лежащая в основе staticgenerator оень простая и дерзкая. Адрес веб-страницы похож на файловый путь. Когда мы запрашиваем страницу /2009/08/07/hello-world, то staticgenerator создаёт в заданном каталоге такую же структуру т.е. каталог 2009, в нём каталог 08, в нём каталог 07, в нём каталог hello-world, а в нём файл index.html, куда и записывается содержимое сгенерированной страницы. Всё это делает специальная middleware. Далее начинается самое интересное, мы настраиваем веб-сервер так, чтобы он смотрел в заданном каталоге закэшированный файл и если там он есть, то файл выдаётся пользователю и джанго-демон даже не дёргается. Вот такие пироги :)
Далее я опишу технические детали того, как я прикрутил staticgenerator конкретно к byteflow.
Для начала неплохо установить staticgenerator через easy_install
Далее идём в settings_local.py проекта и пишем там такое в конце:
# Здесь мы просим staticgenerator складывать кэш файл в каталог нужный
WEB_ROOT = '/web/cache/staticgenerator/web-brains.com'
# Это регулярные выражения. Будут кэшироваться только те страницы, которые
# удовлетворяют выражениям. Я поковырялся в urls файлах byteflow и выбрал те,
# которые относятся к непосредственному отображению данных
STATIC_GENERATOR_URLS = (
r'^/$',
r'^/feeds',
r'^/\d',
r'^/tag',
r'^/tags',
r'^/featured',
r'^/author',
r'^/sitemap\.xml',
r'^/robots\.txt',
)
# Так можно в byteflow добавить новую middleware из setttings.py
ADDITIONAL_MIDDLEWARE= ('staticgenerator.middleware.StaticGeneratorMiddleware',)
Ещё я в settings.py добавил cache_manager в ADDITIONAL_APPS. А что такое cache_manager? А это такое приложение, которое сигналы ловит при создании нового поста или нового комментария и грохает весь кэш. Можно, конечно, хорошо подумать и написать очищение только изменившихся страниц, а можно просто грохнуть быстренько всё :) Я запихал код в cache_manager/__init__.py — таким образом я добился его выполнения при старте сайта т.е. установки нужных обработчиков сигналов.
from subprocess import Popen from staticgenerator import quick_delete
from django.db.models.signals import post_save
from django.conf import settings
from blog.models import Post
from discussion.models import CommentNode
def clear_cache(**kwargs):
Popen('rm -rf %s/*' % settings.WEB_ROOT, shell=True)
post_save.connect(clear_cache, sender=Post)
post_save.connect(clear_cache, sender=CommentNode)
Код элементартный. Если создали Post или CommentNode — грохаем кэш!
Так, так. Вот мы сайт настроили. Осталось веб-сервер настроить. Веб-сервер у нас, конечно, nginx. У меня такой конфиг для веб-мозгов:
server { server_name .web-brains.com; access_log /var/log/www/web-brains.com-access.log; error_log /var/log/www/web-brains.com-error.log warn;
include fastcgi_params;
location /admin-media {
alias /home/web/lib/django_src/django/contrib/admin/media;
}
location /static/ {
root /web/web_brains;
}
# Нас интересует ниженарисованный кусок конфига
# Делаем корнем для статики тот каталог, куда
# staticgenerator кэш пишет.
root /web/cache/staticgenerator/web-brains.com;
location / {
# Всё что не GET, отдаём бэкенду. У меня это apache/mod_wsgi
if ($request_method != GET) {
proxy_pass http://127.0.0.1:8080;
break;
}
# Вот тут чуток меняем путь поиска т.к. staticgenerator
# пишет кэш в index.html файлы
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# Если файл таки не нашёлся, идём в бэкенд
# иначе ничего не делаем и благополучно выкидываем
# закэшированный файл пользователю
if (!-f $request_filename) {
proxy_pass http://127.0.0.1:8080;
break;
}
}
}
Гм, ну вот и всё. Ща сохраню статью и заодно проверю, что кэш грохнулся. Я запускал ab тесты прямо на VPS. Раньше морда веб-мозгов раздавалась со скростью 1page/second, а щас 668pages/second. Клёво :)






Comments
Спасибо за статью. Я даже придумал, куда это можно применить.
Логин часом не отлетел?:) Я не могу залогиниться для ответа.
А я сейчас не мог удалить комментарий т.к. не было кнопки “Удалить”. А виноват в этом я и косвенно staticgenerator. Суть проста: гость запросил страницу, кэш создался, теперь этот же кэш отдаётся и мне :) И в этом кэше нет ссылки удаления комментария и показано, что я гость. Видимо, это ставит жирный крест на staticgenerator. В любом случае — статью написал и то ладно :)
Джанговский вью-кэш в сочетании с vary_on_cookie пробовали? Делает ровно то, что нужно, разве что фрэймворк дергает при обработке запроса.
По идее, несложно написать бэкэнд к кэшу джанго, который бы позволил кэшировать страницы (и только их) в файловой системе и в дальнейшем раздавать как статику.
В идеале хотелось бы что-то такое привернуть, чтобы не править сорцы byteflow :-) Если не получится, придётся законтрибутить туда кэширование или просто на другой движок съехать.
А почему не linode? Или www.rackspacecloud.com?
У сайта gandi.net красивый дизайн.
:)
А ещё он во Франции — пинг меньше, чем до тех, которые в штатах. А ещё у меня два месяца халявных по акции специальной. И для потестировать тоже бесплатно дают. В общем, приятный сервис.
Еще полтора года назад я переделывал этот статикгенератор в более продвинутую версию. StaticGenerator Pro Там и решение проблемы с юзерами через определение куки сессии в нгинксе есть.
Кстати, джаред(автор генератора) взял у меня версию, чуть изменил, чтобы не совсем уж стыдно потыренной выглядела и никакого упоминания ни обо мне, ни ссылки на блог
Вот гад.