APC, Varnish, Memcache, and Caching Beyond Drupal Core

By:

on

November 28, 2013

Drupal is a powerful web application framework and Content Management System. It is capable of serving high volume websites at incredible speeds. But a poorly configured cache setting can grind your web site to a halt, leaving impatient visitors waiting for pages. Excessive page load times will even drive some visitors away with the impression that your site has gone down. The most common recommendations for Drupal 7.x caching beyond the defaults provided in Core are APC, Varnish, and Memcache. Each plays its own specific role, and requires its own configuration settings to be reviewed by the site administrator. As always, the best settings for one site may not be appropriate at all for another. Consider the differences between a site designed for anonymous browsing and information distribution versus a site designed to be used entirely by authenticated users with dynamic reports generated on each page load. Clearly the first site would benefit greatly from a front-end page cache such as Varnish while the second could run into issues by serving cached content when a page should be regenerated. So what are APC, Varnish and Memcache and what do they do?

Varnish

Web site: https://www.varnish-cache.org/ Drupal module: https://drupal.org/project/varnish

Varnish is a front-end "page cache". It can sit in front of any web application and acts as an intermediary between the site vistors and the back-end web server, regardless of the back-end application. When Varnish receives a page request from a web browser, it checks its own internal cache first to see if it has a valid copy of that page's data. If it can serve a copy from its cache, the web application server is never invoked. This has serious advantages for a brochure/pamphlet-type site where content is largely static. If Varnish does not have a copy of that page yet, or if its copy has "expired", Varnish will contact the web application server to get an updated copy of that page and add it to its cache. The most basic Varnish configuration is to tell Varnish where the web server(s) for your application are, so that it can request page data (including any HTML, XML, CSS, Javascript, image files, etc.). On any typical modern GNU/Linux system, this is done with the following snippet of code in the configuration file /etc/varnish/default.vcl:

backend default {
.host = "127.0.0.1";
.port = "8000";
}

This tells Varnish that your back-end web application server can be reached at 127.0.0.1:8000 so this is where Varnish will ask for pages it does not have cached. The server listening at that socket may be Apache, nginx, Microsoft IIS, or any other HTTP server. Varnish doesn't care. The Varnish Control Terminal is a method by which the back-end server can communicate with Varnish in order to affect the cache. For example, if the Drupal Varnish module is configured correctly, it can tell Varnish to expire a page from its cache when that page is updated through Drupal, so that new visitors to the site get the new content immediately, instead of waiting for Varnish to expire the page as per its default page expiration settings. In order to lock down this management of Varnish's cached data, the Control Terminal is protected by a "secret key", usually located in /etc/varnish/secret. In order for the Drupal Varnish module to function correctly, some settings need to be configured. Aside from the Control Terminal secret key, Drupal should also be told the IP address of the Varnish server in order to extract the actual visitor's IP address. Otherwise all your page accesses will appear to come from the Varnish server. The default header added by Varnish for this is X-FORWARDED-FOR, but this can be configured however you please. You will also need to make sure you have the default Drupal cache settings "Cache pages for anonymous users" turned on, and you should consider the use of a "Minimum cache lifetime". Your choice for this setting will depend on your site's usage and traffic. Some administrators may wish to have a long cache lifetime to improve performance, while content editors may prefer a shorter cache lifetime to avoid the serving of stale content.

APC: Alternative PHP Cache

Web site: http://php.net/manual/en/book.apc.php Drupal module: https://drupal.org/project/apc

Alternative PHP Cache is designed to store blocks of PHP code in an executable format. Drupal has many, many PHP files included in every page load, and re-reading each of these files each time a page is requested can cause a very large amount of disk I/O and CPU time. Files that do not change from page load to page load, including Drupal Core and all of your contributed module code, can safely be stored in RAM for fast retrieval. It is much faster for a computer to check a last modified date of a file to see if it has been changed, rather than reload and recompile that file, perhaps hundreds or thousands of times per second on a high traffic site. But be warned: A poorly configured cache can cause the opposite effect! When we first deployed APC with the default settings, our site seemed to perform SLOWER. Most versions of APC come with a handy PHP script, apc.php which can provide a summary of the effectiveness of the APC cache in a user-friendly graphical display. It was quickly discovered that the APC cache with default settings was always full, causing it to constantly expire data to fit new data in. The result was that it was never able to retrieve cached PHP code, since by the time page load #2 began, the first pieces of page load #1 were thrown out! Increasing the APC RAM allocation inside apc.ini to a sufficiently large value caused a dramatic decrease in page load times. Another caveat of APC is that it uses separate RAM segments when PHP is invoked from the Command Line Interface (CLI) versus PHP as invoked by Apache. For Drush users, this means that a 'drush cc all' is incapable of clearing the APC cache, causing a spew of warning messages, and the possibility of uncleared caches. This has been discussed at length on drupal.org.

Memcache

Web site (memcached): http://memcached.org/ Web site (PECL memcache extension): http://pecl.php.net/package/memcache Drupal module: https://drupal.org/project/memcache

Memcache helps reduce database load by caching DB objects in RAM. It requires a 'memcached' daemon/service (first link above), which will do the actual RAM storage of objects, as well as the PHP extension to use this service. There are two separate PHP extensions available, 'memcache' and 'memcached'. You can read about the differences between the two, or just pick one and try it out.

Which to use, and When?

General recommendations for Drupal 7.x site performance are to use all three! Ultimately this depends on your site's requirements and server configuration.

  • Are you finding that anonymous page loads, including image files, are slow? Install Varnish and allow it to store these in RAM.
  • Is Apache (or other web server) expending excessive CPU time executing PHP code? APC will alleviate this for you.
  • Is your database server suffering too many connections and excessive query load times? Memcache can take some of this load off your database server by caching queries and their responses for faster returns to the front-end application.

It is always a good idea to monitor your changes when setting up new services such as these. As mentioned, a poorly configured cache can give the opposite results, increasing page load times, and driving visitors away. And today's cache settings may not be appropriate a year from now, when your site has exploded in popularity! It's good to check on these settings periodically to ensure they are continuing to provide their desired benefit.

Summary Of Drupal Settings

Although many of the settings for these Drupal modules can be managed using the admin UI, these settings can be placed into your site's settings.php file. Note that the module will need to be enabled despite the inclusion of the 'cache_backends' array.

$conf['cache_backends'] = array();

## Varnish
# http://drupal.org/project/varnish
# Add Varnish as the page cache handler.
$conf['cache_backends'][] = 'sites/all/modules/contrib/varnish/varnish.cache.inc';
$conf['cache_class_cache_page'] = 'VarnishCache';
$conf['reverse_proxy'] = TRUE;
$conf['reverse_proxy_addresses'] = array('127.0.0.1');
$conf['varnish_version'] = '3';
# Bypass Drupal bootstrap for anonymous users so that Drupal sets max-age > 0
$conf['page_cache_invoke_hooks'] = FALSE;
$conf['varnish_control_key'] = 'CONTENTS-OF-ETC-VARNISH-SECRET';
$conf['varnish_control_terminal'] = 'localhost:6082';

## APC
# http://drupalcode.org/project/apc.git/blob_plain/refs/heads/7.x-1.x:/REA...
$conf['cache_backends'][] = 'sites/all/modules/contrib/apc/drupal_apc_cache.inc';
$conf['cache_class_cache'] = 'DrupalAPCCache';
$conf['cache_class_cache_bootstrap'] = 'DrupalAPCCache';

## memcache
$conf['cache_backends'][] = 'sites/all/modules/contrib/memcache/memcache.inc';
$conf['cache_default_class'] = 'MemCacheDrupal';
$conf['memcache_servers'] = array('localhost:11211' => 'default');
$conf['memcache_bins'] = array('cache' => 'default');
# "If you want to have multiple Drupal installations share memcached instances,
# you need to include a unique prefix for each Drupal installation in the $conf
# array of settings.php:"
$conf['memcache_key_prefix'] = "UniqueSitePrefix";
# "Make sure the following line also exists, to ensure that the special
# cache_form bin is assigned to non-volatile storage:"
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';

Comments

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.