Pull to refresh

nginx, memcached и SSI

Website development *
Моя первая статья, не судите строго...

Приветствую вас, уважаемые хабрадевелоперы!

Многие из вас знают о прекрасном легковесном веб-сервере nginx.
Некоторые также знают, что он умеет работать с memcached.
Но лишь немногие в курсе, при чём здесь SSI и как его можно использовать в связке с nginx и memcached.

Как известно, новое — это хорошо забытое старое. Каждый названный инструмент и технология вам наверняка известны. Я же хочу рассказать о том, как и зачем свалить всё это в одну кучу :)

nginx


В классической схеме nginx используется как load balancer или reverse proxy перед одним или несколькими серверами типа Apache.
nginx отдает статические ресурсы — картинки, CSS- и JS-файлы. Запросы к динамическим страницам он передает в Apache/PHP, который самостоятельно обрабатывает их и возвращает результат.

Поискав на хабре статьи про nginx, я так и не нашел подробного описания работы этой «классической» схемы, а отвлекаться от темы не хочется, так что желающим копнуть поглубже советую погуглить — информации и туториалов в сети предостаточно.

memcached


nginx умеет работать с memcached при помощи модуля ngx_http_memcached_module.
Когда nginx получает запрос на определенный URL, вначале он проверяет, есть ли результат запроса для данного URL'а в кэше. Если есть — отдает кэшированную страницу как есть, а если нету — передает обработку запроса в Apache/PHP. Получив запрос, PHP подготавливает ответ, сохраняет его в memcached, а затем отображает его пользователю. Таким образом, при следующем запросе по этому же URL'у nginx сам найдет результат в кэше и вернет его пользователю, минуя ресурсоёмкое обращение к Apache/PHP.
В теории всё просто и удобно, но на практике применение такого кэширования весьма ограничено.

Допустим, мы хотим закешировать главную страницу хабра :)
Мы видим блок авторизации в правом верхнем углу (войти/зарегистрироваться, либо общие сведения о текущем пользователе), «закладочки» (все, коллективные, персональные...), ленту захабренных статей, облако тэгов и т.д.
Все блоки на странице можно условно разделить на статические и динамические. Условно — потому что на самом деле все блоки динамические, но некоторые кэшировать можно, а другие — нельзя. Подумайте сами, что будет, если мы закэшируем главную страницу для неавторизированного пользователя, а затем по тому же URL'у на неё зайдет авторизированный пользователь? Правильно, в верхнем правом углу он увидит приглашение войти в систему или зарегистрироваться и будет как минимум удивлён.

Что же делать? Один из вариантов — не кэшировать страницу целиком! У нас есть возможность исключить динамические блоки из кэширования. И помогут нам в этом…

SSI, или Server Side Includes


Если кто-то ещё помнит, была раньше такая технология, задолго до JSP, ASP, PHP и прочих Django'в с RoR'ами :)
Смысл её в том, что обычная HTML-страница обрабатывалась определенным образом на сервере перед тем, как уйти клиенту. Например, обычная директива include выглядела так:
<!--#include file="header.html"-->

Вот нас как раз интересует именно эта директива, только не include file, а include virtual. Отличаются они тем, что include file вставляет вместо себя содержимое файла, а include virtual — результат виртуального запроса по указанному URL'у. В nginx реализовать задуманное нам поможет модуль ngx_http_ssi_module.

Возвращаясь к примеру с главной страницей хабра, в кэш мы помещаем страницу как есть, только блок авторизации заменяем на такой вот include:
<!-- #include virtual="/auth" -->

Затем, когда nginx получит данную страницу из кэша, он должен будет обработать все SSI-инструкции, прежде чем отдавать её клиенту. Таким образом, nginx выполнит виртуальный запрос по URL'у "/auth" и, не найдя результатов для этого URL'а в кэше — передаст запрос в Apache/PHP. Теперь, задача PHP — проверить авторизацию текущего пользователя и вернуть HTML-код блока авторизации в зависимости от того, авторизирован ли пользователь.
Получив результат от Apache/PHP, nginx вставит его на место директивы include и вернет страницу клиенту. Таким образом, авторизированные и неавторизированные клиенты будут видеть разные страницы, контент которых будет по-прежнему кэширован и бедному серверу хабра не нужно будет на каждый запрос получать ленту захабренных статей, генерировать облако тэгов и т.д. — только простенький блок авторизации ;)

Практика


Хотелось сразу описать и практические примеры реализации этой идеи, но статья и так немаленькая получилась — лучше практическую часть оформлю отдельно, с описанием конфигурации сервера и примерами на PHP & Zend Framework.

А у самых нетерпеливых хабрадевелоперов уже есть все ссылки, чтобы поглубже копнуть в эту тему :)

PS: Честно говоря, на практике такой подход к кэшированию мне применять ещё не доводилось, к сожалению. Есть только несколько набросков готового кода, который на первый взгляд вполне работоспособен. Если коллективный разум подскажет узкие места или потенциальные проблемы — буду весьма благодарен. Спасибо за внимание!
Tags:
Hubs:
Total votes 4: ↑3 and ↓1 +2
Views 16K
Comments Comments 93