fbpx

PHP / Server Setup / Wordpress

Speed up WordPress with Persistent Object Cache powered by latest Redis

by , , revisited on


We have by far the largest RPM repository with NGINX module packages and VMODs for Varnish. If you want to install NGINX, Varnish, and lots of useful performance/security software with smooth yum upgrades for production use, this is the repository for you.
Active subscription is required.

WordPress. Poor performance out of the box

Most serious frameworks come with some kind of persistent cache readily available. Sadly, WordPress is not such a framework. By default, it will only make use of the object cache that has a lifetime of… a request. So this only helps to improve performance by a tiny bit. Because the cache lives only for the time when a page is loading. On a new request to the same page, WordPress has to query SQL database all over again with likely all the same queries…

To bring WordPress closer to more mature frameworks, you can and should install a persistent cache plugin.
In this post, we review both the basics of full-page cache vs persistent object cache and how to supercharge your WordPress performance using the latter.

What is a persistent object cache

Let’s clear up some terminology. And let’s not confuse persistent object cache and full page cache (FPC).

Persistent object cache, in WordPress, is storage with frequently accessed data (often configuration). It typically does not store fully generated pages’ HTML. Instead, it stores pieces of data which are expensive to generate; blocks of HTML; configuration data. By storing those in the cache, WordPress can greatly reduce the number of queries against the MySQL server, and reduce CPU usage in general. Persistent object cache helps to display highly dynamic pages, like checkout, or WP admin, faster. An example of persistent cache storage in other frameworks is Magento’s “general” cache.

The full-page is another cache that stores completely generated page HTML and it completely eliminates PHP processing on a cached page. It is efficient with mostly static pages like a blog post.

On any dynamic website, you want both cache types to be enabled:

  • Full-page cache, for “static” pages like blog posts
  • Persistent Object Cache, for pages wherever full-page cache is not applicable: checkout pages, account pages, etc.

Configure persistent object storage powered by Redis

Redis is a highly efficient database engine which often used as cache storage.
For our persistent cache implementation, we need both the Redis server and PHP PECL extension which allows PHP code to communicate with Redis.

Install Redis

Redis 6 is now generally available with threading for I/O.
Using I/O threads it is possible to easily speedup two times Redis without resorting to pipelining nor sharding of the instance.

The following steps for a CentOS/RHEL 8 server, will install Redis 6, as well as the latest PHP 7.4 and Redis PHP extension:

dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf -y install yum-utils

# installing latest PHP-FPM, as well as common extensions required by WordPress
dnf -y module reset php
dnf -y module install php:remi-7.4
dnf -y install php-common php-fpm php-opcache php-mysqlnd php-mbstring php-json php-pecl-zip php-soap php-gd php-pecl-imagick php-pecl-apcu php-xml php-tidy php-pecl-memcached php-ioncube-loader 
# installing php-redis extension
dnf -y install php-redis

# installing Redis 6
dnf module reset redis
dnf module install redis:remi-6.0

If you’re upgrading your installing, ensure restarting PHP-FPM with:

systemctl restart php-fpm

Configure Redis

By default, threading in Redis is disabled.
The documentation suggests enabling it only in machines that have at least 4 or more cores, leaving at least one spare core.
Using more than 8 threads is unlikely to help much.

So for instance if you have four cores boxes, try to use 2 or 3 I/O threads, if you have 8 cores, try to use 6 threads.
In order to enable I/O threads use the following configuration directive in /etc/redis.conf:

io-threads 4

The default Redis configuration that is shipped by the Remi repository’s package, does not set a memory limit on your Redis instance.
This is because Redis is both a cache and a database.
Since entries in a cache might set with “forever” expiration, we are better to add a fail-safe.
Setting the memory limit is applicable for our use case of Redis as a cache.
Likewise, in /etc/redis.conf, specify also the following:

maxmemory 64mb
maxmemory-policy allkeys-lfu

The allkeys-lfu is an eviction policy that removes any key using approximated LFU.
This will ensure that frequently used data stays in the cache, while the least used data can be removed in order to keep our cache size to a sane limit.

For a typical all-in-one server setup, it is recommended to use UNIX sockets for inter-process communication.
Thus, in the same configuration file, enable Redis to listen on a UNIX socket with these lines:

unixsocket /var/run/redis/redis.sock
unixsocketperm 0660

Next, start and enable Redis:

systemctl enable --now redis

Authorize website user for Redis access

A proper PHP-FPM permissions setup includes a separate UNIX user for each website.
If you’re not aware of the concept, check out “NGINX and PHP-FPM. What my permissions should be?”).

We should authorize our website user, e.g. example, to read and write to the Redis UNIX socket.
This can be easily done by adding it to the redis supplementary group:

usermod -a -G redis example

Enable Persistent Object Cache in WordPress

Now we’re ready to set up the persistent object cache in WordPress.
For this, we need a plugin that is capable of talking to Redis and saving cache data there.

There are two prominent plugins that do the job.

Using the “Redis Cache” plugin

This is the most popular plugin. This is because it has some unique features like ignoring cache on some data.

First, ensure Redis connection details at the top of your wp-config.php:

define( 'WP_REDIS_CLIENT', 'phpredis' );
define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/var/run/redis/redis.sock' );
define( 'WP_REDIS_DATABASE', 0 );

If you set up the Redis cache for different WordPress websites on the same server, ensure unique database values for each of them!

To set up the plugin, use WP-CLI:

wp plugin install redis-cache --activate
wp redis enable

Head over to configuration options for more details about advanced configuration.

Using “WP Redis” plugin

WP Redis is one such plugin.

First, ensure Redis connection details at the top of your wp-config.php:

$redis_server = array(
    'host'     => '/var/run/redis/redis.sock',
    'database' => 0, // Optionally use a specific numeric Redis database. Default is 0.
);

If you set up the Redis cache for different WordPress websites on the same server, ensure unique database values for each of them!

To set up the plugin, use WP-CLI:

wp plugin install wp-redis --activate
wp redis enable   

That’s it, things are going to be faster. Read the next section for more details.

How does it all work?!

Even for a WordPress developer, it may be hard to immediately grasp how things work.
There are many terms related to WordPress, and many choices as well.

A few questions you might have if you’re coding themes/plugins, or otherwise interested in how Persistent Object Cache is beneficial:

  • I’ve enabled the Persistent Object Cache plugin. Since it provides only an API, will there be any improvement in site load?
  • Which plugins support Persistent Object Cache and thus will benefit from it?
  • How do I use this cache in my custom code?

The plugins which will benefit from persistent caches are the ones that invoke either wp_cache_* or set_transient functions. You might already have a few plugins installed that use those functions. WordPress Admin definitely does use those.
The difference between the two sets of functions is that the set_transient (in absence of a persistent object cache plugin) will be always persist in the MySQL database in the wp_options table.

So the immense benefit we can have from the mere act of setting up Persistent Object Cache as we did, is that a lot of queries against wp_options will be gone,
and thus performance will be improved.

Subsequently, we can shrink wp_options because the plugin will essentially ensure that transients are stored in Redis!

wp transient delete-all

Success: 243 transients deleted from the database.
Warning: Transients are stored in an external object cache, and this command only deletes those stored in the database. You must flush the cache to delete all transients.

You can monitor the Redis cache memory usage by running redis-cli info memory and will display some stats.
Watch the used_memory_human, and if is coming close to the configured memory limit, you might want to increase your cache size.

# Memory
used_memory:3648912
used_memory_human:3.48M
used_memory_rss:4673536
used_memory_rss_human:4.46M
used_memory_peak:4283992
used_memory_peak_human:4.09M
used_memory_peak_perc:85.18%
used_memory_overhead:861640
used_memory_startup:804832

Conclusions and what will really be faster

The wp-admin is one example location where it uses transients API for update checks.
You will find immense improvement in its performance, and beyond that, other dynamic pages will have a noticeable performance increase.
No custom coding required! And if you are developing something of your own, use wp_cache_* (or set_transient) in your code, where applicable.

A persistent object cache is a must-have cache type for WordPress.
It can greatly complement a full page cache like Varnish.

  1. Bragi Austfjörð

    Could I install this on centos 8 with plesk.

    Reply
    • Danila Vershinin

      Yes. Enable PHP Redis module in Plesk interface then install and configure Redis itself using instructions above (skip the commands for installing PHP module).

      Reply
  2. Ruslan

    Hi, Thx for helpful article!
    Do you know if this, will work with version 6.2, 7.0 or 7.2?
    Thx !

    Reply
  3. Serdar

    Should we always set the “maxmemory” value to 64MB? Thank you! That’s a brilliant guide!

    Reply
    • Danila Vershinin

      Actually this depends on your website size. The maxmemory 64mb is a good starter value. From then on, it helps to regularly monitor the output of redis-cli info memory and if you see that it uses nearly 64MB and you have enough free RAM available (free -h), it might makes sense to increase it.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.