Thank you for reading this post, don't forget to subscribe!
Кешировать сайты, которые редко изменяются довольно легко. Но ведь большинство современных сайтов имеют множество персонализированных элементов на странице (баннеры, виджеты и т.п.). Для таких случаев существует технология SSI. Технология очень простая, она позволяет разделить страницу на блоки и включить кеширование только для некоторых из этих блоков.
SSI
Допустим, у нас на странице есть статический контент и только один баннер. Но баннер зависит от персональных данных, поэтому его нельзя кешировать. Мы могли бы закешировать страницу, но только не тот участок, где находится баннер. А на месте этого участка постоянно выводить динамический контент.
Так вот, SSI — это просто специальная инструкция, которая указывает Web серверу, вставить вместо нее результат запроса к какой-то другой странице. Пример инструкции:
1 |
<!--# include virtual="/authentication.php" --> |
# Вместо этого кода на страницу будет вставлен результат запроса к скрипту "/authentication.php"
Web сервер понимает SSI инструкции и автоматически заменяет нужные участки страницы перед отправкой ее клиенту. Кешировать можно как всю страницу, так и отдельные блоки.
Конечно, само по себе это бессмысленно (зачем делать два запроса, вместо одного), но в связке с кешированием представляет очень удобный инструмент оптимизации.
Nginx и SSI
В Nginx поддержка SSI включается очень просто:
1 2 3 4 5 |
server { ... ssi on; ... } |
Кеширование SSI
Nginx позволяет читать данные из Мemcache.
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 |
server { location / { set $memcached_key $uri; # Ключ - это строка запроса memcached_pass 127.0.0.1:11211; # Подключаемся к мемкешу default_type text/html; # Тип по умолчанию error_page 404 = @fallback; # Данные в кеше не найдены, шлем запрос на бекенд } location @fallback { proxy_pass backend; # Бекенд } } |
[/codesyntax]
Нам останется только сохранить в Memcache нужные данные из приложения (Nginx сам не умеет складывать туда данные).
PHP
В PHP необходимо обеспечить сохранение нужных данных в нужные ключи.
1 2 3 4 5 6 7 8 9 |
<? $memcache = new Memcache(); ob_start(); echo "тут должен быть <b>html</b>, и его будет много"; $html = ob_get_clean(); $memcache->set($_SERVER['REQUEST_URI'], $html); echo $html; ?> |
# Сохраняем результат буфера вывода в Memcache
Настоящий пример
Определяем блоки SSI
Первое — выделяем нужные блоки в шаблоне и заменяем их вызовами SSI.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<html> <body> <h1>Тестируем nginx + memcached + ssi</h1> <div class="auth"> <!--Блок авторизации!--> <!--# include virtual="/authentication.php" --> </div> <!--Тело конкретной страницы!--> <!--# include virtual="/somepage.php" --> </body> </html> |
Как видно, на странице есть два SSI блока — блок авторизации и блок контента. В нашем примере блок авторизации будет персональным (допустим, после входа, там будет имя пользователя). Блок содержимого не будет персональным (т.е. он будет общим для всех пользователей).
Настраиваем Nginx
Нам нужно настроить два хоста:
- Главный хост — к нему будут обращаться посетители. Он будет обрабатывать SSI и использовать данные из кеша.
- Бекенд — наше приложение. Он просто всегда будет отдавать результат работы PHP.
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 |
server { listen 8081; location ~* \.(php)$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME /var/www/test$fastcgi_script_name; } } |
[/codesyntax]
# Бекенд
[codesyntax lang="php"]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
server { listen 80; root /var/www/test; index index.php; location / { # Все POST запросы отправляем на бекенд (не кешируя) if ($request_method = POST) { proxy_pass http://127.0.0.1:8081; break; } # Включаем обработку SSI ssi on; default_type text/html; # Проверяем в мемкеше set $memcached_key "$uri"; memcached_pass localhost:11211; proxy_intercept_errors on; error_page 404 502 = @process; } # Сюда запрос приходит, если его не было в кеше location @process { proxy_pass http://backend; ssi on; } } |
[/codesyntax]
# Главный хост
PHP
Нам понадобится два скрипта — authentication.php и somepage.php. Они будут одинаковыми по сути, somepage.php мог бы выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<? $memcache = new Memcache(); $post = posts::get($_GET['id']); ob_start(); ?> <h1><?=$post['title']?></h1> <p><?=$post['html']?></p> <br/> <? $html = ob_get_clean(); $memcache->set($_SERVER['REQUEST_URI'], $html); echo $html; ?> |
Самое важное
SSI позволяет повысить гибкость обычного кеширования на уровне Web сервера. Использование этого подхода позволит использовать преимущества кеша на динамических сайтах.