Apache + mod_php compared to Nginx + php-fpm

June 24th, 2009 by Boštjan Škufca

Recently I received an email pointing me to this article and with a request that I conduct a test of Nginx, which should supposedly be a better web serving application. But in previously mentioned article they state they are getting over a 500% more from the same hardware with a new piece of software, is still awesome. From the experience I know that with such claims, one must utilise some healthy skepticism.

Test methodology

All the software was compiled from source (details below). Benchmarks were conducted using ApacheBench tool (ab) from apache installation. The tool was running on the same machine as the server. Both servers had request logging disabled. Tests were conducted once with keepalive feature enabled and once with keepalive disabled. Each test was repeated five times and average taken. Test files were:

  • HelloWorld.php – short php scripts, which only echoes string “Hello, World!” (13 bytes), intended to measure processing overhead of PHP vs static file (contents of this file are here: ‘
  • HelloWorld.txt – a static file with string “Hello, World!” inside (also 13 bytes), intended to show static file serving overhead
  • 100KB.txt – a static 100KB file
  • 1MB.txt – static 1MB file
  • index.php – a frontpage of certain application which is quite CPU intensive and includes PHP processing, some DB querying, file cache reads and HTML template processing

Test system and ./configure commands

  • Hardware: HP DL380 G5
  • Hardware: 2x Intel Xeon E5420 (4 cores each, total of 8 cores)
  • Hardware: 8GB of ECC RAM
  • Hardware: Smart Array P400i RAID-1 with 2x 147GB SAS drives
  • OS: Slackware 12.2 with almost all software compiled from source
  • Filesystem: ext3
  • Apache version: 2.2.11, php via mod_php
  • Nginx version: 0.7.59, php via request proxying to php-fpm (via socket)
  • PHP version: 5.2.9
  • Eaccelerator version: 0.9.5.3 (for both, Apache and Nginx)
  • MySQL version: 5.0.77
  • OpenSSL version: 0.9.8k
  • both servers had request logging disabled

Configure command for Apache:

./configure –prefix=/usr/local/$PDESTDIR_HTTPD –sysconfdir=/etc/httpd \
–enable-authn-file –enable-authn-default \
–enable-authz-host –disable-authz-groupfile –enable-authz-user –enable-authz-default \
–enable-auth-basic \
–disable-include –disable-filter –disable-charset-lite \
–enable-log-config \
–enable-env –enable-setenvif \
–enable-ssl –with-ssl=/usr/local/openssl-$PVERSION_OPENSSL \
–enable-http –enable-mime –enable-status \
–disable-autoindex –disable-asis \
–enable-info \
–enable-cgi –disable-cgid \
–enable-vhost-alias \
–disable-negotiation \
–enable-dir \
–disable-actions \
–disable-userdir \
–enable-info \
–enable-rewrite \
–enable-so \
–with-mpm=prefork

Configure command for Nginx:

./configure –prefix=/usr/local/$PDIR \
–conf-path=/etc/nginx/nginx.conf \
–error-log-path=/var/log/nginx/nginx_error.log \
–pid-path=/var/run/nginx.pid \
–lock-path=/var/run/nginx.lock \
–user=httpd \
–group=httpd \
–with-openssl=/usr/local/openssl-0.9.8k

Configure command for PHP:

—–[These lines are for PHP with Apache (mod_php)]—————-
./configure –prefix=/usr/local/$PDESTDIR_HTTPD/$PDIR \
–with-apxs2=/usr/local/$PDESTDIR_HTTPD/bin/apxs –enable-cli –enable-cgi \
–with-config-file-path=/etc/php/httpd \

—–[These lines are for PHP with Nginx (php-fpm)]—————-
./configure –prefix=/usr/local/php-fpm \
–enable-cli –enable-fastcgi –enable-fpm \
–with-fpm-conf=/etc/php/php-fpm/php-fpm.conf \
–with-fpm-log=/var/log/php-fpm.log \
–with-fpm-pid=/var/run/php-fpm.pid \
–with-config-file-path=/etc/php/php-fpm \

—–[These lines are common for both]—————-
–disable-short-tags \
–disable-ipv6 \
–disable-all \
\
–enable-libxml \
–with-openssl=/usr/local/openssl-$PVERSION_OPENSSL \
–with-pcre-regex \
–with-zlib \
–with-bz2 \
–with-curl –with-curlwrappers \
–enable-dba=shared –with-db4 –enable-inifile –enable-flatfile \
–enable-dom –with-libxml-dir \
–enable-filter \
–enable-ftp \
–with-gd –with-jpeg-dir –with-png-dir –with-freetype-dir \
–with-gettext \
–enable-hash –with-mcrypt \
–with-iconv=/usr/local/lib –with-iconv-dir=/usr/local/lib \
–with-imap=/usr/local/imap-$PVERSION_CYRUSIMAP –with-imap-ssl \
–enable-json \
–enable-mbstring –enable-mbregex –enable-mbregex-backtrack \
–with-mysql=/usr/local/mysql-$PVERSION_MYSQL –with-mysqli=/usr/local/mysql-$PVERSION_MYSQL/bin/mysql_config \
–enable-pdo –with-pdo-mysql=/usr/local/mysql-$PVERSION_MYSQL –with-pdo-sqlite –enable-sqlite-utf8 \
–enable-reflection \
–enable-session –with-mm \
–enable-shmop \
–enable-simplexml \
–enable-soap \
–enable-sockets \
–enable-spl \
–with-regex \
–enable-sysvmsg –enable-sysvsem –enable-sysvshm \
–enable-tokenizer \
–enable-xml –enable-xmlreader –with-xmlrpc –enable-xmlwriter –with-xsl \
–enable-zip \
\
–with-pear \
–enable-zend-multibyte

Runtime configuration files

Apache+mod_php: httpd.conf
Apache+mod_php: php.ini
Nginx+php-fpm: nginx.conf
Nginx+php-fpm: php-fpm.conf
Nginx+php-fpm: php.ini was functionally identical to the php.ini used by Apache+mod_php

Results

HelloWorld.php results:

Apache VS Nginx: HelloWorld.php

Apache VS Nginx: HelloWorld.php

Here you are able to see an overhead which each PHP request imposes. Interesting and not unexpected is a fact that Apache performs better at this test, much better. The reason here is that Apache has PHP processing “built-in” via mod_php module. On the other hand Nginx proxies PHP requests to another application server (php-fpm). The performance of Nginx in the graph above is roughly half of that of Apache, which can easily be explained with “two servers doing the work of one”. A reader must mind that here almost no PHP processing is done, a simple echo statement only.
HelloWorld.txt results:

Apache VS Nginx: HelloWorld.txt

Apache VS Nginx: HelloWorld.txt

At this test Apache starts to lag behind. Nginx perform better without keepalive feature, but with keepalive enabled it outperforms Apache by more than a factor of 2. This test is here only to demonstrate the overhead of static file serving.
100KB.txt results:

Apache VS Nginx: 100KB.txt

Apache VS Nginx: 100KB.txt

Here we start the real static file serving benchmark. With file size of 100KB we come closer to what one might call “real world benchmark”. Again we are able to demonstrate that Nginx without keepalive feature performs on-par with Apache with keepalive feature enabled. But Nginx with keepalive feature enabled outperforms Apache by factor of 2. The throughput we may calculate here is roughly around 1,2GB/s, but mind that all tests utilise loopback network interface.
1MB.txt results:

Apache VS Nginx: 1MB.txt

Apache VS Nginx: 1MB.txt

Again “real world static file serving benchmark”, yet this time with a file size of 1MB and without keepalive feature (keepalive does not matter anymore as majority of time is spent by transfering data and not by TCP overhead of establishing new connection).
Custom real world application performance comparison results:

PHP application benchmark Apache+mod_php vs Nginx+php-fpm

PHP application benchmark Apache+mod_php vs Nginx+php-fpm

Here you can see Nginx has a slight edge, but I must note that Apache had a .htaccess parsing enabled (AllowOverride All directive), a feature that Nginx is lacking. A drop in performance at the high concurrency levels has probably resulted from too few concurent database connections available to the system.
Apache HelloWorld.php VS HelloWorld.txt comparison results:

Apache VS Nginx: Apache PHP vs TXT

Apache VS Nginx: Apache PHP vs TXT

Note how close to the static file serving comes dynamic echoing the same content from PHP script.
Nginx HelloWorld.php VS HelloWorld.txt comparison results:

Apache VS Nginx: Nginx PHP vs TXT

Apache VS Nginx: Nginx PHP vs TXT

Nginx difference in static vs dynamic overhead is notably larger.

Memory footprint

If memory usage is of real importance to you, then you should seriously consider using Nginx. With nginx all the static file serving capabilities can be achieved by using only that many worker processes as there are CPU cores on your server. In the example above this means 8 cores and 8 worker processes for Nginx, no matter how many clients connect to it simultaneously. For PHP, there are 16 php-fpm workers alive in the example above (which is enought if you are not doing some blocking IO). When you sum this up you get a decently low memory usage.

On the other hand Apache (with prefork MPM, which is required by mod_php) creates as many processes as there are clients (up to the limit of MaxClients directive) and it does not matter whether clients are requesting static files or for PHP applications. So for 200 clients it will create 200 processes with embedded PHP, which gives far larger memory footprint than Nginx has.

Conclusion or “should you switch from one to another?”

Short answer: I do not know.
Longer answers are here:

  1. If you host many websites and users utilise .htaccess files and change them frequently, then the answer is probably “no”. The cost of switching over to Nginx and converting all the configuration to new format usually reaches the cost of buying another server.
  2. If you have single application on multiple servers and most of the processing power is not consumed by serving static file content, the answer is also probably “no”.
  3. If you are mainly serving static content, the answer is obviously “yes”.
  4. If you are creating a fresh system for webhosting solution, the answer is probably “yes”, with the assumption that users will not miss the .htaccess functionality or it will be provided by other means
  5. If you are consolidating services with some virtualization technology, then answer is probably “yes”, as Nginx tends to have smaller memory footprint than Apache.
  6. If you are looking towards Nginx as your PHP server optimization, look again, but not at Nginx, at your application code.

I hope that this comparison helps you with your decision. If you have some questions, feel free to email me or post a comment below.

UPDATE 2009-06-25:
The ApacheBench tool was invoked with the following command:

ab -n NREQ -c NCONC [-k] http://server.domain.com/bench/FileName
NREQ is the number of requests:
– HelloWorld.php: 500000
– HelloWorld.txt: 500000
– 100KB.txt: 500000
– 1MB.txt: 50000
– AppFront: 5000
NCONC is the number of concurrent requests, as noted in the graphs.

Each test was repeaded 5 times and the average was calculated.
Thanks to Sean Osh for requesting this info.

UPDATE 2013-05-30:
David pointed out in comments below that php-fpm had max children setting set to 16, which is far less than what Apache had. Currently re-testing everything with the same software (OpenSSL 0.9.8 anyone?:) on the same hardware would require too much resources/work or to put it plainly – it is downright impossible for me ATM.
But: if a diligent reader does it properly, publishes the results and notifies me with URL, I will gladly include that URL in this article.
Thanks David!


50 Responses to “Apache + mod_php compared to Nginx + php-fpm”

  1. I was trying to get nginx with php-fpm. I faced a problem some pages works, and pages that connect to remote database say “The page you are looking for is temporarily unavailable. Please try again later.” With nginx and php-fpm, if there is a problem, you don’t get any support as it is like an abandoned project, now some one taken over php-fpm, not much development. After reading your post, i will stay with Apache for php.

  2. Sean Osh says:

    Nice work. Just had two questions:

    1) You say “The tool was running on the same machine as the server.” Does this produce the most reliable results given that the benchmarker now has to compete for resources with what it’s benchmarking?
    2) What were the options you ran ab with in terms of # of requests, concurrency, etc.

  3. @Sean Osh:
    1) If I was going to measure absolute throughtput then you have the point there. But this was a comparative benchmark and the same environment was used for testing both servers, thus the impact of running benchmark tool on the same machine “should” have been nulified in the results. Also I only had 100Mb/s ethernet connection available so it would get saturated quickly. Please check the discussion here for some more info:
    http://www.webhostingtalk.com/showthread.php?t=871025

    2) The number of concurrent clients is noted on the X-axis in the graphs. Total number of requests: thanks for notice, I updated the post (at the bottom). No other options were used, except keepalive feature (-k) where noted.

  4. Sean Osh says:

    Boštjan,

    Thanks for sharing. Again, great stuff…

  5. Sean Osh says:

    Just curious as well, did you stick with the standard configuration files generated from building Apache/NGINX/php-fpm (aside from changing paths/domain name to test with)?

  6. If you’d take some config file from his blog post (ie httpd.conf) and diff it with original one, there would be a lot of differences because I usually strip out all the comments and rearrange order of directives so it becomes more “intuitive” to read (at least for me). Apart from that, there are only some minor differences, like:
    – LogLevel set to notice
    – DirectoryIndex has more entries
    – ExtendedStatus is enabled
    – ServerTokens set to Prod
    – CGI was disabled
    But basically no relevant changes have been made beside the fact that I disabled some standard modules when doing ./configure (autoindex, userdir, actions, negotiation, include, filter, asis and charset-lite) .

    The interesting thing is that when I compiled apache almost all modules excluded (just bare file serving functionality), it did not perform any better than fully loaded with own modules and with mod_php enabled.

  7. Ky Lam Ngo says:

    Some more tests with PHP opcode caching would be nice =)

  8. “Some more tests with PHP opcode caching would be nice =)”

    Can you be more specific? Opcode caching was used all the time (eAccelerator).

  9. till says:

    Is this Apache 1.3 or Apache 2.1 or 2.2? The Apache that performed miserable in my case was Apache 2.2.

    Also, what is your OS?

    Apache 1.3 (mod_php) vs. nginx (php-cgi) on the same (older) hardware on FreeBSD 6.x were not too far apart. I just could not run Apache 1.3 vs. nginx on FreeBSD 7.x because of the APC errors, which I could have probably disregarded for a better benchmark but the real life application went constantly down with “minimal” load. The major difference in speed was noted on FreeBSD 7.x.

    If you want to provide more pointers, I could re-run the tests and send you the data.

    Till

  10. All the relevant specs are in the article, but since you are asking, here are the answers:
    – Slackware Linux 12.2 (production libraries and programs built from source)
    – Apache 2.2

    Was your older hardware multiprocessor/multicore system?
    Did Apache 1.3/2.2 performance get worse when you compared it on FreeBSD 6.x vs 7.x?
    Did you try any other opcode cache?

    Name the pointers you need and I will supply them, but most of the data should already be in the article, or, at least, I believe so :)

  11. Sobored says:

    It would be interesting to see the results of these test cases using Apache 2.2 as MPM worker + fastcgi

  12. Vito Botta says:

    The more I read these comparisons, the more confused I get… :(
    Some say nginx is much faster, some say the opposite :D
    I am currently trying to get nginx working, as lightweight replacement for apache.
    It seems to be extremely fast with php-fpm, but after the application has been in idle for a while the php-cgi processes die and I haven’t yet found a way to make php-fpm restart automatically as soon as new requests come in.
    Now I’ll get 502/bad gateway errors from nginx whenever the php-cgi processes die, and have to *manually* “php-fpm start” to get the website working again…
    Any ideas on how to fix?
    And, besides this, and taking into consideration that I am using a VPS (512MB ram), would you suggest me to stop wasting time with nginx and go back to apache for php, or either to try solve this issue to use nginx and save memory?

    Thanks!

  13. @Vito Botta:

    If you are that limited with the amount of RAM, I would recommend going the Nginx way. Two things:

    1. How long does your application need to be idle before php-cgi processes start dying?
    2. Why don’t you create a temporary solution in form of a short crontab script which runs every minute, checks your website and in case of 502 error restarts the php-fpm? It is almost an one-liner.

    b.

  14. Apache can be well run with MPM worker rather than with the slower MPM prefork, and PHP. You will need to compile thread-safe binaries of the latter, as fasr as I remember by running ‘configure’ with: –enable-maintainer-zts
    Then, figure out how many MaxClients your server can run and configure Apache to run always that number.

    I am curious about the benchmark’s results with the new configuration.

  15. @W-Mark Kubacki:

    Thanks for info. Do you know if any (and which) PHP modules still cause problems when used with threads?

    Anyway, did a quick benchmark with MPM worker and it showed very similar results to prefork MPM, a bit better at HelloWorld.txt, but 100KB and 1MB results were the same. I didn’t test it with PHP, but it makes very little sense to do it. If most of the time is spent processing PHP then switching to different MPM should not have any noticeable impact, except for the memory footprint.

  16. Boštjan, that result sounds too bad to me. You’re right about running tests with PHP, but serving static files (especially the smaller one) you should experience a RPS increase of about at least 20%. (E.g., see http://www.camelrichard.org/apache-prefork-vs-worker.) I am inclined to believe that something is not configured properly.

    For 1MB etc. you shouldn’t see a change, what you confirmed. At these tests Apache has already established communicationship to the requester and thus only streaming performance kicks in. It is a “spoon feeding” test with additional buffer/disk usage – thus little suitable to measure RPS in my humble opinion. It is suitable to benchmark context switching speed (threading is better than forking at that; MPM event is in between; nginx architecture excels here), request handling architecture (of no interest to us), caching, memory usage and the such.

    In practice the performance of a webserver is limited by network, e.g., you skip a lot architecture by testing against 127.0.0.1 (the entire bus down the network card, for example). It is a valid test, though. But after having deployed Apache, Rock or Nginx and having seen 3000 RPS from each from within the LAN or even WAN you must admit it the server’s load, response delays and the such count more.

    Hmm, BTW, “real world application” performance you could measure by “siege” a list of mixed urls.

    Again, your tests are perfectly fine (tune your machine, though; mount caches to /dev/shm, set /proc/sys/vm/swappiness to 1 etc. HelloWorld.txt should peak at it at about 45000 RPS). I’d like just to thank you for them by summarizing my findings.

  17. Oh, about the modules. I have not experienced any significant threading issues anymore since over about two years. Even with extensions.

    What do you think about Nginx in front of Apache+mod_php?

  18. I am leaving for a mountain trip so I will respond to your previous comment after I come back (in a week or so).

    Nginx in front of Apache: I am seriously considering this option, because Nginx is presumably not susceptible to slowloris attack. Just to put it in front and proxy everything to apache. Later add the static file serving functionality, but there you have to generate vhost configs for nginx too.

  19. Aco says:

    Does compiling it from source vs using a package really affect overall performance?

    Also, I am starting a new website which I am sure about will get heavy traffic. The website design hardly uses any images, except the logo and a few others. Most of the design is HTML/CSS. I use xCache and memcache for caching pages/queries. My question is, which web server should I go with? Apache or nginx? I’m not a big fan of compiling things as I always run into random errors, and I would have to compile a lot of things if I were to use nginx. What do you suggest?

  20. Aco says:

    I’d like to give you the specs:

    Supermicro, Intel i7 2.6GHz, 12GB DDR3 1333MHz RAM, 2x 146GB SAS 15K HDs in RAID 1

  21. I really could not tell if it really affects the performance THAT much, but to a certain degree – certainly. Again, I currently have no numbers to back it up.

    I do compile everything from scratch for the stability reasons. There are 3 options generally:
    1. use precompiled packages and stick to that,
    2. use precompiled packages and compile just the things you are lacking and
    3. compile everything

    If you are undemanding user than number 1 could be the best option in terms of maintenance easiness etc. But if you require some non-standard feature and/or version then you probably try to go with number 2 because you hang on to what you know and can do from number 1.

    Personally I have bumped at stability issues and general PITA at maintaining package updates with custom compiled modules so I decided to just compile everything from scratch and it never posed any serious problems (besides the initial time that is needed to get things right).

    So, the answer to your question – which webserver software: if this is going to be a single-application server and you are setting it up anew I would go for Nginx + php-fpm combination. Why? Because I like the idea of separation of static file serving and application serving. Secondly because of the small memory footprint of NginX, if that is a concern. Thirdly because of non-susceptability to slowloris attack. Fourthly because you have no legacy .htaccess configurations to handle.

    Xcache: it seems it is actively maintained, I didn’t do any benchmarks yet, if you have any, please inform me.

  22. Aco says:

    Thanks for the reply Bostjan.

    Wouldn’t having using nginx for frontend and apache for backend give me the same thing as using nginx + php-fpm? Is there a difference performance wise? Being a noob, this is the easiest method for me. It would also allow me to work with .htaccess files, which is much more convenient. What are your thoughts on this?

    I do not have any benchmarks for xcache, but I managed to find several websites that benchmarked APC, xcache, and eaccelerator. The difference between the op-caches was negligible. However, using a op-cache gave the PHP applications a huge boost. When you get the chance, you should run your benchmark with a op-cache, it would be nice to know the boost in performance.

  23. Aco says:

    Sorry, I forgot that you DID in fact use a op-cacher: eaccelerator. Disregard my last paragraph.

  24. As you can notice above, the HelloWorld.php gives better results with Apache than with NginX. I repeat, this is a synthetic test, which only proves that proxying requests to another server (in this case php-fpm) creates some latency and/or overhead.

    The answer to you question about Nginx in front and Apache behind: if you are only going to forward ALL the requests to Apache, then you will have static file serving performance penalty. If you serve static files with NginX, then it really does not matter that much which application server is in the back, Apache or php-fpm. If you are familiar with Apache and it does not seem too much hassle to configure, go with it then. Single tool that you are familiar with can always serve you better than 100 different tools you briefly know. And you can always switch to php-fpm later. But, php-fpm is very easy to set up – apply patch, compile php, modify config file and voila.

  25. […] We all know that Apache is a great software and it cannot be replaced every time. Also, Apache shown great performance serving dynamic php content whether it’s running mod_php or fastcgi. Boštjan Škufca made an excellent comparison between Apache + mod_php and Nginx + php-fpm. […]

  26. It would be interesting to test typical PHP application, like WordPress for example.

  27. […] a na zużycie pamięci. Czyli może działać szybciej, ale nie musi zależy od sposobu mierzenia. Tutaj jest porównanie szybkości mod_php i php-fpm. Brodaci i brzuchaci programiści, tacy jak ja, którzy pamiętają jeszcze czasy Perla, […]

  28. Yes, I am thinking about that, but a standard dataset (database content) must also be available so that test becomes realy repeatable. I found that Magento has such a starting dataset.

    Can someone recommend anything else? Thanks.

  29. I’ve just completed a set of preliminary benchmarking test with Magento and WordPress.

    Magento has proved itself as incapable of performing steadily under high loads. I believe it is some sort of file-cache locking issue because with concurrency=1 it’s performance was flawless.

    WordPress results are on par with results of “Custom application frontpage” benchmark from this article, only scaled down with a factor of around 0.25 (75% the performance of “Custom application frontpage”). Will publish complete results soon.

  30. eran says:

    Hi

    I see that nginx has problems with spawn-cgi or php-fpm, it is not stable / reliable solution – 502 error.

    So, is there a solution to it?

    ——————–

    Can I run apache with MaxClients set to small number and solve the memory issue of apache?

    After reading for hourssss in forums , I can’t decide what to use, apache or nginx ?

    It is for a drupal + vps .

    Thanks

  31. Sergiy says:

    Hi, Eran
    somaxconn by default is too small
    if you have Linux you should encrease:
    somaxconn (try 4000 or more), tw_buckets and backlog in /etc/sysctl.conf (don’t forget to do #sysctl -p /etc/sysctl.conf )
    nofile and nproc in /etc/security/limits.conf for user which start nginx (read about ulimit)
    in nginx config you may try use:
    listen 80 default backlog=4000(or more) sndbuf=32k rcvbuf=8k deferred;

    for freebsd do netstat -Lan, check queue to port 80 and change same parameters

    >I see that nginx has problems with spawn-cgi or php-fpm, it is not stable / reliable solution – 502 error.
    >So, is there a solution to it?

  32. […] Apache + mod_php compared to Nginx + php-fpm […]

  33. Nils Eriksen says:

    If you have a small server. and running many concurrent. nginx, php-fpm does indeed utilize the overall hardware available much better than apache/mod_php.

  34. […] am Unreason People mostly use 1 on larger sites, but 2 is supposed to be good to. There are benchmarks, but most of them are synthetic or […]

  35. […] Segue abaixo um link com um teste de desempenho interessante. Ele mostra bem a diferença ente os dois servidores quando usados em grande escala. Ficou evidente que o ngin é muito superior em conteudo estático, enquanto o apache é melhor com scripts php. http://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/ […]

  36. Edu says:

    good article!

  37. SaltwaterC says:

    Couple of notes though:

    – from php-fpm.conf 16 – this limits the process pool to 16 processes for PHP-FPM while Apache can fork more children aka it can support better concurrency when the load is not CPU bound. This is the case for the HelloWorld.php test. The adaptive process spawning was implemented in PHP-FPM after the inclusion into the upstream PHP distribution, although the configuration file may state otherwise. This may be an unfair disadvantage for the PHP-FPM case. Most people say that Apache2+mod_php5 performs better for “real world applications”, but most of the time they forget to mention what’s the exact level of concurrency stated by worker MPM vs the PHP-FPM process pool since a low number of processes into the PHP-FPM pool means that requests start to queue while the CPU basically is free for other stuff. You benchmark suffers from this kind of starvation.

    – you may use an UNIX domain socket for the FastCGI protocol request / response transactions which avoids the TCP overhead that your tests has, even for the loopback interface that still needs to encapsulate / decapsulate the traffic, or fragment the information which is not uncommon for real world applications as the loopback MTU is just 16436.

    About your longer answers, there are some things to consider:

    – .htaccess comes with some added computational cost, therefore a properly configured Apache won’t have this “advantage”. Apache is good for virtualhosting when the end client has access to the server configuration, but for an organization, that job should suit better a professional sysadmin.

    – from the virtualhosting point of view, mod_php5 comes with a security issue ‘by design’ when combined with worker MPM since by default any virtualhost can access the files hosted by another virtual host. ITK MPM would avoid that. PHP’s safe_mode would avoid most of the issues as well, but that’s a nasty hack that the PHP team is going to remove anyway into the next version. The other solution is FastCGI. Proper configuration with suEXEC, open_basedir and mod_fcgid has loads of fun under Apache. PHP-FPM has a much cleaner implementation since it binds a specific process pool to its own security context by design, not by hacking configuration files and creating FastCGI wrappers.

    What can I say … we ditched Apache from out production servers for quite a while. So far, nobody misses it.

  38. bostjan says:

    “You benchmark suffers from this kind of starvation.”

    Thanks for the hint, you’re probably right. Will retest it with larger PHP-FPM process pool.

  39. zob says:

    Disregard the use of SuEXEC. Its performance is plain abysmal. It’s a nice thing to have but it’s un-useable for performance/high traffic.

    ITK MPM is much better in that case but not always what you want.

    A third solution is something like mod_rsbac. It works with prefork MPM and mod_php, yet provide full virtualhost isolation (in fact, much better isolation any of the previous solution offers by a very long margin)

    mod_rsbac is nearly the same performance as native prefork+mod_php, too

  40. […] 尚、ベンチ云々はググれば出てくる(Apache + mod_php compared to Nginx + php-fpmとか)と思いますので、そのへんはお任せしまして、環境構築した時のメモを記載します。環境はCentOSです。 […]

  41. Phoenix says:

    What a fantastic, and informative post. I have recently made the switch to nginx + php-frm + eaccelerator, so it’s really nice to have this post. So far php-frm is performing well. But it would be great to have some learnings and best practices from these benchmarks — as in, how many process workers should we set in php-fpm for best performance (based on amount of RAM or CPU cores, etc). Thanks!

  42. bostjan says:

    @Phoenix:

    I believe the number of processes are dictated by your site’s max concurrent users you wish to handle which then dictates your hardware resources. If you are constrained then this is another matter, but unfortunately that was not the objective of this article.

    About optimal performance, I would not recommend any exact numbers, but rather server metrics collection and graphing (Collectd is great at this) and based on those graphs you can make some additional decisions. But first you have to decide whether you are optimizing page load times (user experience) or server-side stuff (better overall performance of the server, but not necessarily better for users per se).

    b.

    PS: Did you use PHP-FPM which is included with PHP distribution as of lately?

  43. […] faire beaucoup de config pour simuler les fameux .htaccess. Quand on lis des résultats sur les ban d’essai, on remarque que nginx est en feu pour servir du contenu statique mais pour ce qui est du contenu […]

  44. […] There is a detailed profiling for Apache+mod_php and Nginx+php-fpm done by a linux system engineer in his blog, http://blog.a2o.si/2009/06/24/apache-mod_php-compared-to-nginx-php-fpm/. […]

  45. […] it can take time to tune nginx and php-fpm. If you are switching thinking it will be a fast win for php applications with peformance problems, think again, you need to look at your code. If you serve a lot of static assets, this might be a boost for you. […]

  46. David says:

    You have difference in MaxSpareServers Apache=35, php-fpm=15
    Why only max 16 children in php-fpm ??

  47. bostjan says:

    @David: Thanks for pointing that out!

    At the initial configuration rationale was that if machine has 8 CPUs and they will be fully busy processing application already at 8 max processes, but adjust it to 16 to be on the safe side. Come to think of it, this may have had a non-negligible influence on HelloWorld.php test.

    Although, HelloWorld.php test at lower concurrencies does not yield results that would indicate nginx performing better than Apache. If that were so, it would started better (concurrency 1, 2, 4) and fall significantly at the concurrency 16 or 32, but it does not. This fact – or better, this graph – exhibits no such downstep, and this is the reason I did not consider raising max-children important.

    Anyway, updating an article with a warning, tnx!

  48. […] kracht van nginx komt voort uit het feit dat het gebouwd is met een duidelijk doel voor ogen: hoge performance. Om dit doel te realiseren is nginx ontdaan van iedere vorm van overbodige franje en ontworpen om […]

Leave a Reply

*