Oct 18, 2017

Drupal 8 and Redis, part 2: a review of the module and NGINX configuration

Alexey Doronin
Founder, developer, designer

In the first part I introduced you to the basics of making NGINX read pages directly from Redis. It helps to dramatically speed up your website and reduce load on the web server. Now let's look at the implementation in more detail.

  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 diagram looks like this:

To enable Nginx read from and write to Redis we need:

  1. Redis 
  2. Nginx with the HTTP Redis module 
  3. PHPRedis extension 
  4. The Redis module for Drupal 
  5. Redis Page Cache, our experimental for Drupal

Starting conditions

The Redis module (Drupal) is enabled and working. Setting up and configuring Redis, PHPRedis, and the Redis module is beyond the scope of this article

Redis Page Cache module

This is an experimental module that has not yet been used in production. You can find it here: https://github.com/azimut7/rpcache

It saves generated website pages to Redis. We call these records Redis Page Cache. Nginx then can read and send them to the user without sending requests to PHP, so these records are essentially an external cache. 

How it's work

A page is saved to Redis Page Cache if it is not found in the standard Drupal cache.

For example, a user requests a page with the address mysite.com/mypage for the first time, and the Drupal page cache doesn't have it. In this case:

Next time this same page is requested, Nginx will get it directly from Redis.

Let's say our website has 50 web pages, and the Drupal page cache contains all of them. You install Redis Page Cache module and enable it, but all pages are still sent from Drupal (headers show that). Does it mean the module is not working? No, that's not it. Since the Drupal cache already has all 50 pages, the trigger that saves pages to Redis Page Cache doesn't fire. You'll have to clear the Drupal cache to make it work.

Settings

You can find settings for the module at /admin/config/development/rpcache:

To delete specific URLs and/or delete all records, go to the Purge URLs tab and the Clear All Cache tab.

This module doesn't affect the standard Drupal cache which is also in Redis, so clearing Redis Page Cache will delete only records stored in it.

Configuring Nginx

For Nginx to access Redis, you will need the HTTP Redis module. 

An example of Nginx configuration to read records from Redis:

...
 
location / {
  try_files $uri @rpcache;
}
 
# Redis Page Cache url for purging, allow access only from localhost
location /rpcache/rpcache-clear {
    allow 127.0.0.1;
    deny all;
    try_files $uri /index.php?$query_string;
}
 
location @rpcache {
     
    ## Disable logs (there are tons of info, warn etc when not found in cache)
    error_log off;
     
    ## Header to see that page was handled by RedisPageCache
    add_header X-RPCache 'HIT';
 
    error_page 418 = @rewrite;
 
    if ($http_cookie ~* "SESS") {
       return 418;
    }
    if ($request_method !~ ^(GET|HEAD)$ ) {
       return 418;
    }
    default_type text/html;
 
    set $redis_key "rpcache:$scheme://$host$request_uri";
 
    ## 127.0.0.1 not localhost!
    redis_pass 127.0.0.1:6379;;
 
    proxy_intercept_errors on;
    error_page 404 502 = @rewrite;
}
 
...

1. error_log off;
If this setting is enabled, all Redis cache misses will be logged. You can also specify log levels. 

2. add_header X-RPCache 'HIT';
A header for debugging: it shows that the page was taken directly from Redis.

3. Process requests from anonymous users only (without sessions)

4. Only GET and HEAD requests

5. The key scheme: "rpcache:$scheme://$host$request_uri"
You can change the prefix rpcache:  in the module settings (see above)

6. Deny access to /rpcache/rpcache-clear from outside (we need this address to clear the cache).

Pages  http://drupalvm.dev/mypage and  http://drupalvm.dev/mypage/, are different pages: the latter has a slash at the end. To make sure they are processed correctly, mark removing trailing slashes in the Redirect module settings.

If everything is configured properly and Nginx serve pages from Redis, headers will look like this:

Compare with headers of page sent from Drupal:

Performance

Below you can see the results of running synthetic benchmarks on a virtual machine. The data is relative but still shows the difference in speed.

ab -c 10 -t 30 http://drupalvm.dev/

1. Nginx and the standard Drupal 8 cache implemented through Redis

2. Drupal 8 and Varnish

3. Nginx that returns the page directly from Redis

A comparison table:

 Drupal, standard Redis cacheVarnishNginx + Redis Page Cache
Requests per second18040424265
Time per request55 ms2.474 ms2.344 ms

Nginx with Redis is even faster than Varnish. That's quite impressive! 

In the next article we will get to the most difficult part — clearing the cache.