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.
- Drupal 8 and Redis, part 1: NGINX serve content directly out of a Redis cache
- Drupal 8 and Redis, part 2: a review of the module and NGINX configuration
- 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:
- Redis
- Nginx with the HTTP Redis module
- PHPRedis extension
- The Redis module for Drupal
- 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:
- Drupal generates the page, and saves it to the standard cache
- The page is stored in Redis Page Cache
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:
- Delete all records in Redis Page Cache when clearing the Drupal cache
- Set a list of web page addresses not to store in Redis Page Cache
- You can also set a different prefix for key names in Redis. Default key name is rpcache:url. Note that the key in Nginx settings must correspond to the prefix
- An example of Nginx configuration
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 cache | Varnish | Nginx + Redis Page Cache | |
---|---|---|---|
Requests per second | 180 | 4042 | 4265 |
Time per request | 55 ms | 2.474 ms | 2.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.