Drupal caching with Cache Router

Recommend (1327)

I have been working on upgrading the caching contrib modules to Drupal 6 and started to notice some patterns and duplicated code, which led me to think Drupal's approach to caching in general. We currently have a fairly limited API for caching, but we have a magic bullet that helps us overcome some of these weaknesses: the cache.inc override system. Anyone who has spent time on large production sites knows that one of the easiest ways to see better performance on your Drupal system is to use one of the existing cache mechanisms that I spoke about at Drupalcon Boston.

In Drupal 6, we saw some great improvements in performance with the addition of Block Cache in core, and the cache serialization patch that allows us to override Drupal's default database caching with simple, drop-in cache replacements such as memcached (pronounced mem-cash-dee), APC and XCache. But there's an inherint problem here. "What do I do if I don't have the ability to install memcached?"

This actually becomes quite an issue because memcached configurations vary widly and won't yield the performance you expect if you don't have the ability to run multiple processes and set up one instance per bin. Also, what do you do if you're running a huge site and would rather cache at the file level, but still use memcached for various global caches?

Solution

My solution to this problem is the Cache Router.

From the project page:

"CacheRouter is a caching system for Drupal allowing you to assign individual cache tables to specific cache technology. CacheRouter also utilizes the page_fast_cache part of Drupal in order to reduce the amount of resources needed for serving pages to anonymous users."

What this means in plain english is that you now can install ONE module that will allow you to utilize any of the current cache override strategies.

This can be particularly helpful in the following scenarios:

  1. Shared Hosting
  2. Dedicated Server or VPS hosting
  3. Multi-Server dedicated hosting

Shared Hosting

As anyone who has used shared hosting knows, you have very little control over your environment. In fact the only control you usually have is to choose the host that has the environment that you would set up if it were yours. Usually you are lucky if you get on a not-too-overloaded host with a recent version of the LAMP stack.

For this environment, you could use file based caching to save the day. File based caching is the 3rd fastest caching mechanism in my testing. My version of file caching is based on the great work of Jeremy Andrews, Matt Westgate and Moshe Weitzman in the fastpath_fscache project.

To enable file caching with Cache Router, you would enable CacheRouter module, then add the following lines to your settings.php:

$conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
$conf['cacherouter'] = array(
'default' => array(
'engine' => 'file',
),
);
 

Dedicated Server or VPS Hosting

One of the ways growing sites deal with the traffic is to lease a dedicated server or use VPS servers. This gives the site administrator a great amount of flexibility and control over their environment. The main downside to this is that now you have a single point of failure, but the cost savings usually outweighs the risk.

In this environment, you will hopefully be running the latest stable version of the LAMP stack, including Apache 2.2.x, and PHP 5.2+. If you are a bit savvy and have read some technical articles, you have probably heard of opcode caching and have made the decision to run eAccelerator, APC or XCache.

At this point, your site seems to be running smoothly, but occasionally it is Dugg or gets hit with a traffic spike and your database thrashes; at which point, you pull your hair out until things calm back down. CacheRouter can help with this setup also. However you have many more options in this situation and thus, have some decisions to make.

First, you must choose an opcode cache that has variable caching available. The two current options are APC and XCache. At the time of this writing (APC v3.0.18, XCache 1.2.2), APC seems to be the clear leader in stability, but XCache may work for you as well.

While you can still use file based caching if you please, it should be noted that using the variable cache in these projects seems to be faster in my testing. You also could install memcached, but the shortest road to high-performance will likely be using the opcode cache.

To configure APC, you would install the CacheRouter module, enable it, and add the following to your settings.php:

 

$conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
$conf['cacherouter'] = array(
'default' => array(
'engine' => 'apc',
),
);

To configure XCache, you would install the CacheRouter module, enable it, and add the following to your settings.php:

 

$conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
$conf['cacherouter'] = array(
'default' => array(
'engine' => 'xcache',
),
);
 

Multi-Server Dedicated Hosting

When you are dealing with a very large site and getting multiple millions of visitors every month, you will inevitably come to a decision of scaling up, or scaling out. Scaling up means buying a bigger box, which gets very expensive very quickly. There area ton of reasons to use multi-server hosting, not the least of which is for redundancy for high-availability. However, this setup doesn't come cheap either and it can often be complex to configure and maintain.

In a typical multi-server setup, you will have a couple (few, hundred, etc) web nodes, and a database setup of either a single server or multiple servers with redundancy. I will save the specifics on how to setup this environment for another post. There is already a ton of information out there about this type of scaling, and I would highly recommend checking out Cal Henderson's book on the subject titled "Building Scalable Websites."

In this setup, memcache or a mix of memcache and other caching strategies works best. Here's how to set up examples of both scenarios.

To configure memcache, enable the CacheRouter module, and add the following to your settings.php:

$conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
$conf['cacherouter'] = array(
'default' => array(
'engine' => 'memcache',
'server' => array('192.168.0.100:11211', '192.168.0.100:11212'),
'shared' => TRUE,
'prefix' => 'prod',
),
);
  

To configure a mix and match setup, enable the CacheRouter module and add the following to your settings.php:

$conf['cache_inc'] = './sites/all/modules/cacherouter/cacherouter.inc';
$conf['cacherouter'] = array(
'default' => array(
'engine' => 'memcache',
'server' => array('192.168.0.100:11211', '192.168.0.100:11212'),
'shared' => TRUE,
'prefix' => 'prod',
),
'cache_page' => array(
'engine' => 'file',
),
);

 

For the last example, you can add as many bins/tables as you want; some other examples, might be "cache_views", "cache", "cache_block", etc. If you have any custom caching code in your Drupal web application, you might have some additional bins defined as well.

If you are using memcache as a "shared" bin, it will keep track of each item so that the flush only clears the bin and not the entire process This will allow to do things like use just one large memcache process. If you set "shared" to false, the module assumes that you have assigned one memcache process to each bin.

Summary

I hope this helps you with your journey into high-performance Drupal. For additional resources, please go to the High Performance Group, and check out the other great modules / developers that are turning Drupal into a high performance machine.

Just remember that there is never a silver bullet that will fix everything. This module will help obtain some performance improvements, but often times it takes a seasoned Drupal professional to figure out where your bottleneck is.