[Хд] logo

Caching dynamic content with SSI

Caching sites with rarely changed content is an easy task. But most of today's websites have dozens of personalized elements on each page (banners, widgets and so on). For such cases there is a special technology called SSI. The underlying process is very simple — it allows dividing webpages into blocks and enabling caching for only particular ones.

SSI

Let's say you have a webpage with static content and a single banner. But this banner is personalized, so there's no point in caching it. The page could be cached, but excluding the banner area. And dynamic content can be constantly displayed in this area. SSI

So, SSI is a special instruction that makes webserver replace it with a request result to some other page. Sample instruction:

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

# Webpage will have "/authentication.php" script request result inserted instead of the code

Webserver reads SSI instructions and automatically replaces the appropriate webpage sections before sending it to the client. Thus, you can cache separate blocks as well as a complete page.

Of course, by itself it is pretty meaningless (no sense in making two requests instead of one), but in combination with caching it is a really handy optimization tool.

Nginx and SSI

Nginx SSI

Enabling SSI support in Nginx is simple:


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

SSI caching

Nginx can read data from Мemcache.

server {
  location / {
    set $memcached_key $uri; # Request string is the key
    memcached_pass     127.0.0.1:11211; # Connects to memcache
    default_type       text/html; # The default type
    error_page         404 = @fallback; # No relevant data is found in cache, request is sent to backend
  }

  location @fallback {
    proxy_pass backend; # Backend
  }
}

Now, what is left to be done is saving the desired data from your application into Memcache (Nginx has no appropriate method for this).

PHP

In PHP, you should ensure that relevant data is saved with the right keys.

<?
$memcache = new Memcache();
ob_start();
echo "here goes <b>html</b>, plenty of it";
$html = ob_get_clean();

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

# Saves output buffer results in Memcache

Real world example

Defining SSI blocks

Firstly, define the desired blocks in the template and replace them with SSI requests.

<html>
<body>

<h1>Testing nginx + memcached + ssi</h1>

<div class="auth">
<!--Authorization block!-->
<!--# include virtual="/authentication.php" -->
</div>

<!--Body of a particular webpage!-->
<!--# include virtual="/somepage.php" -->

</body>
</html>

As you can see, this webpage has two SSI blocks — authorization block and content block. In this example, the authorization block is personalized (for example, input field displaying user name). Content block is not personalized (i.e., it will be displayed the same for all users).

Configuring Nginx

You'll need to configure two hosts:

  • The main host handles visitors. It processes SSI instructions and uses data from cache.
  • Backend is the application. It simply always returns PHP operation results.
 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;
    }
}

# Backend


server {
	listen 80;

	root /var/www/test;
	index index.php;

	location / {
		# All POST requests are sent to backend (no caching)
		if ($request_method = POST) {
			proxy_pass http://127.0.0.1:8081;
			break;
	        }

		# Enables SSI processing
		ssi on;
		default_type text/html;

		# Checks in memcache
		set $memcached_key "$uri";
		memcached_pass localhost:11211;
		proxy_intercept_errors  on;
		error_page 404 502 = @process;
	}

	# Request goes here if not found in cache
	location @process
	{
		proxy_pass http://backend;
		ssi on;
	}
}

# Main host

PHP

You'll need two scripts — authentication.php and somepage.php. In essence, they will be the same, somepage.php could look like this:

<?
$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;
?>

The most important

SSI allows to enhance flexibility of a conventional cache on webserver level. This approach utilizes the advantages of cache in regards to dynamic websites.

  читать на русском
[Хд]

Sign up to read high quality stuff on advanced development

Google Email

Esc for later