Drupal 7 Performance: Memcache vs. Filecache

Pig racing

If you've worked on a few Drupal sites, no doubt you've run into one of those horrendously slow sites. To call it a pig, would be unfair. Pigs can actually be quite fast. (http://en.wikipedia.org/wiki/Pig_racing)

Image Credit: Calibas

There are a few common speed enhancements. To start with, you can make sure that Drupal's native database caching is turned on and Javascript and CSS aggregation are enabled (IE. your basic settings under admin/config/development/performance.) If you have time and resources there's Nginx, Varnish, APC and Memcache—these are general-purpose web technology and all require a degree of configuration. They may not be possible in all hosting situations.

One other option that is specific to Drupal is Filecache (http://drupal.org/project/filecache). While Drupal core stores cache information to the database, filecache will store it directly in the filesystem. The idea here is that the database is already pretty busy and has some overhead that's not really necessary for storing cache. Filecache avoids that complexity and as a result can make your site faster.

Memcache vs. Filecache

I thought I would compare Filecache to its big brother to see how they stack up. To do so, I set up a server at Digital Ocean—a 2GB virtual server with 2 cores and 40GB SSDs.

The Setup

I wanted a fairly standard setup of LAMP + Memcache running on Ubuntu 12.04 32-bit. This gave me a chance to work a bit more with Chef Solo to provision the server. I'll share my experience with using Chef in an upcoming post.

The Drupal site itself was basically just core Drupal, plus Views and the Memcache and Filecache modules. I also included APC for good measure. I used Devel Generate (part of the Devel module http://drupal.org/projects/devel) to generate 500 random nodes. Using Views, I created a view that was a clone of the default "frontpage" view, with 100 nodes per page. The result was a fairly long page or about 190KB. All caching options for Drupal and for the view were enabled.

Benchmarking

I used ApacheBench to run many simultaneous requests to the server. It is fairly basic in what it can do, but it does give fairly comprehensive statistics. I ran the ApacheBench command

The ApacheBench command looks like this:

ab -n 500 -c 30 http://example.com/mypage

The -n option is the number of total requests. The -c option is concurrency—in other words, the maximum number of requests that could be sent at the same time. I did my tests with 500 total requests and concurrency of 1, 30 and 50. The median response time was recorded for each test. I ran each test several times to confirm the results.

Surprising Results

The most surprising thing I found was that Memcache actually slowed things down. First, I had to check that it actually was working, so I enabled memcache_admin (part of the Drupal Memcache module) to confirm that I actually was getting cache hits. I was. Next, I increased the memory used by memcache from 64MB to 256MB. No difference. Finally, I noticed that memcache logging was enabled, so I commented out that and the "verbose" flag. This did make a bit of an improvement, but not a great one. For my simple test site, Memcache was not helping.

Results: Core Drupal Cache

Median response times for the core Drupal database caching:

Concurrency 1: 5ms
Concurrency 30: 89ms
Concurrency 50: 156ms

Not bad... That little VPS performs well. The main advantage of the core caching is that it is easy to set up... just a few checkboxes.

Results: Memcache

The best I was able to wring out of memcache was still not better than core Drupal.

Concurrency 1: 5ms
Concurrency 30: 101ms
Concurrency 50: 166ms

Memcache is the most difficult to set up. You have to install the memcache daemon itself, you need a PHP mod installed and you have to add a few lines to your site's settings.php file. I have to assume I'd get a benefit in a more complex site, with a load that was more like real-world users.

Results: Filecache

The median request times for Filecache were the best of the lot.

Concurrency 1: 5ms
Concurrency 30: 81ms
Concurrency 50: 134ms

Filecache is the winner here. In this test it did marginally better than core, but I've seen about 35% knocked off the response times of a complex Drupal site. Filecache is also very easy to install... just install the module and add two lines to the settings.php file.

Conclusions

Easiest to install is core Drupal, with Filecache coming a close second. Memcache is not daunting, but it will definitely take some time to install and tune.

Fastest is Filecache, while Memcache was surprisingly slower than the standard core Drupal caching.

I'll be going with Filecache in most situations where the web performance stack is not predetermined and I don't have a lot of time to fuss with the ideal caching strategy.

Things to Consider

I wouldn't consider my test to be entirely scientific. Off the top of my head, I can think of several things I'd want to control better:

  • I did my testing a VPS, so I don't have control over the activity from other servers sharing the hardware.
  • Digital Ocean uses SSD which might give an advantage to filecache that it wouldn't have on a conventional hard drive. SSDs are still much slower than RAM, however.
  • ApacheBench only requests the page... the other resources such as images, Javascript and CSS are not retrieved. As a whole, it doesn't give a very accurate simulation of real-world users.

Credits

Here's some articles that were helpful in getting things working with Chef and Memcache:

Comments

It does not really surprise me, if you have tested with a very small database (very small may contain thousands of nodes): having only one TCP connection (MySQL) instead of two (+Memcache) will be faster: MySQL will fit everything in RAM and maximise the query cache. But as your site grows, database will become the bottleneck and won't scale as easily as Memcache, then they are great chances the figures will be the exact opposite of what you measured. Considering file cache, if your filesystem is fast enough, it will be very efficient, and you will benefit from the filesystem cache, but it's a not a viable solution if you need to scale your PHP frontends horizontally and if you end up duplicating the files on every frontend. Worse will it be when you'll start to use network file systems.

I just want to point out for simple nodes (title + body only) on a simple site (1 view), this is expected. If you have nodes with 20+ fields, a simple node_load() can generate many SQL queries, and if you have 20+ nodes on the one page, then things start getting really messy.

If however you deploy memcache + entitycache, the combination is magical for larger more complex sites, reducing SQL queries by the hundreds, and effectively making node_load() as close to free as possible.

Just ensure your memcache RAM limit is not maxed out, else memcache will drop items from it.

I wrote a blog post a while back with real world performance gains with entitycache - http://www.pixelite.co.nz/article/using-entitycache-speed-your-drupal-site have a read.

@ wiifm thanks for adding that. I'd like to try a more realistic test. Other than trivial benchmarks like this, I think Apachebench hits limits of usefulness. I'm planning to use siege and hitting a list of URLs that would be a better simulation of real world traffic. Hammering away at a single page is certainly not very realistic.

More complex content will need to be part of the testing as well.

... if you have enough memory in your server: put its .ht.filecache directory in a RAM tmpfs disk, so you will have the "fastest" possible disk.

On Ubuntu:

sudo mount -t tmpfs -o size=32M,mode=0777 tmpfs /<drupal_root>/sites/default/files/.ht.filecache

You can see how much storage FileCache is using:

df -h

Even you can resize it on the fly:

sudo mount -o remount,size=64M /<drupal_root>/sites/default/files/.ht.filecache

And finally do not forget to put the first command inside /etc/fstab to create the volume everytime your server boots.

Add new comment