http://www.perlmonks.org?node_id=989939

amasidlover has asked for the wisdom of the Perl Monks concerning the following question:

We have a large (77,000 lines inc POD and comments) application written in Perl and our client has asked us to 'make it faster' we already have a number of strategies for doing this and are tackling performance from multiple angles. However, in a meeting last week they showed us some stats of a PHP app they use along side our app and showed it doing 2,000 concurrent requests on the same hardware that our app only manages 200 concurrent requests on.

Obviously comparing two apps doing different jobs is nonsense, but the scale of difference was so dramatic I decided to see what we would need to do to get our app to that kind of performance. Our assumption, based on timings from debugs, is that talking to the DB (Oracle) is the most time consuming part of our app, so I decided to write a quick test script that did an INSERT and SELECT and then call it lots of times to see how fast it will go on their hardware.

So I wrote the test handler (will paste code and set-up details at end) and ran it on our hardware (not the client's yet), it performed badly... As its a bank holiday and I don't have access to test on their hardware I decided to knock together a PHP script for comparison, the results were quite shocking when loaded with 300 concurrent requests the average response time from the mod_perl handler is 1900ms and from the PHP it is 400ms.

So bearing in mind rewriting our app in PHP is not likely to be cost effective, my questions are:

1) Is my test valid?

2) Can I make the mod_perl version faster (and how)?

3) How much faster?

Server details:- The hardware node is a Quad Core Xeon L5630 @ 2.13GHz with 24Gb RAM, the OS for the Apache virtual machine is Gentoo, the OS for Oracle is Centos 5,.

Versions: OSes both updated within last 2 weeks, Apache version 2.2.22, mod_perl version 2.0.4, DBI Version 1.622, DBD::Oracle version 1.50, Oracle instant client version 10.2.0.3, Oracle Database 10g Express Edition Release 10.2.0.1.0, PHP version 5.3

Things I checked: during the testing the only load was from the test app/oracle, neither virtual machine hit any of its bean counter limits, e.g., memory, Oracle showed 1 session per Apache child at all times, inserts had been done after each run.

Apache config - the mod_perl module was not loaded for the PHP tests and PHP not loaded for the perl tests

PerlRequire "/etc/apache2/startup.pl" PerlModule Apache::DBI PerlModule SQLLoad; PerlModule Apache2::Reload PerlInitHandler Apache2::Reload PerlSetVar ReloadAll Off PerlSetVar ReloadModules "SQLLoad" <Location /sqlload> SetHandler perl-script PerlHandler SQLLoad </Location> <IfModule mpm_prefork_module> ServerLimit 2000 StartServers 1 MinSpareServers 1 MaxSpareServers 1 MaxClients 2000 MaxRequestsPerChild 200 </IfModule>

The Perl code

startup.pl: use DBI (); use CGI (); CGI->compile(':all'); DBI->install_driver("Oracle"); SQLLoad.pm: package SQLLoad; use strict; use Apache2::RequestRec (); use Apache2::RequestIO (); use Apache2::Const -compile => qw(:common); use DBI; use CGI; our $dbh; sub handler { my $r = shift; # Connect to DB $dbh = DBI->connect( "DBI:Oracle:host=oracle.ourdomain.com;port=15 +21;sid=XE", "hr", "password" ) unless $dbh; my $err = ''; # Do the selects my $dbi_query_object = $dbh->prepare("SELECT id FROM zz_system_opt +ions"); $dbi_query_object->execute(); my $dbi_insert_object = $dbh->prepare("INSERT INTO zz_system_options (id,option_name +) VALUES (zz_system_optionsids.nextval,?)"); $dbi_insert_object->execute("load testing"); # Print out some info about this... $r->content_type('text/plain'); $r->print("Errors: \n"); return Apache2::Const::OK; }

The PHP code

$cs = "//oracle.ourdomain.com:1521/XE"; $oc = oci_pconnect("hr","password",$cs); if(!$oc) { print oci_error(); } $stid = oci_parse($oc, 'SELECT id FROM zz_system_options WHERE id = 1' +); oci_execute($stid); $stmt = oci_parse($oc, "INSERT INTO zz_system_options (id,option_name) + VALUES (zz_system_optionsids.nextval,'load testing')"); oci_execute($stmt); echo "hello world";

PHP Results

Concurrency Level: 300 Time taken for tests: 13.286 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 2071035 bytes HTML transferred: 110055 bytes Requests per second: 752.69 [#/sec] (mean) Time per request: 398.569 [ms] (mean) Time per request: 1.329 [ms] (mean, across all concurrent reques +ts) Transfer rate: 152.23 [Kbytes/sec] received

Perl Results

Concurrency Level: 300 Time taken for tests: 63.716 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 1541003 bytes HTML transferred: 130923 bytes Requests per second: 156.95 [#/sec] (mean) Time per request: 1911.488 [ms] (mean) Time per request: 6.372 [ms] (mean, across all concurrent reques +ts) Transfer rate: 23.62 [Kbytes/sec] received

I'm happy to answer more questions about the set-up and try any suggestions. I've done some searching myself and what I've found via Google seems to say a) mod_perl should be faster than mod_php and b) PHP has 'native' DB access code so 'can' be faster for DB access - I've got a fairly big problem though if its going to be 5 times worse under load...

Subsequent edit: SOLVED! Had done the PHP test without https on...