Oct 17, 2017

Drupal 8 and Redis, part 1: NGINX serve content directly out of a Redis cache

Alexey Doronin
Founder, developer, designer

There are many ways to speed up your website and reduce load on the web server by using a cache. I reviewed different types of caching in the previous article and in this series I'll try to show you how to get the best performance with minimum configuring.

  1. Drupal 8 and Redis, part 1: NGINX serve content directly out of a Redis cache
  2. Drupal 8 and Redis, part 2: a review of the module and NGINX configuration
  3. Drupal 8 and Redis, part 3: clearing the external cache

The idea has been around for a while — data is stored in the memory, in Memcached or Redis (a fast key-value store), so that Nginx can get data directly from Redis without sending requests to PHP.

This is essentially how it works:

Nginx gets a page request and tries to get data from Redis first. If the Redis cache doesn't contain the page, the request is passed to PHP (Drupal).

Now let's see how to implement this.

Nginx

First, we need to add the HTTP Redis module to NGINX, so that it can interact with Redis. You can learn more about it in our article How to compile dynamic modules for NGINX (HTTP Redis as an example).

There is another option with more functionality, Redis2, but we only need to read data, so HTTP Redis will suffice. 

Drupal and Redis

Then we install Redis on the web server and use it to store cache for Drupal (with the help of a Drupal module that you can find here). 

Let's look at the records. We'll be using Keylord as a GUI for Redis:

Keys are on the left, values are on the right. Records related to cached pages — the type of records we want to fetch — will have this in their keys:

render:http

And here is an example of a full key:

drupal.redis.8.3.7..3f62575ace1138c5777536543445081669d32a76a2a8d6ee514ca459bd0c89f8:render:http://drupalvm.dev/mypage:html

The value of the Data field:

The page is stored as a serialized Response object and Nginx can't read it. 

Redis Page Cache

To enable Nginx to read these pages, we will create separate records in Redis to store HTML pages. 

Then, Redis will have two types of records:

  1. Standard Drupal cache;
  2. Records with HTML pages as values. Let's call them Redis Page Cache.

There are at least two approaches to storing pages in a separate cache (Redis Page Cache): 

  1. StackMiddleware 
  2. Set a handler for one of the events that are triggered when Drupal sends a page back  

I chose the second option and the TERMINATE event.

Related links:
The HttpKernel Component
The Drupal 8 render pipeline

So, we use Redis in two capacities: as the standard Drupal cache and as an external cache for pages.

For Redis Page Cache we will use the following keys: rpcache:url. An example record: