Getting #2,000 requests per second without varnish

Getting #2,000 requests per second without varnish

Let's Rock

Now that Varnish is finally "the free version of a propietary software", it's time to look somewhere else, and the answer is right in front of our noses. When the word pripietary starts to appear, let's stick to the big guys. If you want to know how to get #2,000 requests per second without depending on anything else but your current webserver (yes, the same one you are using to serve your pages, no need to setup anything else here) then keep on reading.

Having quite an extensive background on Windows ASP.Net development, here at we knew that since IIS 7 we have the powerful IIS Output Caching.

Being IIS and ASP .Net Microsoft technologies, IIS Output Caching was desgined to be consumed from within ASP applications and we had never made the effort to see how this could be integrated into PHP. 

Output caching is setup in your Web.config file (or through the UI):

Here you can configure:

  • File name extensions: the file extensions that who's output will be cached. This can be static resources such as images, or dynamic pages like .aspx or .php.
  • User-mode caching: to cache the output in user mode.
  • Kernel-mode caching: to cache the output in kernel mode.

Because we want to cache dynamically generated output, using file change notifications to expire content makes no sense and we should stick to time-based expirations. Not the best, but useful under heavy load.

The big problem here is to decide what criteria are we going to use to tell if two requests should be served the same content or not. The UI only offers two possiblities: query string variables and headers. None of them gives us the fine grained control we need. Of course the people at Microsoft knew that, and opened the door (not through the UI) of a having a custom "varyByCustomString" setting in the Web.config that allows you to implement custom logic inside your ASP application.

Unluckily for us, we couldn't come up with a way of using the varyByCustom in a PHP application (we even thought of implementing an ASP handler that would do this job and then delegate it to PHP, but looks like you can only delegate back to managed handlers).

So we ended up with this simple configuration:

<add extension=".php" policy="CacheForTimePeriod" kernelCachePolicy="CacheForTimePeriod" duration="00:00:10" varyByHeaders="User-Agent, Cookie" varyByQueryString="*" />

Let's Apache Benchmark a vanilla Drupal installation with and without output caching (Page Caching turned on inside Drupal!).

Without Ouput Caching (#212 Requests per second):

With Output Caching (#1990 Requests per second):

That's a 10 time fold improvement in Requests per second, over a not so bad base 212 Requests per second without output caching. This is being run on a development environment where both database and web server are running on the same box.

Final Words

The caching strategy proposed here is extremely easy to setup (no need for external stuff....), and gives you reasonable control on what is being cached and how. We miss the ability to have a more fine grained control on how the caching works as you would have in ASP .Net applications.

Anyways, this setup will suffice most situations and yields extremely good results. So if you are using IIS with middle sized projects (< #2,000 RPS) and your application can work properly using the caching configuration here described, you are more than good to go without the need of using an external caching application (don't take that seriously, you should always use a CDN but that is another story).

IIS Output caching is far more complex than what the scope of this article could cover, but I've given you some perfromance figures and an easy to setup starting point.




Thanks for the article. I discovered wincache recently as well but we are not getting those page loads you mentioned. What does your application pool settings look like? Were you running on 2012 server?



Because those numbers belong to a parallel request test they depend a lot on your hardware and are thus quite missleading.

I now run all tests with sequential requests which are better and more reliable indication of what is going on. Expect at least 1/20th of those numbers when running sequential without output caching (aprox 15RPS) and more or less unchanged with output caching (just a guess).

To get the fastest RPS out of Drupal without any external system, turn on page caching and use this in your settings.php:

$conf['page_cache_without_database'] = TRUE;

$conf['page_cache_invoke_hooks'] = FALSE;

Then route the page cache directly to Wincache. That is the fastest you could ever get, because that's in-memory page caching with minimal bootstraping. If your site is big then use Couchbase as the storage backend for page cache.

Add new comment

By: david_garcia Sunday, February 8, 2015 - 00:00