четверг, 27 декабря 2012 г.

Nginx, Memcached и SSI (Server Side Include)

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

Nginx

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

Memcached

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

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

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

SSI или Server Side Includes

Если кто-то ещё помнит, была раньше такая технология, задолго до JSP, ASP, PHP, Python и прочих 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/Python. Теперь, задача Python - проверить авторизацию текущего пользователя и вернуть HTML-код блока авторизации в зависимости от того, авторизирован ли пользователь.

Получив результат от Apache/Python, Nginx вставит его на место директивы include и вернет страницу клиенту. Таким образом, авторизированные и неавторизированные клиенты будут видеть разные страницы, контент которых будет по-прежнему кэширован и бедному серверу Хабрахабра не нужно будет на каждый запрос получать ленту захабренных статей, генерировать облако тэгов и т.д. - только простенький блок авторизации.

Комментариев нет:

Отправить комментарий