Caching can give the impression of a "holy grail" for all performance problems. It's no wonder people raise an eyebrow when I use caching in my presentations, meetups, workshops or at the WordPress Support say "stop caching".
For some, especially in the WordPress community, I've become the guy who hates caching. So it's time to make it clear what I really mean by this topic, when and what it should be used for. And perhaps most importantly, when you're not using caching and looking for alternative solutions.
When should you use full page caching?
Let's start with the biggest one of all. Full page caching or just page caching. A technique where you temporarily store a pre-generated version of a page to deliver the same code (HTML) to visitors within a limited amount of time. This is how full-page caching works:
Visitor A visits abc.com/page. This page is not cached, hits PHP and is generated from the database. Before it is delivered to visitor A, it is also saved in the full page cache after 10 minutes.
Visitor B visits abc.com/page 2 minutes after visitor A and is therefore served the same page, but this time directly from the cache. The pages for visitors A and B are identical.
Visitor C visits abc.com/page 15 minutes after visitor A. Since the cached version of the page has now expired, the request is called again with PHP and the page is generated again in exactly the same way as for visitor A.
Since anyone who visits this page in the time span in which a valid cached page is available can be delivered very quickly. Almost no resources are used to serve a cached page. Therefore, by fully caching pages, performance and most importantly scalability can be improved. It may sound very appealing, but full-page caching also has some major disadvantages.
1. if you want to provide dynamic content, personalized or otherwise different content for different users, this must be solved with Javascript (Ajax), which is executed after the HTML document has been submitted to the visitor. This can work well, but still requires an additional request to the server. If you use caching to avoid writing fast code, you will run into problems with your dynamic Ajax requests.
2. just because something works fast for you doesn't mean it's fast for everyone. Websites don't have a single entry point, and visitors come to your website through different pages. This is especially true for WooCommerce, where visitors use Google and come through product pages. Or, if you run Google Shopping in the full catalog with links to product pages. To solve this issue, some people even try to fix the problem by "priming" the entire page cache and using spiders to index the entire site to ensure that every page is cached beforehand. In practice, this doesn't work well. It's fragile, difficult to set up and configure properly, difficult to maintain and time-consuming - and completely unnecessary. And because Google has already been mentioned in this paragraph, let's test whether Google finds this link legitimate, even though it has nothing to do with the topic of this article. You could, for example, link to WordPress website costs and pretend it fits the article.
3. you lose control over the actual performance of your website and how the code works (or doesn't work as it should). When you use full page caching, you lose sight of what the actual response time of your website is and how well your code is performing. Experience shows that the lack of focus on actual performance is the main reason why websites crash on days like Black Friday or during the distribution of large campaigns.
What about caching plugins like W3 Total Cache?
WordPress plugins such as W3 Total Cache work like all other page caches. They store a version of a pre-generated page in the file system or memory and make it available to users until it expires. W3 Total Cache is used by 1 million websites and many WordPress freelancers and WordPress programmers used. However, this does not mean that this is a good idea. Especially not if you use fast WordPress Managed Hosting use.
W3 Total Cache is a very comprehensive plugin, and for most websites - this simply adds a lot of unnecessary code to the website. More code means more things can go wrong. If you really need to do full page caching, it should not be done in the PHP part of your application, as PHP is slow. Full page caching should be done on the web server as close to the user as possible (in our case nginx).
W3 Total Cache is about pages loading in less than 2 seconds to show a theme like twenty or fifteen. To be clear; a similar test on our servers is delivered in about 100 milliseconds with no caching and not in seconds.
So when should you use full page caching and why?
Full page caching was made to scale websites with a lot of traffic to handle traffic spikes more easily. Full page caching was invented when people mainly used the internet to read news articles. Generating unique content for each visitor is not practical for newspapers as their pages are mostly static and rarely updated. For this scenario, caching entire pages is absolutely right. Nowadays, however, websites are more like applications.
Contemporary websites are more complex, dynamic and constantly personalized. Code is getting more and more complex, and it's not always a good idea to add even more complex mechanisms (read caching techniques) on top of already complex code. In practice, you then add another layer of technology that introduces new, single points of failure, requires dedicated maintenance, upgrades and operations. Bugs become harder to solve and overall development becomes more difficult (more expensive). If you base your performance on full page caching, I can close to ensure that the solution breaks down when caching stops working.
The answer to the question is therefore to write good code and queries and take into account that the solution must be scalable. With full page caching, you can handle sudden traffic spikes, as was and is common in newspapers.
It should be possible to disable full page caching on a normal day with normal traffic without getting nervous. And if you do everything right, you should be able to disable full page caching even on high traffic days - without crashing your website.
On Servebolt, the vast majority of stores run without full page caching - even on busy days like Black Friday.
WordPress Object Cache - You use it without knowing it
Many people don't realize that the WordPress object cache is used near all WordPress sites. And yes, the object cache is effective even if you don't use an external object cache like MemCached or REDIS.
How does the WordPress object cache work?
You make a request for the postmeta values by using get_post_meta ().
WordPress executes the request, retrieves the result from the database and automatically saves the result in the object cache (RAM).
You get the result and use it somewhere in your code
Later in your code, set another get_post_meta () request for the same data. WordPress already has this in the object cache and returns it directly without querying the database again
The page is delivered to the visitor and the object cache is emptied (memory released).
Not all functions in WordPress store their results in the object cache, but get_post_meta () does. This is because the _postmeta table in the database can become very large and the requests can become expensive (lots of computing resources).
As a developer, you can add results to the object cache yourself so that the same data can be reused more quickly at a later date. If you write your own queries with i.e. WP_Query, you must store the results in the object cache yourself. It is important to remember that, as with all caching, you cannot rely on it. Therefore, make sure that you do not write any code that assumes your results are in the object cache.
You can check the performance of the object cache and the number of queries to the database by installing a plugin such as Query Monitor. In my tests with a regular WooCommerce, the normal hit rate of the object cache is between 95% and 98%.
But what about external object caches such as MemCached and REDIS?
An external object cache can provide a so-called "persistent object cache". This is an object cache that is not emptied between page requests so that the data is retained across different page requests. A clever idea, isn't it? But as always with caching, it's not that simple.
The potential performance gain from using a persistent object cache is limited to the hits that miss the object cache. With the standard hit rate for non-persistent caches of 95 % to 98 %, the potential for performance gains is between 2 % and 5 % of requests. In addition, an external object cache introduces additional latency because it is an external application - so it slows down the 95-98 % previously served directly in PHP. The net gain of additional latency + performance gain from the external object cache often becomes negative for e-commerce stores.
Even if you use an external object cache, you cannot rely on the information being available when you write your code.
If you are relying on an external object cache to load pages at a reasonable speed, it means your code is bad, the database queries are too heavy, or there are too many of them. The real problem lies in your code and not in how fast the database responds. For this reason, you should not use the MemCached or Redis tools.
If you use a fast database that is optimized and uses indexes correctly, you do not need an external object cache.
If you do not need an external object cache, it can be harmful to use one
Harmful is perhaps a bit of an exaggeration, but it is often the case. This actually applies to any technology you build into your web stack that you don't need. If you have it, there's a good chance you'll become dependent on it, even if you don't really need it. If you're dependent on it, the likelihood of something going wrong increases. What's more, every additional piece of technology in the stack requires installation, configuration, maintenance and security upgrades - adding another vulnerability.
Transients can be good, but they can also damage your website
Transients are generated during WordPress Web Design used by various plugins, and the concept is quite simple. You make a request and store the result or parts of it in the database for later reuse. Unlike the object cache, you don't need any additional technology to make this view persistent for all page views, as data is stored in the database. Transients can have an expiration time or not - it's your choice.
Personally, I don't like the overuse of transients, and there are many reasons for this
Transients are stored in the _options table of WordPress. This table is already heavily used, and excessive writing to _options can cause locking problems (queue).
Excessive use of transients leads to a large _options table. Each individual page view is dependent on this table, and a large options table can reduce performance for all page views.
Transients that do not expire are queried via wp_load_alloptions () each time the page is loaded (automatic loading). This reduces performance for all page views.
But with that said - transients can be great for performance if used correctly. If you're querying data that is frequently used and rarely changes, it can make sense to store the result in transients. For WordPress, it is much easier to retrieve the value of key X in the options table than to perform selects in other tables. However, if you do use transients, be sure to keep an eye on the _options table to make sure it doesn't grow wildly, and make sure you implement a cleanup for transients that you no longer use or have expired. Never use transients for data that requires frequent updates. This will affect performance.
Fragment caching is good when used correctly
Fragment caching is a type of caching where you store an element, part of a page or something else that is complex to create and/or frequently used. Many have opted to implement Mark Jaquith's feature for fragment caching in WordPress.
Fragment caching means saving a result (HTML output) so that it can be delivered much faster later. The idea is as simple as it is amazing. You can choose which elements to cache and you don't have to cache the entire output, like full-page caching. We have already conducted experiments like this and others on the website of our WordPress agency in ZT
The procedure in WordPress corresponds to object caching, as there are no limits to the data you can cache. Therefore, the same principles apply. Never rely on anything being cached. Make sure you don't rely on it - and focus on your code instead of using the fragment cache shortcut.
Many implement memory-based fragment caching. However, for this to be effective, an external object cache is required to make the elements available for page requests (see above). I recommend using fragment caching cautiously and storing data in transients instead. In practice, this will give you the same results in terms of performance without adding additional technology to your stack.
Which cache technique should I use and when?
Use full page caching for scaling. There is no way to increase performance for this. Make sure you don't make yourself dependent on it. You should be able to disable full page caching without a significant drop in performance. In many WordPress maintenance contracts for example, but REDIS Cache is also integrated.
Use the object cache as often as possible, especially if you or your WordPress Agency Use WooCommerce. However, if you're not dealing with external object caches, you're introducing all sorts of new problems. External caches shift the focus to the wrong parts of your application. A better trick is to do faster hosting with high-performance databases like ours.
You should use transients for frequent queries that hardly change. Make sure that you set a suitable expiration date, depending on how often the data is to be updated. Also make sure that expired transients are deleted. Use fragment cache in transients for items that are resource intensive and frequently used.