It all started with
this topic on the forum , when many seriously began to argue, they say, nginx is not at all faster than Apache, and even the translation of documentation from the official site was not convincing. As you know, there is nothing more enjoyable than testing and displaying a graph to attract attention. For example, the graph for the total load on the server, try to guess where is the Nginx testing stage, and where is Apache.

Well, before you find out the right answer - a little about the server and the testing mechanism.
In order to eliminate any suspicion of “spinning up” their VDS, the test was conducted on a third-party server, which was kindly provided to me by one of the forum participants for this test in this configuration:
AMD Athlon X2 5600+ 4 GB DDR2 2 × 400 GB HDD with Linux Debian in minimal install. All software was installed in a standard way - via apt-get. Both PHP and Apache were set in minimal mode.
For the test object, I set up a very light blog, Moscquito, which works without MySQL, writing a couple of posts and comments there.
First of all I want to say that before starting the benchmark Nginx and Apache, I restarted the server. The network subsystem was a little twisted up for faster work:
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"
sysctl -w sysctl net.ipv4.tcp_window_scaling=1
sysctl -w sysctl net.ipv4.tcp_timestamps=1
sysctl -w sysctl net.ipv4.tcp_sack=1
sysctl -w net.ipv4.tcp_no_metrics_save=1
sysctl -w net.ipv4.tcp_moderate_rcvbuf=1
sysctl -w net.core.netdev_max_backlog=1000
sysctl -w net.ipv4.tcp_congestion_control=htcp
sysctl -w net.core.somaxconn=1000
ifconfig eth0 txqueuelen 1000
And the limits were raised for the correct operation of the tested and benchmarks themselves:
ulimit -s unlimited
ulimit -n 1024000
For both web servers, the timeout was set to 300 seconds (standard for Apache, it is less in Nginx).
PHP-FPM
The processes were tied to a TCP socket, two pools were created with 4 processes each in a static mode.
nginx
Two workers on 10240 connections each, php is connected as upstream:
upstream php {
server 127.0.0.1:9000 max_fails=1 fail_timeout=60s;
server 127.0.0.1:9001 max_fails=1 fail_timeout=60s;
}
')
Apache
Keepalive is disabled, and MaxClients and ServerLimit are set to 10240
Now about the benchmark
I tried to create a site situation under a DDOS attack, when 20k bots were hammering into the main page, and 5,000 legal users walk through the site.
An improvised DDOS attack can be easily done with ab. But for users it was necessary to generate
a site map and set siege on it.
Testing took an hour and the site availability record was logged using ab. Here are the two commands that I launched in parallel in the screen:
while true; do ab -r -t 300 -n 20000 -c 20000 213.239.211.15 >> nginx.log; sleep 5; done
while true; do siege -i -f urllist.txt -c 5000 -b -t1M ; sleep 5; done
Naturally, for a benchmark with an apache, the log was written in apache.log
Go to the charts

As you can see, the number of processes changed only while Apache was running, well, it was not for nothing that MPM was called Prefork. Nginx and PHP-FPM are static, which is a big plus.

Unfortunately, the memory graph turned out to be not very beautiful, but if you look closely, Apache consumes more memory.


The graphs of switching between processes and their forks correlate very interestingly among themselves.

The layout for recycling CPU is also clearly not in favor of Apache.
Break through the logs
Nginx:
# grep -c Failed nginx.log
38
# grep Failed nginx.log | grep -v 'Failed requests: 0'
Failed requests: 10629
Decryption - in an hour of work, a bunch of Nginx + PHP-FPM managed to go through 38 iterations and fill up one of them - 10,629 erroneous requests. This was due to the inaccessibility of upstream - siege tried, running most of the requests to the main page.
Apache:
# grep -c Failed apache.log
23
# grep Failed apache.log | grep -v 'Failed requests: 0'
Failed requests: 8730
Failed requests: 2124
Failed requests: 10539
Failed requests: 7599
Failed requests: 6027
Failed requests: 1986
Failed requests: 7578
Failed requests: 270
Failed requests: 9819
Failed requests: 60
Failed requests: 9369
Failed requests: 8193
Failed requests: 10248
Failed requests: 684
Failed requests: 7968
But with Apache everything is bad - even if we cross out 2 “successful” siege hits, there are still errors + in the allotted time fewer requests were made.
Thus, according to the test results, the Nginx + PHP-FPM bundle defeats Apache with a score of 38:23