Drupal - Nginx vs Apache - Are there any actual usage comparisons and statistcs out there?

Strictly speaking, this doesn't answer the question you are asking. I'm hoping it's helpful anyway.

Apache/Nginx/Lighttpd/other web server. Does it matter which one I choose? In short, No.

The much much longer answer:

If, and only if, you have a very large percentage of your users being logged in, should you care at all about the performance of your web server. If your users are anonymous, any difference that you can theoretically derive from optimizing at that layers absolute pales compared to making your resources better cacheable. If your css files have proper cache headers on them, the UA won't even ask for them the second time. That matters. If you can cache your pages in Varnish or a similar software solution, then serving that page is a matter of making a hash-lookup, and then returning a large chunk of data directly from RAM. That matters. In both of these scenarios, the HTTP daemon is never even involved, PHP does not get invoked. Drupal does not bootstrap. No large set of modules must be loaded into RAM, no time consuming database queries are executed.

When you perform a full page load, from a cold cache, for a logged in user, on a complex page; a lot of things are going on. Yes, the web server is involved in dealing with the incoming request, setting some headers and passing the response back. But the time that takes, is not even relevant in the context of Drupal running a full bootstrap and outputting its response. There could be hundreds of database queries being executed. Highly complex logic in PHP is evaluated by the parser. Lots of modules are being loaded into RAM. Improving the performance of any of those things, are much more likely to make a serious contribution to performance.

For the sake of argument: Let's say you have spent a lot of time performance optimizing everything else.

  1. You run APC (Or Optimizer+) and the latest and fastest version of PHP.
  2. DB-queries are few.
  3. PHP logic has been reduced.
  4. You cache what you can in Varnish.
  5. You have re-structured your entire site so that you can cache a lot client side, and do lots of heavy lifting in ECMAScript.

If you have a lot of logged in users, and you've dealt with all of the above, then you can probably make a difference but performance tuning, or replacing your web server. However, guess what. Your site is so complex, and the usage patterns of your particular users, is unique. There is no generic answer. You will need to setup all different web servers behind a load balancer, and see how they behave, under your scenario.

The above was an attempt at logically reaching the conclusion that spending time performance optimizing the web server is likely a bad use of time. I would love to have someone pick holes in the above though, I would probably learn something new from it. :)

Some other notes:

  1. During the DrupalCon Copenhagen keynote, PHP creator Rasmus Lerdorf, using Nginx himself, speaking on the topic of Drupal performance, said "People always ask me about web servers ... it really doesn't matter, the web server is pretty much irrelevant". (Roughly at 26:30 in the video)
  2. Facebook has spent countless hours on writing Hiphop, a code base significantly larger than Drupal itself, for accelerating PHP-code by a "measly" 100%. I examined Hiphop with $ wc -l $(find . -type f | grep -v "^\.git" | grep -v "^\.hphp/third_party") | sort -nr | head -n1 and found it to consist of 1.512.481 lines of code. That's an absolutely insane amount of work put in to improving the speed of PHP. I'm guessing that's because the speed of PHP matters greatly to them.
  3. Did I mention that good caching is going to have a much greater effect that tuning the web server?
  4. With the release of Apache 2.4, Jim Jagielski basically claims that Apache 2.4 is faster than event based servers.
  5. I attented Drupal Performance and Scalability with The Dream Team, where just this question came up. All the answers about which to choose, was unrelated to performance. Things like "Which one do you already know how to configure", and "Which one will allow you to build the simplest technology stack", were among the reasons mentioned to pick on over the other. Performance did not enter the picture.

OK, although this question is already answered, I'm necromancing once more, primarily because I don't like the implications of these answers that it doesn't make a difference, and because as a web developer, I hate caching with a passion.

The difference between Apache and nginx is not that much "how fast they can serve a request" but how many requests they can serve on the same amount of hardware (especially with limited ressources), which is a somewhat different thing.

Apache is a process-based server. Meaning it forks a process for every request. Nginx is a event based server, meaning is uses an (asynchronous) event-loop instead of processes or threads.

And while a process-based server (like Apache) can perform more or less on par with an asynchronous event-based server (like nginx) under light loads, under heavier loads like for example 10'0000 simultaneous requests, nginx uses only a few megabytes of RAM, whereas Apache requires several hundred megabytes for the web server alone (not including the web application, which needs far more ressources itselfs), if it could do it at all.

So under heavier loads, you will see Apache consume far too much RAM, which unsurprisingly degrades performance significantly.

More significantly, a higher RAM consumption means that Apache is being able to serve less requests on the same hardware than nginx, which means Apache requires more hardware for the same amount of users, which means you have a higher TCO (total cost of ownership) with Apache than with nginx, which reduces your ROI (return on investment).

Total memory used by X concurrent connections (less is better)

Memory Usage

Requests that can be served per second at X concurrent connections on 1 set of hardware (more is better)

Requests per second

Source: ApacheBench, by dreamhost.com

See also this digital ocean writup.
Apparently, it depends on the Connection Handling Architecture you choose for Apache.


I switch from Apache to Nginx / PHP-FPM a few month ago.

I made some benchmarck with a drupal website, and test several use case. On a VPS server with 1 CPU and 512 Mo RAM

Drupal with only cache

Nginx

ab -n 100 -c 30 xxx
Server Software:        nginx
Document Path:          /
Document Length:        24902 bytes

Concurrency Level:      30
Time taken for tests:   2.775 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      2529500 bytes
HTML transferred:       2490200 bytes
Requests per second:    36.04 [#/sec] (mean)
Time per request:       832.394 [ms] (mean)
Time per request:       27.746 [ms] (mean, across all concurrent requests)
Transfer rate:          890.28 [Kbytes/sec] received


httperf --client=0/1 --server=xxx --port=80 --uri=/ --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=10
Maximum connect burst length: 1

Total: connections 100 requests 1000 replies 1000 test-duration 48.946 s

Connection rate: 2.0 conn/s (489.5 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 470.6 avg 489.5 max 522.2 median 488.5 stddev 9.5
Connection time [ms]: connect 0.2
Connection length [replies/conn]: 10.000

Request rate: 20.4 req/s (48.9 ms/req)
Request size [B]: 74.0

Reply rate [replies/s]: min 20.0 avg 20.4 max 20.8 stddev 0.2 (9 samples)
Reply time [ms]: response 46.8 transfer 2.1
Reply size [B]: header 450.0 content 24902.0 footer 2.0 (total 25354.0)
Reply status: 1xx=0 2xx=1000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 6.50 system 17.58 (user 13.3% system 35.9% total 49.2%)
Net I/O: 507.3 KB/s (4.2*10^6 bps)

Apache

ab -n 100 -c 30 xxx
Server Software:        Apache/2.2.16
Document Path:          /
Document Length:        24902 bytes

Concurrency Level:      30
Time taken for tests:   28.364 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      25346000 bytes
HTML transferred:       24902000 bytes
Requests per second:    35.26 [#/sec] (mean)
Time per request:       850.918 [ms] (mean)
Time per request:       28.364 [ms] (mean, across all concurrent requests)
Transfer rate:          872.66 [Kbytes/sec] received


httperf --client=0/1 --server=xxx --port=80 --uri=/ --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=10
Maximum connect burst length: 1

Total: connections 100 requests 1000 replies 1000 test-duration 52.261 s

Connection rate: 1.9 conn/s (522.6 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 499.0 avg 522.6 max 591.0 median 518.5 stddev 19.4
Connection time [ms]: connect 0.6
Connection length [replies/conn]: 10.000

Request rate: 19.1 req/s (52.3 ms/req)
Request size [B]: 74.0

Reply rate [replies/s]: min 18.2 avg 19.2 max 19.6 stddev 0.5 (10 samples)
Reply time [ms]: response 46.9 transfer 5.3
Reply size [B]: header 453.0 content 24902.0 footer 2.0 (total 25357.0)
Reply status: 1xx=0 2xx=1000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 6.80 system 18.88 (user 13.0% system 36.1% total 49.1%)
Net I/O: 475.2 KB/s (3.9*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Drupal with cache and boost

Nginx

ab -n 10000 -c 30 xxx
Server Software:        nginx
Document Path:          /
Document Length:        25002 bytes

Concurrency Level:      30
Time taken for tests:   2.275 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      253780000 bytes
HTML transferred:       250020000 bytes
Requests per second:    4395.52 [#/sec] (mean)
Time per request:       6.825 [ms] (mean)
Time per request:       0.228 [ms] (mean, across all concurrent requests)
Transfer rate:          108934.95 [Kbytes/sec] received


httperf --client=0/1 --server=xxx --port=80 --uri=/ --send-buffer=4096 --recv-buffer=16384 --num-conns=1000 --num-calls=30
Maximum connect burst length: 1

Total: connections 1000 requests 30000 replies 30000 test-duration 5.971 s

Connection rate: 167.5 conn/s (6.0 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 4.2 avg 6.0 max 13.0 median 4.5 stddev 2.6
Connection time [ms]: connect 0.1
Connection length [replies/conn]: 30.000

Request rate: 5024.0 req/s (0.2 ms/req)
Request size [B]: 74.0

Reply rate [replies/s]: min 5017.2 avg 5017.2 max 5017.2 stddev 0.0 (1 samples)
Reply time [ms]: response 0.2 transfer 0.0
Reply size [B]: header 405.0 content 25002.0 footer 0.0 (total 25407.0)
Reply status: 1xx=0 2xx=30000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 0.79 system 2.56 (user 13.2% system 42.9% total 56.1%)
Net I/O: 125016.7 KB/s (1024.1*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Apache

ab -n 1000 -c 30 xxxx
Server Software:        Apache/2.2.16
Document Path:          /
Document Length:        25002 bytes

Concurrency Level:      30
Time taken for tests:   0.753 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      25291000 bytes
HTML transferred:       25002000 bytes
Requests per second:    1327.92 [#/sec] (mean)
Time per request:       22.592 [ms] (mean)
Time per request:       0.753 [ms] (mean, across all concurrent requests)
Transfer rate:          32797.26 [Kbytes/sec] received


httperf --client=0/1 --server=xxx --port=80 --uri=/ --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=10
Maximum connect burst length: 1

Total: connections 100 requests 1000 replies 1000 test-duration 1.148 s

Connection rate: 87.1 conn/s (11.5 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 6.2 avg 11.5 max 14.1 median 11.5 stddev 1.3
Connection time [ms]: connect 0.1
Connection length [replies/conn]: 10.000

Request rate: 870.8 req/s (1.1 ms/req)
Request size [B]: 74.0

Reply rate [replies/s]: min 0.0 avg 0.0 max 0.0 stddev 0.0 (0 samples)
Reply time [ms]: response 1.1 transfer 0.1
Reply size [B]: header 260.0 content 25002.0 footer 0.0 (total 25262.0)
Reply status: 1xx=0 2xx=1000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 0.13 system 0.57 (user 11.1% system 49.5% total 60.6%)
Net I/O: 21544.9 KB/s (176.5*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

benchmark for Authenticated user (page load)

Nginx

Page load times : 2.85 s

Apache

Page load times : 5.4 s

But the power of Nginx is the cache system

Drupal without Boost and Nginx with cache system enabled

Server Software:        nginx
Document Path:          /
Document Length:        24902 bytes

Concurrency Level:      30
Time taken for tests:   2.437 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      252670000 bytes
HTML transferred:       249020000 bytes
Requests per second:    4103.34 [#/sec] (mean)
Time per request:       7.311 [ms] (mean)
Time per request:       0.244 [ms] (mean, across all concurrent requests)
Transfer rate:          101248.99 [Kbytes/sec] received


httperf --client=0/1 --server=xxx --port=80 --uri=/ --send-buffer=4096 --recv-buffer=16384 --num-conns=1000 --num-calls=30
Maximum connect burst length: 1

Total: connections 1000 requests 30000 replies 30000 test-duration 6.044 s

Connection rate: 165.5 conn/s (6.0 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 4.2 avg 6.0 max 11.7 median 4.5 stddev 2.6
Connection time [ms]: connect 0.1
Connection length [replies/conn]: 30.000

Request rate: 4963.7 req/s (0.2 ms/req)
Request size [B]: 74.0

Reply rate [replies/s]: min 4970.1 avg 4970.1 max 4970.1 stddev 0.0 (1 samples)
Reply time [ms]: response 0.2 transfer 0.0
Reply size [B]: header 405.0 content 25002.0 footer 0.0 (total 25407.0)
Reply status: 1xx=0 2xx=30000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 0.72 system 2.68 (user 12.0% system 44.3% total 56.3%)
Net I/O: 123516.8 KB/s (1011.8*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

You should use the perusio's configuration Nginx for Drupal

Tags:

Performance