Memcache in Drupal 8: how to optimize performance
In this blog post, our technical lead Kevin guides you through the best caching strategies for Drupal 8. Interested in how D8's flow has been improved and how to use Memcache for yourself in the best possible way? Read on!
Flow improvements with Drupal 8
The way data is cached has been overhauled and optimized in Drupal 8. This means that cached data is aware of where it is used and when it can be invalidated, which resolved in two important cache bins responsible for holding the rendered output, cache_render and cache_dynamic_page_cache. In previous versions of Drupal, the page cache bin was responsible for rendered output of a whole page.
Consequently, the chance of having to rebuild a whole page in Drupal 8 is far lower than in previous versions, because the cache render bin will contain some blocks already available for certain pages - for example a copyright block in your footer.
Nevertheless, having to rebuild the whole render cache from scratch on a high-traffic website can result in a lot of insert query statements for MySQL. This forms a potential performance bottleneck.
Why use Memcache?
Sometimes you need to rebuild the cache. Doing this on large sites with a lot of real-time visitors can lead to a lock timeout of MySQL, because the cache tables are locked by the cache rebuild function. This means that your database is unable to process the cache sets queries in time and in worst case resulting into a down time of your website.
Using Memcache allows you to directly offload cache bins into RAM, which makes cache sets, speeding up the cache along the way and allowing MySQL more breathing space.
How to install Memcache?
Before you can connect to memcache, you need to be sure that you have a memcache server up and running. You can find a lot of tutorials how to do this for your distribution, but if you use MAMP PRO 4 you can simple spin the memcache server up. By default, memcache will be running on port 11211.
When you have the memcache server specifications, host IP and port you need to download and install the Memcache module, available here: https://www.drupal.org/project/memcache
This module is currently in alpha3 stage and ready to be used in production sites.
Once you have installed the module, it should automatically connect to memcache using the default settings. This means that the memcache server is running on localhost and listening on port 11211. If your server is running on a different server or listening on another port you need to modify the connection by changing the following line in your settings.php.
$settings['memcache']['servers'] = ['127.0.0.1:11211' => 'default'];
Once you have installed memcache and have made the necessary changes to the settings.php file to connect to the memcache service, you need to configure Drupal so it uses the Memcache cache back end instead of the default Drupal cache back end. This can be done globally.
$settings['cache']['default'] = 'cache.backend.memcache';
However, doing so is not recommended because it cannot be guaranteed that all contrib modules only perform simple GET and SET queries on cache tables. In Drupal 7, for example, the form caching bin could not be offloaded to Memcache, because it can happen that the cache key gets overwritten with something else resulting in a cache miss for specific form cache entries.
Therefore it is recommended to always check if the cache bin is only used to store cache entries and to fetch them later on while not depending on it to be in cache.
Putting cache_render and cache_dynamic_page_cache into memcache is the safest and most beneficial configuration: the larger your site, the more queries those tables endure. Setting up those specific bins to use Memcache can be done with the following lines in settings.php.
$settings['cache']['bins']['render'] = 'cache.backend.memcache'; $settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.memcache';
How does it work?
To be able to test your setup and finetune Memcache, you should know how Memcache works. As explained before, we are telling Drupal to use the cache.backend.memcache service as cache back end. This Service is defined by the Memcache module and implements like any other cache back end the CacheBackendInterface.This interface is used to define a cache back end and forces classes to implement the necessary cache get, set, delete, invalidate, etc. functions.
When the memcache service sets a cache entry, it stores this as a permanent item in Memcache, because validation is always checked in cache get.
Invalidation of items is done by setting the timestamp in the past. The entry will stay available in RAM, but when the service tries to load it it will detect it as an invalid entry. This allows Drupal to recreate the entry, which will then overwrite the cache entry in Memcache.
Conclusion: when you clear all cache with Memcache installed, you will not remove all keys in Memcache but simple invalidate them by setting them with an expiration time in the past.
Optimizing your Memcache setup
Simply using Memcache will not always mean that your site will be faster. Depending on the size of your website and the amount of traffic, you will need to allocate more RAM to Memcache.
How best to define this amount? If you know how much data is currently cached in MySQL, this can help to summarize the sizes of all cache tables and check how much of these tables are then configured to go into Memcache.
Let me give an example: consider a 3GB cache_render table and a 1GB cache_dynamic_page_cache table, resulting in 4GB of data that would be offloaded to Memcache. Starting with a 4GB RAM setup for Memcache would give you a good start.
But how can you check if this setup is sufficient? There are a few simple rules to check if you have assigned sufficient -or perhaps too much - RAM to Memcache.
- If your evictions are increasing, meaning that memcache is overwriting keys to make space. And your hit rate is lower than 90% and dropping, you should allocate more memory.
- If your evictions are 0 but the hit rate is still low, you should review your caching logic. You are probably flushing caches to often or your cached data is not reused, meaning that your cache contexts are too wide.
- If your evictions is at 0 and your hit rate is 90 and higher, and the written bytes in memcache is lower than the allocated RAM, you can reduce the amount of RAM allocated to Memcache.
It is very important that you never assign more RAM than available. If your server needs to start swapping, the performance will drop significantly.
If you are considering using memcache for Drupal, you need to think a few things through in advance:
- Which cache bins will be offloaded into Memcache? Only offload cache tables that do not depend on an cache entry.
- Does the site has a lot of traffic and a lot of content? This will result in larger render cache tables.
- The amount of RAM allocated to Memcache, depending on the amount available on your server and the size of the cache bins you offloaded to Memcache.
Also keep in mind that the allocation of RAM for Memcache is not a fixed configuration. When your website grows, the cache size grows with it. This implies that the amount of necessary RAM will also increase.
We hope this blog post has been useful! Check our training page for more info about our Drupal training sessions for developers and webmasters.