Why is FastCGI /w Nginx so much faster than Apache /w mod_php?

(this post has a sister post on Apache’s event MPM compared to Nginx)

I was originally going to write a blog post about why NginX with FastCGI was faster than Apache with mod_php.  I had heard a while ago that NginX running PHP via FastCGI was faster than Apache with mod_php and have heard people swear up and down that it was true.  I did a quick test on it a while back and found some corresponding evidence.

Today I wanted to examine it more in depth and see if I could get some good numbers on why this was the case.  The problem was that I couldn’t.  IIRC, it was for a Magento installation.

To test I did a simple “hello, world” script.  Why something simple?  Because once you’re in the PHP interpreter there should be no difference in performance.  So why not just do a blank page?  It’s because I wanted to have some kind of bi-directional communication.  The intent was to test the throughput of the web-server, not PHP.  So I wanted to be spending as little time in PHP as possible but still test the data transmission.

The baseline tests show the following.

Apache w/ mod_php

 Total transferred: 3470000 bytes
 HTML transferred: 120000 bytes
 Requests per second: 2395.73 [#/sec] (mean)
 Time per request: 4.174 [ms] (mean)
 Time per request: 0.417 [ms] (mean, across all concurrent requests)
 Transfer rate: 811.67 [Kbytes/sec] received

NginX with PHP-FPM

 Total transferred: 1590000 bytes
 HTML transferred: 120000 bytes
 Requests per second: 5166.39 [#/sec] (mean)
 Time per request: 1.936 [ms] (mean)
 Time per request: 0.194 [ms] (mean, across all concurrent requests)
 Transfer rate: 801.82 [Kbytes/sec] received

Apache was able to dish out 2400 requests per second compared with 5200 requests per second on NginX.  That was more than I had seen before and so  I did an strace -c -f on Apache to see what came up.  -c shows cumulative time on system calls, -f follows forks.  The result for the top 10?

% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
 33.65 0.042063 4 10003 getcwd
 16.10 0.020127 2 10001 writev
 16.00 0.019994 2 10001 shutdown
 10.54 0.013179 0 51836 40118 open
 9.01 0.011263 1 20008 semop
 5.22 0.006522 0 54507 10002 read
 2.53 0.003158 0 10024 write
 1.91 0.002386 0 88260 66483 close
 1.57 0.001959 245 8 clone
 1.16 0.001455 0 54832 384 stat64

getcwd?  Why?  Then I remembered that I had AllowOverride (.htaccess) turned on.  So I re-ran the test with AllowOverride set to None.

Total transferred: 3470000 bytes
HTML transferred: 120000 bytes
Requests per second: 5352.41 [#/sec] (mean)
Time per request: 1.868 [ms] (mean)
Time per request: 0.187 [ms] (mean, across all concurrent requests)
Transfer rate: 1813.40 [Kbytes/sec] received

At 5352 requests per second Apache actually was outperforming NginX.  But what about if more data was transferred?  So I created about 100k of content and tested again.

Apache

Total transferred: 1051720000 bytes
HTML transferred: 1048570000 bytes
Requests per second: 2470.24 [#/sec] (mean)
Time per request: 4.048 [ms] (mean)
Time per request: 0.405 [ms] (mean, across all concurrent requests)
Transfer rate: 253710.79 [Kbytes/sec] received

NginX

Total transferred: 1050040000 bytes
HTML transferred: 1048570000 bytes
Requests per second: 2111.08 [#/sec] (mean)
Time per request: 4.737 [ms] (mean)
Time per request: 0.474 [ms] (mean, across all concurrent requests)
Transfer rate: 216476.53 [Kbytes/sec] received

This time the difference was even greater.  This all makes sense.  mod_php has PHP embedded in Apache and so it should be faster.  If you’re running only PHP on a web server then Apache still seems to be your best bet for performance.  And if you are seeing a significant performance difference then you should check if AllowOverride is turned on.  If it is, try moving that into httpd.conf and try again.

If you are running mixed content, such as adding CSS, JS and images, then NginX will provide better overall performance but it will not run PHP any faster.  It will also respond better to denial of service attacks better, but a CDN is generally better at mitigating that risk.

But if you are running pure PHP content on a given server, Apache seems to still be the best bet for the job.

[UPDATED]

Here’s a chart of the throughput difference

apache-vs-nginx

55 comments
joeynovak
joeynovak

I really appreciated this post.  It really highlights how important it is to tune your web server according to your server and usage case, and I appreciate that you used both of them out of the box :)

DimaSoltys
DimaSoltys

I understand it's a year too late, but there's a bit on information lacking from the article. Have you been connecting nginx and php-fpm through unix socket or tcp one?

DIREKTSPEED
DIREKTSPEED

And Now Open your EYES!!!!! Test Apache 2.4.6 With Directly proxy cgi and PHP-FPM and use the Apache 2.4.6 Event MPM not the Prefork or Worker?????


Now any questions who has won? Right Apache wins all clear NGINX is fake its like compare apples and PC


NGINX has a EVENT engine and you benchmark it against PREFORK Engine with MOD PHP wow what a supprise NGINX was faster but realy test Apache MPM Event best 2.4.6 with the cgi proxy and you will be stunted how blind a nginx user is!


Last time as i tested my Ferrari against my Ford i was Realy supprised that the Ferrari was Faster ;)


Oh and what a Wonder i tested Nativ C vs NGINX nativ C was able to Handle over 1million connections on a single server what a supprise is that ? Nginx and apache both get down after a few 100 000 per single server at the same time :D

nneves
nneves

Hi, what about the difference between nginx + php-fpm versus nginx proxy apache/mod_php for php pages only?

Gwyneth Llewelyn
Gwyneth Llewelyn

Thank you for doing some benchmarking on this! Recently I've being toying with a VPS with a very small memory footprint and limited resources, and the goal was to get everything in memory and avoid swap. This seemed to be impossible to manage with Apache; doing some benchmarks, Nginx + PHP-FPM outperformed Apache (both with mod_php and FastCGI) by about 10:1 — accepting at least 10 times as more simultaneous connections — while leaving the VPS running smoothly; Apache would bring it down under serious load.

But now I know why that was the case. As you so well explained, not everything is PHP — at least half of that content is static (JS, CSS, images, and so forth), since in my case I was using WordPress as the sole application on the backend. Now I understand why Nginx performed so well: it was dealing mostly with static content, and would outperform Apache easily — and handle much higher loads — even though Apache might be winning the race every time there was a PHP request. But in the middle of so many requests for static content, Nginx clearly was ahead of the race.

The lesson learned is that Apache isn't "that bad". On a completely different environment, the solution was to put Varnish in front of Apache. Varnish is merely a proxy-cache server, it doesn't serve static content at all (unlike Nginx, which can do all of that), but it does its job admirably well, and it's programmed/configured in a very similar way than Nginx. The results are impressive — if you can afford a lot of memory for Varnish.

At the end of the day, the lesson I learned was simple. If you are operating in a very limited and constrained environment, and still need to extract good performance of your underpowered setup, then the solution is to deploy Nginx + PHP-FPM, because it's easier to fit everything inside memory and avoid nasty surprises with swap. If, on the other hand, you have a couple of GBytes to spare, a better solution might be Varnish + Apache + mod_php — Varnish will handle static content even quicker than Nginx, and you'll benefit from Apache's slight edge in running PHP. In either case, make sure that your application handles dynamic content cleverly — the better it's able to generate static content out of that, the better the performance, and that applies to both kinds of solution.

For the sake of the argument, on my tiny VPS I avoided TCP sockets completely. Nginx talks to PHP-FPM via Unix sockets, and PHP talks to MySQL via TCP sockets as well (MySQL doesn't reply to TCP ports in my configuration). According to what I've read, the difference in performance shouldn't be noticeable, although benchmarks (and some academic papers) report a performance increase from as little as 5-10% to 200% when using Unix sockets. Why there is such a huge difference in the reports baffles me, although many of those reports are old. Maybe recent TCP/IP stacks are far better these days and, as such, the differences in performance between both communication techniques have been reduced...

mkevac
mkevac

The problem with Apache is not speed, but ability to handle lot of user requests. That's why high load sites use nginx. Read about 10k (100k, 1m) connections problem - http://www.kegel.com/c10k.html

tubalmartin
tubalmartin

A few months ago I reviewed this topic too since many people claimed NGINX + PHP-FPM to be faster than mod_php and the tests we ran at my company revealed results similar to yours, that is, Apache + mod_php for PHP only is faster than NGINX + PHP-FPM under any load scenario.

The setup we end up using is NGINX as reverse proxy for Apache 2.2 prefork with mod_php. NGINX handles HTTP connections, SSL, serving static files etc...while Apache is used just for PHP. AllowOverride is set to none for sure.

What's more, many people often claim NGINX + PHP-FPM consumes much less RAM memory than Apache + mod_php. Our tests revealed memory consumption to be more or less the same. Note that we enable just the Apache modules our app needs:

mod_cgi # Munin Zoom graphs
mod_status # Munin
mod_alias # Aliases
mod_authz_host # Order deny allow commands
mod_expires
mod_rewrite
mod_headers
mod_setenvif 

With these modules only, we observed a nearly equal memory consumption.

I'm glad to see more people testing things properly (although Apache Bench is not the best tool for load testing). Good article!



joaquinhdzg
joaquinhdzg

What about apache + php5-fpm + mod_pagespeed?

fkrauthan
fkrauthan

Jeah there should be a big difference if you use fastcgi or php-fpm to embed php into nginx.

petewarnock
petewarnock

The bigger issue is the memory footprint. If the server hits its swap, the performance will degrade. Nginx facilitates much larger scale on smaller, more economical hardware by using a smaller, more predictable amount of memory under load. It's a SWAG, but Nginx might be a little slower because each request has multiple asynchronous events; I think along the lines of send upstream and listen upstream. What version of Apache were you running? 2.4 claims to be faster than Nginx, but it's only been around for a year.

Gwyneth Llewelyn
Gwyneth Llewelyn

@DIREKTSPEED I did exactly those tests on a low-end VPS with constrained memory (merely 512 MB) for a few websites who have moderate traffic — and Apache would drag the VPS to its knees, while Nginx runs smoothly and has a tiny footprint both in memory and CPU consumption.

So, to take your analogy further, if you drive your Ferrari on a narrow, short street, the Ford can still beat it… specially if you're driving on a cobbled street (try it, if you have a Ferrari!).

Ferraris work great on motorways, though, and will eventually beat Fords. A fellow sysadmin also evaluated your setup, this time using a physical server with 8 cores and 32 GB, which, although it has considerable load, is generally running at 20-25% of maximum load. He reports that Apache beats Nginx under that configuration, so he sticks to Apache with Varnish on top of it (and plenty of RAM for Varnish!)

My guess is that you have a balanced mix of PHP and static content, Nginx will very likely be better, if you have a small footprint — at least, that's what I've experienced so far, and that's why I use Nginx on all my small servers, where every CPU cycle counts. On the other hand, if you have a vast amount of free CPU cycles, lots of RAM, superfast connections, unlimited bandwidth, and so forth, then Varnish + Apache should have a slight advantage over Nginx. But that's just my experience.

kschroeder
kschroeder moderator

@DIREKTSPEED I should also mention that the point of this was not to see which is faster, but to address _common_claims_about_nginx_against_apache_.  People say "Nginx is faster" and I say "ehhhhh, not so fast."  That is it.

Latest blog post: side-ywtdwwphp

kschroeder
kschroeder moderator

@DIREKTSPEED You don't need to get your panties in a bunch.  This was testing the typical Apache scenario against the typical Nginx scenario for PHP.  The event MPM for Apache is irrelevant to this discussion.  It will not be any faster with PHP because PHP then will need to use PHP-FPM for Apache in exactly the same manner as you would with Nginx.  This post was about PHP, not static content.

Latest blog post: side-ywtdwwphp

akaMrJohn
akaMrJohn

@kschroeder & @Gwyneth Llewelyn  Hi, Thanks for the comments and the article, they are very useful! By implication of what you're saying, then if your web architecture is such that you're serving static html files (web app) using a CDN and this app only makes API calls to your backend (all in PHP) i'd be better off sticking with Apache + mod_php than considering Nginx + PHP-FPM?

DIREKTSPEED
DIREKTSPEED

@Gwyneth Llewelyn  

LoL you Should Test NODE.JS it can handle Easy Some 100.000 Connections even on Small Hardware. If you got Biger it can Handle over Million Requests at time.

But at all to Stop you from Thinking Nativ C can Handle Most is the Fastest and thats simply coz the other software like webservers is Written in that Language and not PHP :D

DIREKTSPEED
DIREKTSPEED

@mkevac  

Apache MPM Event can Handle more Requests at same time then NGINX !

kschroeder
kschroeder moderator

@mkevac Yes, but if you are running PHP-FPM with NginX you still have the same problem.  Even though NginX can handle 10k connections does not mean that you want 10k PHP processes running in the background to handle the requests.  So while your assertion is true it's an apples/oranges comparison.  For static content, absolutely NginX is the best server.  However, for running PHP loads, Apache handles the request just a little more efficiently.

Eugene OZ
Eugene OZ

@tubalmartin thank you, it's very interesting for me. I like nginx, but I think proxy is better when we have clients with slow connections (like mobile apps/sites), because PHP can send response to nginx and finish execution (free resources), while nginx will send response to client with slow connection - all this time memory and CPU will not be used by PHP process. 

But there is one important thing - fastcgi_finish_request(). This function can solve wide range of issues, very useful in REST API implementations and cases when we need update/insert something big in database and user doesn't need results in response. These cases can be solved by queues/tasks, but with fastcgi_finish_request() it's much more easily.

kschroeder
kschroeder moderator

I was using Apache 2.2. But let's not go too far here. What I claimed was that PHP was faster on Apache. I have heard several times that this is the case. I wanted to figure out why and found that assertion was actually wrong. I wasn't talking about memory and I wasn't talking about static files. NginX is faster on a raw performance test. By at least an order of magnitude, due to its event based architecture. Personally, I would still recommend using NginX with FastCGI for PHP even though it is slower than Apache. For a mixed media site, the additional performance of static files more than makes up for the slow-down with FastCGI. And if it's an API-based site (only PHP-based content) NginX will handle transient loads better (as well as denial of service attacks).

Latest blog post: Kevin @ LinkedIn

garet1
garet1

@kschroeder @Gopalakrishna Palem  "Because once you’re in the PHP interpreter there should be no difference in performance." and especially, "getcwd?  Why?  Then I remembered that I had AllowOverride (.htaccess) turned on.  So I re-ran the test with AllowOverride set to None."

This is where you really start comparing apples and oranges. Perhaps you're not familiar with how to optimize php-fpm as much as you are apache, but A) fpm makes a huge difference on real scripts as it caches opcode, where mod_php does not. B) if you play with both configs nginx will still easily outperform Apache even with message pool extensions. This is a contrived benchmark, aside from now being rather dated.

DimaSoltys
DimaSoltys

@kschroeder Thank you. It's just that I've been asked to move from nginx to apache with mod_php recently. Your post have given me some much needed insight.

petewarnock
petewarnock

... reason being FastCGI protocol has less overhead than HTTP.

garet1
garet1

@DIREKTSPEED @Gwyneth Llewelyn  Native C can handle the most because it inherently runs faster with fewer calls.  Practically all other languages are simply programs written in either native C, lisp or something similar to native C like verilog/vhdl. 

These programs interpret strings and run commands, like a terminal, but they're still native commands and issuing them directly is faster. The only downside is it's usually too complicated for the likes of you to do correctly. There's few things as frustrating to me as people spreading bad info. 

Aside from that, NodeJS's performance can be obtained from most languages, not only C, but the V8 engine google made for javascript is the real key there.

More on topic, I see many people posting about apache+varnish, which is good. Something to consider additionally is Apache+Nginx, where nginx is a proxy cache.

From the nginx conf you can add a few lines to have your site output proxied similarly to varnish, this allows you to more-or-less use nginx's static content speed and apache's runtime conveniences together. Dynamic content turns into static content on-the-fly. Issue a delete from cache folder on updates, or have a time to live.

This way you can also have many nginx servers in the same cluster replicate from one or two apache VMs. Any time a request isn't cached, apache serves it anyway. You can define rules to bypass the proxy as well, for web services and such.

Bonus, no license fees =0


JaimieSirovich
JaimieSirovich

@kschroeder @mkevac Finally some sense in a benchmark.  I've never had the patience to run this test, but I've always assumed that mod_php would be faster if you are serving predominantly dynamic content.  In theory, PHP in Apache's threaded MPM should be fastest, but it's known to be problematic historically.

Nginx & Light are going to be awesome at server static content because they can use various event-based features of an OS to pump data without any thread at all.  You can't do that for a script.

tubalmartin
tubalmartin

@Eugene OZ

What we do for long running processes is run them in the background using either Gearman or shell_exec($cmd.' > /dev/null 2>/dev/null &'); so that the user doesn't have to wait for a response to arrive.

kschroeder
kschroeder moderator

... in other words, yes, memory utilization is more efficient with NginX. But one of the claims I heard was that NginX was faster, which turned out not to be true. With memory being cheap these days, memory usage should not be a primary factor for determining the server to use. The arguments _for_ NginX can be made quite easily without having to go to secondary arguments.

Latest blog post: Kevin @ LinkedIn

JaimieSirovich
JaimieSirovich

@kschroeder @JaimieSirovich@Jason Yang@petewarnockThere's one thing I overlooked.  If you proxy to a PHP process pool, you'll gain (usable) keepalives.  Whether this matters so much, of course, depends -- on connection speed and number of connections per page.  If you're going to use the prefork MPM, you're going to get into trouble with keepalives as well as mobile clients, potentially.  Slowloris is just surfing a website with a Hayes 300baud modem, no?  Totally possible.  Of course you can mitigate it.  Turn off keepalives and use mod_reqtimeout, etc., but that might be a bandaid.

JaimieSirovich
JaimieSirovich

@kschroeder @JaimieSirovich@Jason Yang@petewarnock

Is there some sort of issue with ZTS and a big fat lock for thread safety?  The reason many don't use it is that it is only _allegedly_ thread safe.  Or extensions are not, etc. I'd want to see Apache+mod_php in worker/event mode.  Bet it might not stink?

JaimieSirovich
JaimieSirovich

@Jason Yang @petewarnock @kschroeder What about if you're primarily serving dynamic content, and you're going to consume a coordinating process from the FastCGI pool nearly 100% of the time?  In that case mod_php might actually be more efficient.  In THEORY.  Well, threads might be better than processes still, but proxying from 1 pool to another seems silly if it's almost 1:1.

Jason Yang
Jason Yang

@petewarnock  because your requests to nginx magically bypasses HTTP protocol completely. /sarcasm

tubalmartin
tubalmartin

@Eugene OZ Sure, but we have Gearman/shell_exec wrapped in a simple function call: do_job_async($cmd).

If Gearman is not installed in one of our servers, it falls back to shell_exec.

Eugene OZ
Eugene OZ

@tubalmartin I have solution too, but one function is much more convenient than Gearman.

garet1
garet1

@Alexander Ustimenko this is not the case.

Imagine situations where you might want (nginx)+(nginx with php-fpm). Since nginx shines so much with proxying and static content, it is reasonable to replace the backend development with the client/team's preferred stack.

Some algorithms do work better in apache, especially if the frontend serving is taken out of the equation.

Similarly, some cloud services very much need php-fpm's process pool or similar features.

Eugene OZ
Eugene OZ

Alexander, maybe, but it's need to be tested without AllowOverride.

Eugene OZ
Eugene OZ

Another option is nginx+apache. Nginx as front-end for static files and as proxy to apache+mod_php. In this setup, nginx will also send responses to "slow" clients (like mobile phones) and it will give more free memory.

Trackbacks

  1. [...] move to the traditional Apache with mod_php instead of Nginx with php-fpm, after going through the pros and cons of each setup. If you are not aware already that AllowOverride All brings a major performance lag [...]

  2. [...] even show that on low-traffic sites serving dynamic (php) content – Apache might be faster like this blogpost shows. That’s why it’s important that the combination of everything in your environment is a [...]

  3. […] worth noting that Apache with mod_php is going to be faster for pure PHP — while consuming more memory, particularly under heavier loads — so, again, you should […]

  4. […] concurrency is vital for scaling. Nevertheless, if you’re serving primarily PHP to relatively few concurrent connections, Prefork may be preferable to the threaded […]

Post Navigation

Web Analytics