<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Brandon&#039;s Blog &#187; benchmark</title>
	<atom:link href="http://www.brandonturner.net/blog/tag/benchmark/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.brandonturner.net/blog</link>
	<description>Random thoughts on web applications, software development and Linux</description>
	<lastBuildDate>Thu, 08 Apr 2010 01:47:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>FastCGI with a PHP opcode cache benchmarks</title>
		<link>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/</link>
		<comments>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 05:32:17 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Server Admin]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[fastcgi]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[suEXEC]]></category>

		<guid isPermaLink="false">http://www.brandonturner.net/blog/?p=377</guid>
		<description><![CDATA[mod_php and FastCGI performance is very comparable when an opcode cache is utilized.  These benchmarks cover performance and memory usage of mod_php vs FastCGI.]]></description>
			<content:encoded><![CDATA[<p>In my previous post, I described how to implement <a href="/blog/2009/07/fastcgi_with_php_opcode_cache/">FastCGI with a PHP opcode cache</a> on an Apache webserver.  My primary motivation for moving to FastCGI was to take advantage of the extra security provided by FastCGI with suEXEC over mod_php.  In this post, I&#8217;ll compare the two environments and provide a few benchmark results.</p>
<h4>Benchmark Setup</h4>
<p>To compare mod_php to FastCGI with a PHP opcode cache, I used the <a href="http://httpd.apache.org/docs/2.2/programs/ab.html">ab tool</a> on my desktop running PHP 5.3.0, mod_fastcgi 2.4.6 and Apache 2.2.11 on Gentoo linux.  Apache had a limited number of modules enabled (actions alias authz_host dav deflate dir expires filter headers log_config mime rewrite setenvif status vhost_alias).  The hardware consisted of a Intel Core2 Quad Q6600 (2 x 4MB L2 cache) with 2GB of RAM.</p>
<p>I chose to benchmark against the main page of a stock WordPress 2.8.2 install with no plugins enabled.  I chose WordPress because it&#8217;s extremely easy to set up and many people are familiar with it.  I&#8217;ve read that WordPress is very liberal with queries to the database (especially when plugins are involved).  Without database queries, I would expect to see a bigger difference between results with an opcode cache and results without one.  That being said, most PHP applications today make database queries as part of a typical request and thus I think these results are realistic of what you might experience on your server.</p>
<p>I executed the following command:</p>
<div class="prompt">
$ <span class="cmd">ab -n 1000 -c 30 http://localhost/</span>
</div>
<p>in four different environments:</p>
<ul>
<li>mod_php with a 30MB APC opcode cache (Apache MPM prefork)</li>
<li>mod_php without an opcode cache (Apache MPM prefork)</li>
<li>mod_fastcgi, suEXEC with a 30MB APC opcode cache (Apache MPM worker)</li>
<li>mod_fastcgi, suEXEC without an opcode cache (Apache MPM worker)</li>
</ul>
<p>Between each benchmark, I reconfigured and restarted the server.  I then loaded the main page in a web browser to prime the APC cache.</p>
<h4>Benchmark Results</h4>
<h5>Requests</h5>
<div id="attachment_385" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/requests_per_second.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/requests_per_second.png" alt="Graph displaying requests per second of each benchmark scenario" title="Requests per second" width="580" height="300" class="size-full wp-image-385" /></a><p class="wp-caption-text">Requests per second</p></div>
<p>The graph above shows that mod_php and FastCGI behaved very similar in terms of requests per second.  Using an opcode cache increased the request rate by almost 3 times in both scenarios.  As I mentioned earlier, I&#8217;d expect to see an even bigger increase with fewer database queries.</p>
<p>I saw similar results when increasing the number of requests to 10,000, or changing the concurrency level.  I never saw any failed requests.  I was happy to see there wasn&#8217;t a significant performance difference moving from mod_php to FastCGI.</p>
<h5>Memory Usage</h5>
<div id="attachment_384" class="wp-caption aligncenter" style="width: 590px"><a href="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/ram.png"><img src="http://www.brandonturner.net/blog/wp-content/uploads/2009/07/ram.png" alt="Graph displaying memory usage of each benchmark scenario" title="Memory usage" width="580" height="400" class="size-full wp-image-384" /></a><p class="wp-caption-text">Memory usage</p></div>
<p>The graph above shows the approximate memory usage for each of the 4 benchmarking scenarios.  This data was gathered by running the <a href="http://www.pixelbeat.org/scripts/ps_mem.py">ps_mem.py</a> script immediately after the ab tool completed.  This script outputs the private and shared memory usage for each program running on the system.  Because I ran my benchmarks in isolation, with nothing else accessing the host, these results should be pretty accurate.</p>
<p>The results surprised me.  From the graph you can see that disabling the opcode cache resulted in <em>more</em> memory usage.  I think this is misleading.  Typically, Linux keeps memory resident until it is needed by another process.  I believe the increased memory usage for the non-opcode cache scenarios is actually discarded memory that the Linux kernel hasn&#8217;t reclaimed.  Since each process is having to recompile the PHP script on each request, you see a lot more built up memory reported as private but most likely free to be reused.  I suspect running this on a low memory server would yield slightly different results.</p>
<p>You can clearly see the difference in memory usage for the Apache processes (green in the graph) between FastCGI and mod_php.  The FastCGI Apache processes are much leaner.  Since Apache doesn&#8217;t need the PHP bloat, it can serve static content much more effectively and quickly.</p>
<p>The scenarios with an opcode cache each used a similar amount of RAM.  There is a catch to these results however: I only benchmarked a single user.  In a shared environment, each user gets their own PHP instance and opcode cache.  With mod_php, all users share the same.  Thus I would expect every user to roughly double the RAM used in a FastCGI scenario, while mod_php memory usage would stay relatively constant.  This increased memory usage is the main trade-off when going with FastCGI.</p>
<h4>Raw Results</h4>
<p>For those who want even more detail, below are the raw results from my benchmark tests:</p>
<p>mod_php without an opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   28.507 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5717000 bytes
HTML transferred:       5474000 bytes
Requests per second:    35.08 [#/sec] (mean)
Time per request:       855.200 [ms] (mean)
Time per request:       28.507 [ms] (mean, across all concurrent requests)
Transfer rate:          195.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:   138  849 214.5    842    1608
Waiting:      138  848 214.3    842    1601
Total:        139  849 214.4    843    1608

Percentage of the requests served within a certain time (ms)
  50%    843
  66%    911
  75%    975
  80%   1004
  90%   1112
  95%   1230
  98%   1355
  99%   1426
 100%   1608 (longest request)
</pre>
<p>mod_php with opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   10.784 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5717000 bytes
HTML transferred:       5474000 bytes
Requests per second:    92.73 [#/sec] (mean)
Time per request:       323.530 [ms] (mean)
Time per request:       10.784 [ms] (mean, across all concurrent requests)
Transfer rate:          517.70 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:    66  319  62.9    316     580
Waiting:       66  318  62.9    316     580
Total:         67  319  62.8    316     580

Percentage of the requests served within a certain time (ms)
  50%    316
  66%    339
  75%    354
  80%    364
  90%    395
  95%    424
  98%    464
  99%    482
 100%    580 (longest request)
</pre>
<p>FastCGI without an opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   28.170 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5695000 bytes
HTML transferred:       5474000 bytes
Requests per second:    35.50 [#/sec] (mean)
Time per request:       845.104 [ms] (mean)
Time per request:       28.170 [ms] (mean, across all concurrent requests)
Transfer rate:          197.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:   105  832  82.9    832    1004
Waiting:      105  832  82.9    832    1004
Total:        107  832  82.8    832    1004

Percentage of the requests served within a certain time (ms)
  50%    832
  66%    856
  75%    873
  80%    882
  90%    908
  95%    927
  98%    954
  99%    971
 100%   1004 (longest request)
</pre>
<p>FastCGI with opcode cache:</p>
<pre class="brush: plain;">
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)

Server Software:        Apache
Server Hostname:        localhost
Server Port:            80

Document Path:          /
Document Length:        5474 bytes

Concurrency Level:      30
Time taken for tests:   10.917 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      5695000 bytes
HTML transferred:       5474000 bytes
Requests per second:    91.60 [#/sec] (mean)
Time per request:       327.509 [ms] (mean)
Time per request:       10.917 [ms] (mean, across all concurrent requests)
Transfer rate:          509.44 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:    46  323  36.6    325     426
Waiting:       46  323  36.6    325     426
Total:         47  323  36.5    325     426

Percentage of the requests served within a certain time (ms)
  50%    325
  66%    335
  75%    342
  80%    346
  90%    359
  95%    368
  98%    383
  99%    389
 100%    426 (longest request)
</pre>
<p>Memory Usage (in MB):</p>
<table>
<tr>
<th rowspan="2">Benchmark</th>
<th colspan="3" style="text-align: center;">Apache</th>
<th colspan="3" style="text-align: center;">PHP</th>
<th rowspan="2">Total</th>
</tr>
<tr>
<th>private</th>
<th>shared</th>
<th>total</th>
<th>private</th>
<th>shared</th>
<th>total</th>
</tr>
<tr>
<th>mod_php, no cache</th>
<td>202.3</td>
<td>7.7</td>
<td>210</td>
<td></td>
<td></td>
<td></td>
<td><b>210</b></td>
</tr>
<tr>
<th>mod_php, with cache</th>
<td>45.3</td>
<td>15.5</td>
<td>60.8</td>
<td></td>
<td></td>
<td></td>
<td><b>60.8</b></td>
</tr>
<tr>
<th>FastCGI, no cache</th>
<td>9.2</td>
<td>3.3</td>
<td>12.5</td>
<td>68.3</td>
<td>5.0</td>
<td>73.3</td>
<td><b>85.8</b></td>
</tr>
<tr>
<th>FastCGI, with cache</th>
<td>9.2</td>
<td>3.6</td>
<td>12.8</td>
<td>23.4</td>
<td>13.8</td>
<td>37.2</td>
<td><b>50</b></td>
</tr>
</table>
<h4>Conclusion</h4>
<p>I run my blog on a <a href="http://www.linode.com/">Linode VPS</a> with a very limited amount of RAM.  I also host other applications and a few friends&#8217; sites on this same server.  Thus, I am very concerned about memory usage.  Still, the security advantages provided by FastCGI far outweigh the increased RAM usage.</p>
<p>I hope you have seen that the performance of FastCGI with an opcode cache is just as good as with mod_php.  It&#8217;s also evident how important an opcode cache is to running PHP scripts.</p>
<p>If you have any thoughts about these benchmarks, or the performance of FastCGI vs mod_php, feel free to leave a comment or question below!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonturner.net/blog/2009/07/fastcgi_php_opcode_cache_benchmarks/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
