Segfault > IT > Webserver > PHP acceleration for Apache

(16.Nov.2011)


Introduction

I tried multiple times to use a PHP accelerator (APC, eAccelerator and XCache) to generate less load on the server when PHP-pages are created (and therefore render them on the screen faster).

Unluckily it never worked well - the server stopped to respond, memory consumption increased endlessly, etc... .
E.g. when testing the server's stability with ...

httperf --hog --server myserver.com --num-conn 100 --ra 10 --timeout 5

...or when just simulating a reload (happens when my cron job archives the old server logs)...

/etc/init.d/apache reload

...I was seeing in "apache/error_log" each time error messages similar to these ones:

[Wed Nov 16 20:09:34 2011] [notice] child pid 32387 exit signal Segmentation fault (11)
[Wed Nov 16 20:10:31 2011] [notice] child pid 32564 exit signal Bus error (7)

Additionally the server stopped responding and the browser displayed just a blank page waiting for a reply from the server.
Even after shutting down apache (/etc/init.d/apache stop) I was still seeing processes (with "ps -Af | grep -i apache") hanging around for 10 seconds or more:

[Wed Nov 16 20:12:07 2011] [warn] child process 32766 still did not exit, sending a SIGTERM
[Wed Nov 16 20:12:07 2011] [warn] child process 340 still did not exit, sending a SIGTERM
[Wed Nov 16 20:12:09 2011] [error] child process 32635 still did not exit, sending a SIGKILL

I gave it up for a while but a few days back I found out something interesting.


Problem solved

Seeing that I had segmentation faults I thought that it might be thread-related so I started investigating into the area of Apache's Multi-Processing Modules (MPMs).

I saw Apache was using - at least for the Linux distribution that I am using ("Gentoo") - the "worker" MPM, which apparently uses threads to handle user requests.
A variant was apparently the "prefork" MPM, which from what I read in the docs "...implements a non-threaded, pre-forking web server..." so I gave it a try.

To activate the "prefork" MPM I did the following:

  • I set the compilation option in "/etc/make.conf" to "prefork" (other distros use probably just a config file to define which MPM to use without the need to compile anything?)
    APACHE2_MPMS="prefork"
  • I changed in "/etc/portage/package.use" the use flag for apache to not to use threads (otherwise "emerge" refused to compile Apache - probably only needed in Gentoo?):
    www-servers/apache -threads
  • I changed in "/etc/portage/package.use" the use flag for PHP to not to use threads (otherwise "emerge" refused to compile Apache - probably only needed in Gentoo?):
    dev-lang/php -threads

After recompiling PHP and Apache I restarted the webserver and all problems vanished - it is now working perfectly.

No problems even when stressing the single Apache processes by making them run with minimal settings like (set them in "/etc/apache2/httpd.conf")

StartServers 2
ServerLimit 10
MinSpareServers 2
MaxSpareServers 2


Benchmark - setup

Having now all 3 PHP accelerators working I did a simple test to get an idea of which one was better.

I did all tests by querying the first page of a standard insallation of Concrete5 and all the tests were done as follows:

httperf --hog --server myserver.com --num-conn 200 --ra 10 --timeout 5

The Versions of the PHP accelerators I used were:

  • dev-php/pecl-apc-3.1.7
  • dev-php/eaccelerator-0.9.6.1-r4
  • dev-php/xcache--1.3.1

 

Other informations:

  • www-servers/apache-2.2.21-r1
  • Kernel: 2.6.39-gentoo-r3
  • CPU: Intel(R) Core(TM)2 Quad CPU    Q6600  @ 2.40GHz
  • RAM: 4GB
  • Apache running the the minimal settings mentioned above.
  • All tests done while having "suhosin" active - no scope of doing tests without something that I would definitely use in a productive environment.

Each test was repeated twice - the first time to check how much time the PHP accelerator needed to compile the code for the first time (to see how long it takes for a user that ends up on a page that isn't yet cached) and the second time to check how fast the page is when accessing the cached data (for all subsequent accesses).

All tests were done on the same server hosting Apache - to avoid interferences due to the Internet connection.


Benchmark - raw results

Normal - No acceleration

  • 1st run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 20.014 s

    Connection rate: 10.0 conn/s (100.1 ms/conn, <=2 concurrent connections)
    Connection time [ms]: min 111.1 avg 115.0 max 140.8 median 114.5 stddev 4.0
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (100.1 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 9.8 avg 10.0 max 10.0 stddev 0.1 (4 samples)
    Reply time [ms]: response 115.0 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 5.82 system 14.14 (user 29.1% system 70.7% total 99.7%)
    Net I/O: 53.8 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
  • 2nd run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 20.015 s

    Connection rate: 10.0 conn/s (100.1 ms/conn, <=2 concurrent connections)
    Connection time [ms]: min 110.9 avg 115.3 max 142.2 median 114.5 stddev 4.6
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (100.1 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 9.8 avg 10.0 max 10.0 stddev 0.1 (4 samples)
    Reply time [ms]: response 115.3 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 5.61 system 14.37 (user 28.0% system 71.8% total 99.9%)
    Net I/O: 53.8 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

APC

  • 1st run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.943 s

    Connection rate: 10.0 conn/s (99.7 ms/conn, <=2 concurrent connections)
    Connection time [ms]: min 41.3 avg 44.2 max 152.0 median 43.5 stddev 8.1
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.7 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 44.2 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 6.04 system 13.89 (user 30.3% system 69.7% total 99.9%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
  • 2nd run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.942 s

    Connection rate: 10.0 conn/s (99.7 ms/conn, <=1 concurrent connections)
    Connection time [ms]: min 41.0 avg 43.0 max 49.9 median 42.5 stddev 1.5
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.7 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 43.0 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 6.01 system 13.92 (user 30.1% system 69.8% total 99.9%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)

    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

eAccelerator

  • 1st run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.944 s

    Connection rate: 10.0 conn/s (99.7 ms/conn, <=3 concurrent connections)
    Connection time [ms]: min 42.2 avg 47.3 max 317.6 median 43.5 stddev 23.4
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.7 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 47.3 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 6.10 system 13.84 (user 30.6% system 69.4% total 99.9%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
  • 2nd run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.942 s

    Connection rate: 10.0 conn/s (99.7 ms/conn, <=1 concurrent connections)
    Connection time [ms]: min 41.7 avg 44.1 max 75.5 median 43.5 stddev 3.9
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.7 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 44.1 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 6.03 system 13.90 (user 30.2% system 69.7% total 99.9%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

XCache

  • 1st run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.948 s

    Connection rate: 10.0 conn/s (99.7 ms/conn, <=4 concurrent connections)
    Connection time [ms]: min 45.0 avg 50.7 max 331.5 median 47.5 stddev 24.3
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.7 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 50.7 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 5.91 system 14.03 (user 29.6% system 70.3% total 100.0%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
  • 2nd run:

    Maximum connect burst length: 1
    Total: connections 200 requests 200 replies 200 test-duration 19.954 s

    Connection rate: 10.0 conn/s (99.8 ms/conn, <=1 concurrent connections)
    Connection time [ms]: min 44.7 avg 49.1 max 99.8 median 48.5 stddev 5.8
    Connection time [ms]: connect 0.0
    Connection length [replies/conn]: 1.000

    Request rate: 10.0 req/s (99.8 ms/req)
    Request size [B]: 58.0

    Reply rate [replies/s]: min 10.0 avg 10.0 max 10.0 stddev 0.0 (3 samples)
    Reply time [ms]: response 49.1 transfer 0.0
    Reply size [B]: header 329.0 content 5128.0 footer 0.0 (total 5457.0)
    Reply status: 1xx=0 2xx=200 3xx=0 4xx=0 5xx=0

    CPU time [s]: user 5.88 system 14.07 (user 29.4% system 70.5% total 99.9%)
    Net I/O: 54.0 KB/s (0.4*10^6 bps)
    Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
    Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Benchmark - results summary

1st run

Well, referring to the "max" column, it seems that when the PHP accelerators have to save for the first time the PHP code that is compiled, the response takes more than double as much time to get back to the user.
An exception is the APC accelerator, which is practically as fast as when Apache is running with no PHP accelerator installed.

2nd run

During the second run an Apache that does not have a PHP accelerator still needs of course the same time as during the first run, but I see that all other timings have decreased quite a lot, where APC seems to be the best one (at least with the page of Concrete5 that I tested).

APC seems therefore to be the winner.


Conclusion

It's since 2 weeks that I am using APC and didn't experience any problem so far.
Good work guys!

Homepage: http://pecl.php.net/APC
Configuration settings: http://www.php.net/manual/en/apc.configuration.php

APC's most important people - as of Nov.16 (2011)
George Schlossnagle (lead)
Daniel Cowgill (lead)
Rasmus Lerdorf (lead)
Gopal Vijayaraghavan (lead)
Edin Kadribasic (developer)
Ilia Alshanetsky (developer)
Marcus Börger (developer)
Sara Golemon (developer)
Brian Shire (developer)
Kalle Sommer Nielsen (developer)
Pierre Joye (developer)