# Memory-lean nginx on a VPS

May 8, 2007

I spent this weekend testing and installing nginx and I have said Adios to Apache! Let me tell you why I have done that.

I am running this blog on a slicehost.com 256Mb Xen VPS, using WordPress. I have been using Apache 2.2 for almost a year now without any problems. But recently I deployed a little Ruby on Rails application using mongrel for my wife's business, and then suddenly I ran out of memory. Each Apache worker was easily taking 15 to 20Mb, even with a really cut-down configuration and built on Gentoo. With three Mongrel backends and the MySQL server I was starting to swap to disk.

I tried FastCGI instead of Mongrel, but it only cut down from about 50Mb to 40Mb for each process, not enough really to make a difference. I had to trim the fat out of the web server.

So about dropping Apache. First I considered Pound as a load balancer, but given that I would also still need a web server for static content in Rails (not wanting to serve that with Mongrel) I decided to look for alternatives.

Lighty and FastCGI tests did not even complete, so I gave up on Lighty. The FastCGI processes were becoming Zombie for some unknown reason.

Then I tried nginx. I have 5 workers, each consuming around 3Mb. Wow ... I call that Spring savings.

nginx is sending all blog traffic to a couple of php-cgi handlers. I tried both TCP and Unix sockets, but went for TCP since I was getting dropped requests and stalling processes for Unix sockets. php-cgi is not very fast, but it's stable and it has a reduced memory footprint.

Then nginx is acting as a reverse proxy and balancing across 3 Mongrels. I tried also FastCGI, but again it's not stable.

And man is this thing flying or what!? I have enough memory spare to make MySQL happy. Plus I am caching a lot of Rails generated content that nginx serves happily.

Now, some numbers from Apache Benchmark (running on Linux 2.6.16.29-xen #3 SMP, x86_64 Dual Core AMD Opteron(tm) Processor 265 AuthenticAMD GNU/Linux, Xen host with 256Mb):
nginx + pure HTML content:

 Concurrency Level: 50 Time taken for tests: 0.96657 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Requests per second: 10345.86 [#/sec] (mean) Time per request: 4.833 [ms] (mean) Time per request: 0.097 [ms] (mean, across all concurrent requests) 

 Concurrency Level: 50 Time taken for tests: 192.387414 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Requests per second: 5.20 [#/sec] (mean) Time per request: 9619.371 [ms] (mean) Time per request: 192.387 [ms] (mean, across all concurrent requests) 
 Concurrency Level: 50 Time taken for tests: 8.290116 seconds Complete requests: 1000 Failed requests: 0 Write errors: 0 Requests per second: 120.63 [#/sec] (mean) Time per request: 414.506 [ms] (mean) Time per request: 8.290 [ms] (mean, across all concurrent requests)