Wednesday 18 January 2012

Drupal and Nginx

I'm responsible for this website which is hosted on a Linode vps. Recently we've switched from using Apache to Nginx. In this post, why and what we've found has happened as a result.

I've found Linode to be excellent. Their prices and service are good, the basic linode offers plenty of disk space and data transfer. They're also fast.

However having read about how fast and well designed the Linode system was, we were seeing very poor performance on our Drupal site. There can be lots of reasons for Drupal to perform badly; it's complicated, makes heavy use of MySQL queries and can be significantly extended with extra modules. According to my understanding, each module used increases the amount of memory used by php on the server. We have quite a lot of modules, our site makes heavy use of views and I'm sure could be optimised to be more efficient, but I still wasn't happy with the server's performance.

We have the entry level Linode with 512MB of RAM. By modern standards this isn't very much, but should be enough for a Linux server to host the Drupal site in question. However we were seeing significant performance lags and more drastically there were times when the server would hit the swap file, start to thrash and become completely unreachable.

Apache seemed to be the bottleneck. As it spawned child processes to handle multiple connections, each one using as much memory as php needed to render the site, we were running out of RAM. Some simple tests with browsermob found the server could only handle 14 concurrent connections before hitting the swap file and starting to thrash.

Foolishly guilty of sticking with Apache's default config on Ubuntu server, I spent a bit of time optimising the config and could get Apache to a state where it didn't exceed the server's available memory but then it still couldn't handle more than 14 concurrent connections. Also, the data transfer to browsermob peaked at about 6MB, averaging closer to 4MB.

So, bring on Nginx. I've used Nginx with PHP-FPM. This runs php as a separate service. I installed both of these with aptitude.

Config is reasonably straight forward, but Nginx doesn't have the same dynamic config approach as Apache. So .htaccess files don't do anything. For most users this is better, as it reduces the need to access the file system to consult these files for each page request. For URL rewriting to work the site config for Nginx has to be right. It wasn't difficult to find a reference config for drupal. I used this one.

The end result...

Blistering speed compared to Apache. The same browsermob tests report up to 60MB throughput from our server with an average of 57MB. Yes... 10x the speed. Visiting the site at our office over a fast, but domestic ADSL connection it feels like it's hosted locally. I can't overstate how much more responsive the site is. For one user on a development system you probably won't notice, but for a busy site the difference is significant.

Stable memory usage and high user concurrency. Nginx doesn't use more RAM for more connections. Using the free browsermob account the load test ramps up to 25 concurrent users with no problems at all. I've played with Siege running locally and can achieve over 2000 requests per second, vs apache scoring about 550.

So Nginx with php-fpm seems to be faster and more efficient than Apache, but where it really excels is serving static content. Serving up a static rendering of our site's homepage our server can now handle over 4500 requests per second vs Apache's 600.

I've been playing around with the drupal module Boost. It doesn't currently seem to work properly with Drupal7 (creates but doesn't clear the cache) but the performance benefit for busy sites with lots of anonymous users is dramatic. Boost creates a static html rendering of the drupal site. The correct Nginx rewrite config means it serves up the cache without having to touch php or mysql. The result is incredibly fast. Worth noting that normal drupal caching uses the database. It still helps performance but php and mysql remain a bottleneck.

Of course there is a halfway house, and you'll find lots of documentation for it, and that's to use Nginx as a reverse proxy for apache. In combination with Boost this would offer a very significant performance increase for sites with lots of anonymous users as Nginx can serve the static cache directly when it's present. Personally this felt like increased complexity. I decided not go down this well trodden path because we were short of RAM. Running more services didn't seem to be the best way to go.

So that's what we've done, and I'm very happy with the results.

No comments:

Post a Comment