Enterprise-grade WordPress sites that can scale at will, need a persistent caching mechanism beyond pages and images, a mechanism that can cache actual PHP objects. Although WordPress provides an object caching mechanism through the WordPress Object Cache, there are other solutions that offer great leverage and power. But before we get into all that, first, we need to see what object caching is and how it works in PHP.
What is object caching?
PHP is an Object-oriented language. It uses the Object paradigm to structure code. As a result, your WordPress site consists of many different PHP Objects that are constantly created, instantiated and destroyed (by memory manager). Creating and destroying objects has a cost overhead, particularly if they are many. However, most of these tend to be reused a lot since they represent core functionalities. This means that each time the application needs them again, it will need to instantiate them from the start.
What if you could cache a frequently-used instantiated object so that you did not need to destroy and create it all the time?
You can use PHP’s
serialise() function to convert an object or a primitive to a number representation (byte blob) that can be stored in memory, or disk for later access. Then you compute the byte blob’s hash number using the
hash()function and store both of them. The hash as key and the byte blob as value. In order to retrieve it, you use the byte blob’s computed hash number which was initially stored as a key. You can turn anything (String, Integer, Object, Boolean, Array, etc) into a storable representation of a value this way.
$serialized = serialize(array('test'));
Perform the reverse operation, with unserialize():
In general, there are three ways you can cache objects: Using the native WordPress Object Cache, the Transients API, or an external key-value store like Redis or Memcached.
WordPress Object caching
The native WordPress Object Cache can store objects and primitives in the cache, but not in a persistent manner by default. This means that the caching happens in memory, and the cached objects do not live beyond the request’s lifetime cycle. So you can’t share your cached objects across different page loads. You need to supply your own store implementation with the use of Drop-Ins, which are “advanced” plugins that can extend WordPress functionality. You can see them on your WordPress dashboard, in the plugin list:
The Transients API, on the other hand, works out of the box. You can save variables, arrays, objects tied with an expiration date directly on a database and have persistent object caching. However, the problem is that when your cached objects expire, they remain on the database taking up space. This means that there is an extra overhead spent in maintaining the database, pruning every once in a while the expired objects.
WordPress detects if you have implemented your own persistent object cache and when it finds that to be the case, calls to the Transients API are bypassed and routed to the WordPress Object Cache (and thus the reason for them being identical).
Developers can implement their own object cache, use a WordPress plugin (more about those later) or our own implementation, if a Pressidium client. We do not have the object cache turned on by default, as this can cause performance penalties if used in the wrong situation. There is no “one-size-fits-all” solution when it comes to object caching in WordPress sites.
Redis and Memcached
Key-value stores do not use tables and predefined data types to store information in records such as in RDBMS. They are designed to store and retrieve key/value pairs, as in the dictionary data-structures you find in programming languages.
One fine example of such store is Redis. Aside from dictionary data structures, it supports a plethora of others, including advanced ones such as sorted sets with range queries, and geospatial indexes with radius queries. It offers persistent object-caching.
Redis is not just a key-value store or cache. It supports data replication, scripting, high availability in a cluster configuration. You can also fine-tune the level of on-disk persistence you want. The good thing about Redis is that if you do a restart, most of your cache will still be on-disk, with the lost data will be only a small fraction. The thing is that upon restart, the server would have to rebuild the cache and this most of the times increases the load. With Redis this doesn’t happen. Additionally, expired objects are immediately deleted from the database. No management overhead time there too.
Redis Labs has an excellent page showcasing the Redis use cases in the Enterprise: These range from Very Large DataSets, to full-text search, Real-Time Series, Spark integration and more.
Although all these features cost in complexity and maybe in speed in some cases, optimizing your Redis Drop-In code can achieve quite a few gains. Don’t forget the fact that Redis does persistent object-caching, something that Memcached doesn’t, although it is much simpler to use.
Memcached is an in-memory high-performing object caching system that is according to the official website, specifically designed to speed-up dynamic web applications and alleviate database load. It is also much simpler and straightforward to use than Redis.
Due to being specifically designed to do object caching for web pages, and the fact that it uses an in-memory database makes it the fastest object caching solution out there. However as we’ve mentioned earlier, if your server restarts, your cache is out. And until it is rebuilt, you will probably be experiencing increased load. But as the creators say: “think of it as a short-term memory for your website”, so it rather depends on what you want to do in the first place.
Since Memcached uses an in-memory database for keeping the cache, it is very efficient in caching SQL queries, function call outputs, and such.
- WP Redis, the official Redis WordPress plugin. Supports WP-CLI, clustering and replication.
- Redis Object Cache Another back-end Redis Plugin for WordPress.
- Memcached Object Cache, the backend for Memcached.
- Delete Expired Transients, this plugin deletes expired transients objects from the database. It supports multisites too!
How to run benchmarks
The point of our article is to get you excited about object caching and start tinkering on your own. You can try various persistent cache implementations and see how well your application behaves. You can use PHP’s microsecond() function to benchmark calls. For example: Call
microsecond() before and after calling
wp_cache_get(), subtract the values and store the result. Do this for various cache implementations, and see in what cases you notice a performance gain.
At Pressidium, we don’t have object caching enabled by default and although this is something that can be requested, we usually don’t advise in favor of it from the start. We run tests and make sure that your site is going to gain benefits from it.
Let’s say that in order to render a page the application needs to read 2,000 transient objects. That means 2,000 reads on the database. By using a persistent object caching system, these 2,000 reads are offloaded to the key-value store. If you use memcached then you risk losing all of your cache in a sudden restart. In general, Redis might not be as fast as Memcached but its Enterprise features and persistence benefit you in the long-term.
However, one size does not fit all! For example, we’ve seen Redis instances that actually slowed down websites, and in other cases where they speeded them up incredibly. This has to do with a number of objects that your application uses: in general, if your application uses a few (let’s say a dozen) you won’t get much benefit from the object caching, and in the worst case, you’ll have network overhead. If however, your application is in the hundreds then it might pay off to have a look.