1. 云栖社区>
  2. 博客>
  3. 正文


天飞.h 2016-05-09 11:00:45 浏览817


apache -vs- nginx
The choice used to be clear:

  • You want convenience – go with Apache
  • If you want speed – then it’s Nginx

Or lighttpd. Or whatever, but NOT Apache web server. Sometimes they were even used in conjunction – Nginx on the front, to spoon-feed slower client connections and serve static content (using almost no memory for that), and Apache at the back, to generate dynamic content.

Digital ocean has covered the practical considerations of running one or the other (or both) very nicely, so I’m not going to. What I am going to tell you though is that it is outdated. Long gone the days when Nginx had a significant advantage over Apache.

If you run a dynamic website, such as WordPress, Apache can now be just as good in terms of speed, so instead of rushing over to Nginx, I’d like to suggest an alternative approach.

Disclaimer: this article is mostly focused on websites running on PHP, it is however also relevant to those running dynamic websites using any other apache module, such as mod_python, mod_ruby, mod_perl etc.


You know what used to be the main problem with Apache? It’s that it was only possible to serve dynamic websites through Apache modules. For example, to serve a PHP-based website, Apache would use a module calledmod_php (module, that many websites use to this day) and that module used heaps of memory (pun intended).

Yet the actual problem was that one httpd process was only able to handle one connection at a time (think of httpd process as a separate program on your server that doesn’t like sharing resources with other programs).

So even if you were only serving static files such as css filesjavascripts or images, Apache used separate processes to serve them, and all the extra memory. Whereas Nginx used so called events-based architecture that allowed single process to handle hundreds of connections.

What you may not know though, is that in version 2.4 (which has been around since 2012), Apache can now use the same method to handle connections, which Nginx used to be famous for.

Yes, now a single Apache process can handle tens, hundreds or even thousands of connections.


To prove it, I want to share results from two sets of benchmarks I ran with each web server:

  1. Serving static content
  2. Serving dynamic content

Both benchmarks were done on the same 4-core machine with 7.5G of RAM, configured to best of my knowledge.


Let’s start with static files. For this test, I used the same 150kb jpeg image file and I just kept fetching it at an increasing number of parallel requests using ab.

One thing I was interested in was how many such requests each one will handle per second. Here’s a result that says it all:

10770 req/s
20232 req/s

I take it you’re laughing out loud right now. Clearly Nginx smashed Apache into pieces. Well laugh no more and here’s why: unless your server is only serving static content, this benchmark is pretty much irrelevant.

Let me say that again The results of this bechmark are only interesting if you are using your server for static content mostly rather than generating PHP or some other dynamic content.

If you are indeed serving static content only, then by all means go with Nginx, especially if you’re either already running more than one server, or considering running one more because your current static content server can hardly keep up.

Otherwise, here’s one thing from this particular benchmark that did interest me: how much memory will the server consume during the test? Here’s the result:


The reason it is interesting, is that with a typical Apache configuration (e.g. mod_php), such a test would have killed Apache almost instantly.

Apache would have used the entire server memory and the server would have slowed down to a crawl. As a safeguard, one would likely have configured it to only serve a hundred or so requests in parallel, but then a lot of the requests would’ve been queued up and, consequentially, they would’ve take even more time to complete.

To summarize the results of this first test, when configured properly, Apache is now capable of handling an impressive amount of concurrent requests with very low memory footprint and in that regard, it is an acceptable choice even if your server is only serving static files.


This is where things get really exciting.

If you are considering Apache or Nginx for your dynamic website, be it WordPress, Joomla, Drupal or any other 3rd party or in-house web app, what your server will be doing most of the time is running code.

In fact, the amount of time spent serving static files will be disproportionally low compared to dynamic content, therefore it’s way more important to see how well can Apache handle dynamic content and how that compares to Nginx.

Drumroll, please!

108 req/s
108 req/s

Exactly! They’re the same.

And the reason results are the same is that both Apache and Nginx are pretty much sleeping during this test. All they do is pass the request on to php-fpm (we’ll talk about it more later), wait for a response and then send it back to the user. And while they wait, they can keep serving static files without any need to launch extra processes for that.

In terms of memory, both servers have used the same amount of memory too.

So, when it comes to dynamic websites, Apache is now just as good an alternative as Nginx or any other events-based web server. And the reason is exactly that – Apache can now use events-based approach too, as long as you configure it to do so.


I mentioned in the beginning that Apache can be configured to use events instead of processes since version 2.4. Truth is, it has been available since 2.2, except that in version 2.2 it was considered experimental and in order to use this new approach, you would have to rebuild the server. Let’s not go down that path and switch to 2.4 instead (if you have not done so yet).

Before we configure Apache though, we must first set up php-fcgi. We’ll use php-fpm (which stands for PHP FastCGI Process Manager) that will act as a server that we’ll be forward requests to for PHP processing.


Depending on the OS and repository you are using, the actual command to get php-fpm installed will be different. I will assume CentOS/RHEL 6 but feel free to adapt it to your distribution of choice. On CentOS you would install it with:

There are several configuration files involved (could vary between different distributions):

We’ll use a stock configuration file /etc/php-fpm.d/www.conf and we’ll make a few small changes:

Also it’s good to know what the main php-fpm controls are:

Once you’re done with the changes, start it and configure to start during server startup:


First, check the version of Apache httpd server you are using (httpd -V should do it) and if you’re still on 2.2, let’s set up 2.4. One way to do it on CentOS 6 is through “CentOS Software Collections”:

It will install Apache 2.4 with all of the files and configuration under /opt/rh/httpd24/root/etc/httpd/. I’ll leave all of the standard configuration options for you to handle (there’s usually not much to change there anyways), but here’s what you want to do to start using events-based architecture:

Now create a new file, say, 05-php.conf to configure Apache to php-fpm interface:

And start the server:

If you’re upgrading from 2.2, it’s probably a good idea to first start this new Apache on an alternative port, say 81 (that’s maybe as simple as changing Listen directive) and test it before you commit to the change. Once you’re good with it though, stop the old apache and reconfigure the startup options:


Apache httpd is a great web server and the new mpm_event module takes it to entirely new heights. Nginx can still outdo Apache in some edge cases (i.e. serving static content only), but when it comes to dynamic websites, which most of the web 2.0 is built on, Apache is now just as good of a choice as Nginx. And if you are already running mpm_event based configuration, I’d recommend to focus your optimization efforts elsewhere rather than looking at Nginx as an opportunity.


I wrote a little while ago about how, for running PHP, Nginx was not faster than Apache.  At first I figured that it would be and then it turned out not to be, though only by a bit.

But since Apache also has an event-based MPM I wanted to see if the opposite results were true; that if Apache were using its event MPM it would be about the same as Nginx.  I had heard that Apache 2.2’s event MPM wasn’t great (it was experimental) but that 2.4 was better, possibly even faster, than Nginx.

So I had a few spare moments this Friday and figured I would try it out.   I basically ran ab at concurrency levels of 1, 10, 25, 50, 100 and 1000.  Like before the results surprised me.


The first run with Nginx was impressive.  It peaked at 14,000 requests per second.  Given my wimpy VM that  I ran it on, those numbers are pretty good.  What surprised me was that Apache was only half that.  I will say for the record that I do not know how to tune the event MPM.  But I don’t really have to tune Nginx to get 14k requests per second so I was expecting a little better from Apache.  So I pulled out all of the LoadModule statements I could but still have a functional implementation of Apache.  While the numbers were 25% better or so they were still well shy of what Nginx was capable of.  Then I added the prefork MPM to provide a baseline.  Again, I was surprised.  The event MPM was faster than the prefork MPM for static content, but not by much.

So it seems that if you are serving static content Nginx is still your best bet.  If you are serving static content from a CDN or have a load balancer in front of Apache which is running PHP then the prefork MPM is the way to go.  While the event MPM will help with concurrency it will not help you speed up PHP and so is not really needed.


Apache 2.4 vs Nginx Benchmark Showdown

Disclaimer: This test was highly unscientific, with a +/- 10% fabricated margin of error.  No maths were performed to gather proper averages and statistics.  No effort was made to ensure consistency of the two Apache builds and no legitimate effort was made with regard to proper scientific rigor during this test.  This test does not take into account memory usage, responsiveness of the server under load, or any other relevant metric that would be of more use than this test.  I highly encourage you to do your own testing and draw your own conclusions. 

How the tests were performed: 
I wanted to simulate a VPS environment similar to a basic Linode.  A base install of Ubuntu Server 10.04 was installed in VMWare with an older/slower 7200RPM sata drive for storage.  This drive was not in use by any other system during the test, nor were any other VMs active on the host.  The guest was given 512MB of RAM and 1 CPU core of the host's 8 cores.  The host's CPUs are dual Xeon X5365 @ 3Ghz. 

Apache 2.2 was installed along with nginx 0.7.65, later Apache 2.4 was compiled on this same system.

Testing was performed using Apache JMeter on an 8 core Xeon workstation running Windows 7 and 32GB of RAM  with a 1Gb/s link to the VMWare host.  Requests per second were determined by rounding off the throughput displayed in the Summary Report listener.  Each test was run until the requests per second stabilized. 

The Apache 2.2 server was only tested with the Prefork MPM, while the Apache 2.4 server was tested with both Prefork and Event.  Apache's KeepAlive setting was on throughout the testing and set at 2 seconds.

I received several requests to post memory usage statistics so I've updated the Jquery test with memory results.  Again, care was not taken to keep the Apache builds consistent.  It concerns me that the Prefork build of Apache 2.4 was using so much memory compared to the other Apache builds.  Take these results with a grain of salt, but trust that Nginx definitely uses significantly less memory than Apache.

Update 2 - Nginx 1.0.12:
I received some flak for using an older version of Nginx, so I tested with Nginx 1.0.12 and it was around 4% slower than the results shown here.

Test 1 - 21KB text file
HTTP Server Req/s
Apache 2.2 Prefork 2220
Apache 2.4 Prefork 2250
Apache 2.4 Event 2300
Nginx 2600

Test 2 - 2B text file consisting of a single period.
HTTP Server Req/s
Apache 2.2 Prefork 4400
Apache 2.4 Prefork 4700
Apache 2.4 Event 4810
Nginx 6650

Test 3 - jquery.min.js (92KB)

HTTP Server Req/s Memory Usage
Apache 2.2 Prefork 650 12MB
Apache 2.4 Prefork 770 72MB
Apache 2.4 Event 820 20MB
Nginx 1000 2MB

Test 4 - PHP output of phpinfo()
HTTP Server Req/s
Apache 2.2 Prefork 525
Apache 2.4 Prefork 575
Nginx FastCGI 450




+ 关注