On one of our Drupal sites, we had an interesting problem. While the site happily handled up to 600 requests/second (on a 4 Gig, 4 CPU system) with the built-in Drupal page caching turned on, if an editor updated content on the front page, the site would hang for more than 30 seconds. We were simply getting too many requests in the period of time that the page cache was being updated. In extreme cases, the requests clogged the database, caused the system load to skyrocket, and users were getting timeout errors.
One simple solution was to lower the number of Apache MaxClients (in httpd.conf) to 10 (down from 150). This allowed a small number of requests to hit the database while the rest of the requests waited. Since the database wasn’t beleaguered, it responded quickly, causing the front page cache to be rapidly restored. The problem is that if MaxClients is unusually low, a small number of searches or other longrequests could clog up the site (an unintentional denial-of-service).
What we really wanted was that when the front page cache expired, to have one request update the cache while the other requests get the old version until the new one is ready. This way in the couple of seconds that the front page is being updated, the couple hundred front page requests that occur during this time will happily get the old version and continue on their merry way.
We accomplished this by updating Drupal’s cache functionality (includes/cache.inc) to do the following:
- In cache_get() and cache_clear_all(), when items are expire, instead of directly deleting them, we use the created time to record the current time as a negative value (so that we still know it is expired but keep track of when it expired), and delete those items that have expired more than an hour ago (since they’re not high traffic pages)
- In cache_get(), when we are asked to retrieve a page that has a cache entry that expired, we temporarily set the created time to 10 seconds in the future, but return 0 for the current request so that it updates the cache. This allows other requests to get the old cache copy while the current request updates the cache to the latest version.
To incorporate this capability to your site (please back up you cache.inc and unit test your installation), download cache.inc
or apply cache.inc.patch
. Also please make sure that page caching is turned on and set minimum cache lifetime to a non-zero value (say 10 minutes).
With this update, we are able to maintain 600 requests/second even as the home page is updated. I hope it helps you!