Кэширование динамики с SSI

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

SSI

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

Так вот, SSI — это просто специальная инструкция, которая указывает Web серверу, вставить вместо нее результат запроса к какой-то другой странице. Пример инструкции:

<!--# include virtual="/authentication.php" -->

# Вместо этого кода на страницу будет вставлен результат запроса к скрипту "/authentication.php"

Web сервер понимает SSI инструкции и автоматически заменяет нужные участки страницы перед отправкой ее клиенту. Кешировать можно как всю страницу, так и отдельные блоки.

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

Nginx и SSI

Nginx SSI

В Nginx поддержка SSI включается очень просто:


server {
    ...
    ssi on;
    ...
}

Кеширование SSI

Nginx позволяет читать данные из Мemcache.

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; # Бекенд
  }
}

Нам останется только сохранить в Memcache нужные данные из приложения (Nginx сам не умеет складывать туда данные).

PHP

В PHP необходимо обеспечить сохранение нужных данных в нужные ключи.

<?
$memcache = new Memcache();
ob_start();
echo "тут должен быть <b>html</b>, и его будет много";
$html = ob_get_clean();

$memcache->set($_SERVER['REQUEST_URI'], $html);
echo $html;
?>

# Сохраняем результат буфера вывода в Memcache

Настоящий пример

Определяем блоки SSI

Первое — выделяем нужные блоки в шаблоне и заменяем их вызовами SSI.

<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.
 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;
    }
}

# Бекенд


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;
	}
}

# Главный хост

PHP

Нам понадобится два скрипта — authentication.php и somepage.php. Они будут одинаковыми по сути, somepage.php мог бы выглядеть так:

<?
$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 сервера. Использование этого подхода позволит использовать преимущества кеша на динамических сайтах.


Подпишитесь на Хайлоад с помощью Google аккаунта
или закройте эту хрень