45

I have a new server to play with, and I am staring at a blank canvas. I can put anything I want on it. While I am comfortable with Apache, I keep hearing how nginx can handle so much more traffic than Apache, by factors of 10, 100, even more. Not only that it's "much much faster."

When I search for articles I can find lots of stuff unrelated to Drupal. Or, when I do come across a Drupal related article it's either 1) someone's configuration file with a quick attempt at explaining how to set it up, or 2) it's someone saying "no, don't use nginx, go with Apache with PHP fcgid" but there is never explanation as of why.

So, when it comes to Drupal, what is the reality here?

As an example, I am looking for something along the lines this 2bits.com article. Here the author has taken a pretty extensive look at Apache mod_php vs Apache with fcgid, weighing the pros and cons of each, and provided a case study to illustrate the impact in the real world. There is enough information in this article for me to make an educated decision as to which approach would be best for my situation.

While that author compares mod_php to fcgid, I am looking for the same type of comprehensive, real world look at Apache vs Nginx.

Anyone switched to Nginx and been "blown away" by the difference it made compared to Apache? Even for highly optimized environments that are already using APC, Memcache, and aggressive caching like Varnish, when the only variable that changes is replacing Apache with Nginx, does make enough of a difference in and of itself to merit investing in this newer, alternative technology?

The site that will go on this server gets an avg of 2 million PV a month. LAMP stack running Cent OS 6. 4 core CPU with 8 GIGS of ram. Memcached and APC will be part of the mix. Nothing special about the Drupal install - basically vanilla 7 with about 50 modules.

  • 2
    If you want to tune a particular site for performance, you're better off running your own tests than relying on other people's work. The mix of anonymous versus logged-in users, for example, is a major factor. If you look at performance stats for a site getting mainly anonymous traffic, and yours is not like that, you might as well not bother. But if your site does have largely anonymous traffic then in my experience putting Varnish in front of your web server makes a much greater difference than what server you run behind it. – Alfred Armstrong May 6 '13 at 11:30
60
+200

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.
  • 4
    Don't forget about CDN to prevent the vast majority of CSS, JS, and image requests from ever hitting the web server. – mpdonadio May 4 '13 at 2:39
  • Excellent point! I think I'll have to re-write drupal.stackexchange.com/questions/24180/… at some point. A discussion about Apache/Nginx doesn't seem like the optimal place to build a comprehensive list of performance optimizations. – Letharion May 4 '13 at 7:43
  • 1
    This is a great answer. Just one nitpick: you shouldn't use "ECMAScript" and "JavaScript" interchangeably. There is a lot more to JavaScript than ECMAScript. – user19770 Aug 4 '13 at 22:33
  • You are saying that the cache is by far more important than webserver speed. Guess what? If a webserver uses less memory than the other, you can use more RAM for caching. So we can say that it is important to tune your webserver properly so that it doesn't eat all your RAM, right? – pqnet Aug 29 '14 at 20:11
  • Tuning your server to use less RAM is absolutely fine, but if you are trying to go into high performance territory you'll likely be running varnish on a dedicated server, so your http server and cache won't be competing for the same memory. – Letharion Oct 24 '15 at 10:18
32

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.

  • 6
    You hit the nail on the head with "... not how fast they can serve a request, but how many requests they can serve on the same amount of hardware..." Indeed ultimately I want to get the biggest bang for my buck. Given a machine of the exact same hardware and other variables, if I can serve 1,000,000 users a day with nginx where apache could only serve 200,000, then certainly the best choice from a cost perspective is nginx. Given a certain hardware configuration, have you seen a large difference between what nginx can do compared to apache? – blue928 Jun 3 '13 at 22:10
  • 2
    Apache 2.4, the current release, has an event-based model: httpd.apache.org/docs/current/mod/event.html – Greg Jan 2 '14 at 20:53
  • 1
    Also, for those who says that it doesn't matter because "it will be ok as long as you are caching stuff": you know what you need to do caching? You need FREE RAM. – pqnet Aug 29 '14 at 20:15
  • I frequently see these general claims of "Nginx is more awesome", however, I rarely (ever?) see anyone back this up with solid evidence. It's always "My highly configured nginx instance beat a stock apache server so now I have proven I'm cool because I use nginx like the other cool kids". Nginx might be vastly better than Apache for all I know, but I have yet to see anyone truly show that that is the case. – Letharion Oct 24 '15 at 10:16
  • @Letharion: Done (by dreamhost.com), and added as per your request. As you can see in this benchmark results, nginx is clearly more memory-efficient. Also it's probably: my stock-nginx-instance beat my stock-Apache-instance on the same benchmark on the same computer. – Quandary Jan 11 '17 at 11:53
16

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

  • How was Apache running, preform, FCGI, etc? Was your Apache config as optimized as possible when you ran these tests? Was the exact same PHP environment running? – mpdonadio May 3 '13 at 13:09
  • The PHP (5.3) environment was exactly the same. Apache was running mpm_prefork, and the apache config (maxclient, MaxSpareServers, MaxRequestsPerChild, etc) was exactly the same than PHP5-FPM – flocondetoile May 3 '13 at 13:58
  • 4
    These are good numbers, but I am not sure if they are a true comparison. Apache + FastCGI vs Apache + FCGI + PHPFPM vs Nginx + PHPFPM would show the differences between Apache and Nginx better. – mpdonadio May 4 '13 at 2:37
  • As MPD points out, this is not a true comparison. You need to be running php-fpm on both to get a true picture. – user19770 Oct 7 '13 at 13:31
  • 1
    Nginx is a good choice for RAM-limited VPS accounts, I think. As it can operate comfortably with a smaller RAM footprint than Apache - especially if you keep unnecessary modules uninstalled - you have more RAM left over to run opcode caches (APC or PHP 5.5's built-in OpCache), give the MySQL/Postgres server daemon a big buffer, and other optimizations which Letharion rightly points out are important as well. – Garrett Albright Oct 21 '13 at 17:26
0

Here is a performance test for ten webservers/varients (e.g. Apache, Nginx, lighttpd, Lightspeed, Hiawatha, Cherokee). Three of the tests relate to Drupal.

I'm thinking Hiawatha may be the best overall choice. Supposed to have full Drupal compatibility, has an emphasis on security (DoS, XSS, CSRF, SQL-injection prevention), and speeds & footprint similar to Nginx.

In two of the three Drupal tests, both Hiawatha and Nginx outperform Apache by about 150%, but in the Drupal static test, Apache marginally outperforms Nginx, while Hiawatha bests the pack by about 10%.

I wouldn't hang my hat on any of these tests, but it does give one a ballpark view of performance in different usage situations. I think performance alone shouldn't be the only consideration. Stability and security may be the more important factors.

0

here is a load testing results for drupal running on same hardware but with different web servers. (nginx and apache)

here is the conclusion of this test:

under a large traffic with same hardware resources, nginx performs way better than apache.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.