Saturday, October 15, 2011

Nginx with php-fpm versus apache with modphp

I have been using apache with modphp for ages now. It works like a charm. But as the concurrency increases, apache chews up a lot of resources. I came across nginx some time back. It is a very light weight server which I had used earlier to serve static content. I thought why not try it to serve dynamic pages as well. After some searching, i found that nginx with php-fpm is a lethal combination as a dynamic web server.

php-fpm stands for php fastcgi process manager. It is a fastcgi implementation of php with some additional features. Have a look here http://php-fpm.org/

So without getting too much into the technicalities, lets focus on the benchmark. I did a benchmark on my laptop which has a i5 processor and 4 GB of ram. Running ubuntu 11.10 - kernel 3.0.0.12 64 bit. The software versions which i used were

php-5.3.8
apache 2.2.19
nginx 1.1.5
XCache v1.3.2


Benchmark process :
First i compiled php with apache using the following configure command.

'./configure' --with-apxs2=/usr/local/apache2/bin/apxs '--with-gd' '--with-curl' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--enable-mbstring'

Ran my tests and then compiled the php again with fpm, configured nginx and ran the benchmark again.

To compile php with fpm do

'./configure' '--enable-fpm' '--with-fpm-user=jayant' '--with-fpm-group=jayant' '--with-gd' '--with-curl' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--enable-mbstring'


I ran tests for 3 levels of concurrency 100, 500 and 1000 for 10 minutes each. The code that i was benchmarking was simple phpinfo with a random number display. I used siege for benchmarking.

x.php
------
<?php
echo "Random : ".rand(1,100000).'
';
phpinfo();
?>

nginx with php-fpmapache with mod php

concurrency : 100
Time : 10 min
siege -i -c 100 -t 10m http://localhost/x.php
Load : 0.10

Lifting the server siege... done.
Transactions: 118171 hits
Availability: 100.00 %
Elapsed time: 599.56 secs
Data transferred: 6611.79 MB
Response time: 0.00 secs
Transaction rate: 197.10 trans/sec
Throughput: 11.03 MB/sec
Concurrency: 0.96
Successful transactions: 118171
Failed transactions: 0
Longest transaction: 0.07
Shortest transaction: 0.00

concurrency : 100
Time : 10 min
siege -i -c 100 -t 10m http://localhost/x.php
Load : 0.25

Lifting the server siege... done.
Transactions: 118688 hits
Availability: 100.00 %
Elapsed time: 599.55 secs
Data transferred: 7278.54 MB
Response time: 0.01 secs
Transaction rate: 197.96 trans/sec
Throughput: 12.14 MB/sec
Concurrency: 0.99
Successful transactions: 118688
Failed transactions: 0
Longest transaction: 0.09
Shortest transaction: 0.00

siege -i -c 500 -t 10m http://localhost/x.php
concurrency : 500
Time : 10 min
Load : 2.0

Lifting the server siege... done.
Transactions: 589098 hits
Availability: 100.00 %
Elapsed time: 599.44 secs
Data transferred: 32960.63 MB
Response time: 0.01 secs
Transaction rate: 982.75 trans/sec
Throughput: 54.99 MB/sec
Concurrency: 7.59
Successful transactions: 589098
Failed transactions: 0
Longest transaction: 3.23
Shortest transaction: 0.00

siege -i -c 500 -t 10m http://localhost/x.php
concurrency : 500
Time : 10 min
Load : 20

siege aborted due to excessive socket failure; you
can change the failure threshold in $HOME/.siegerc
Transactions: 45954 hits
Availability: 97.36 %
Elapsed time: 50.84 secs
Data transferred: 2818.13 MB
Response time: 0.02 secs
Transaction rate: 903.89 trans/sec
Throughput: 55.43 MB/sec
Concurrency: 14.47
Successful transactions: 45954
Failed transactions: 1248
Longest transaction: 3.30
Shortest transaction: 0.00

siege -i -c 1000 -t 10m http://localhost/x.php
concurrency : 1000
Time : 10 min
Load : 48

Lifting the server siege... done.
Transactions: 941105 hits
Availability: 99.98 %
Elapsed time: 599.43 secs
Data transferred: 52655.81 MB
Response time: 0.14 secs
Transaction rate: 1570.00 trans/sec
Throughput: 87.84 MB/sec
Concurrency: 213.57
Successful transactions: 941105
Failed transactions: 167
Longest transaction: 21.17
Shortest transaction: 0.00

siege -i -c 1000 -t 10m http://localhost/x.php
concurrency : 1000
Time : 10 min
Load : 58

siege aborted due to excessive socket failure; you
can change the failure threshold in $HOME/.siegerc
Transactions: 45454 hits
Availability: 96.86 %
Elapsed time: 36.27 secs
Data transferred: 2787.47 MB
Response time: 0.19 secs
Transaction rate: 1253.21 trans/sec
Throughput: 76.85 MB/sec
Concurrency: 240.04
Successful transactions: 45454
Failed transactions: 1475
Longest transaction: 9.37
Shortest transaction: 0.00

As you can see apache buckles its knees and stops responding at a concurrency of 500. The load shot upto 20 in just 50 seconds and there are lots of socket errors. Siege gave up the benchmark stating that there are too many errors. Whereas nginx+php-fpm runs well with a concurrency of 500 with 0 failed transactions. In fact when apache+modphp is aborted by siege in just 36 seconds due to excessive errors for a benchmark with concurrency of 1000. Nginx runs for the whole 10 minutes and with a success rate of 99.98%.

Without any doubt i can conclude that nginx with php-fpm is the web server for large scale websites.

4 comments:

anuraag said...

A good benchmark jayant. Of course the php file used is trivial. Nine the less its an interesting result. Nginx+phpfpm demands to be explored more.
-anuraag

Parth Lawate said...

Just getting my hands dirty with some hands on load testing.. So probably a silly question !

Any idea why there is a diff in no of transactions & Data transferred though there are no errors in either case ?

Jayant Kumar said...

@Parth, There are lots of errors in apache+mod-php case. You can see the following output in the tests.

siege aborted due to excessive socket failure;

Anonymous said...

It is also worth noting that apache can run using php-fpm and that helps quite a bit. That especially can help if static assets are involved.