I'm on Ubuntu where mpm-prefork is the only way Apache can run with PHP (i.e. if I install php5 it automatically installs mpm-prefork even if I wanted worker.)

My problem is that each Drupal page takes a minimum of 5 seconds to load (more than 10 if I request more than one page at once.) An example outline line from the Devel plugin:

Executed 37 queries in 30.5 milliseconds. Queries taking longer than 5 ms and queries executed more than once, are highlighted. Page execution time was 5286.25 ms.

If I start a new mysql console on the web machine, it takes around 5 seconds to login to mysql on the database machine. This didn't seem like a coincidence to me, so with a bit of poking around (ps and netstat) I managed to confirm that a fresh connection to the mysql database was being established for every single request.

I'm using mysqli so using pconnect to try and dodge the problem doesn't appear to be a viable solution (though maybe switching back to mysql is, there is plenty of documentation saying that mysqli is "better".) I have attempted to set up FastCGI, and have in fact succeeded in setting it up but it has not improved the problem. Now what happens is, the php5-cgi processes *do* sit around, but they still connect to mysql every single page hit.

So what I'm looking for is a way around this problem. More than likely this is not Drupal's fault, but something wrong with how Ubuntu's Apache config is managing its child processes.

My mpm-prefork config in apache2.conf looks like this (the default?):

<IfModule prefork.c>
StartServers         5
MinSpareServers      5
MaxSpareServers     10
MaxClients          20
MaxRequestsPerChild  0
</IfModule>

My virtual host config:

<VirtualHost *:443>
    ServerAdmin sysadmin@drupal
    DocumentRoot /var/www/drupal
    ServerName drupal
    ErrorLog /var/log/apache2/drupal_ssl_error_log
    CustomLog /var/log/apache2/drupal_ssl_access_log common

    SSLEngine on
</VirtualHost>

<Directory /var/www/drupal>
    Allow from 192.168.222
    Order allow,deny
    SSLRequireSSL

    # Next three lines added to enable FastCGI - original attempt lacked these.
    AddHandler fcgid-script .php
    Options +ExecCGI
    FCGIWrapper /var/www/cgi-bin/php-wrap .php
</Directory>

The php-wrap script mentioned up there looks like this:

#!/bin/sh
PHP_FCGI_CHILDREN=4
export PHP_FCGI_CHILDREN
PHP_FCGI_MAX_REQUESTS=5000
export PHP_FCGI_MAX_REQUESTS
exec /usr/bin/php5-cgi "$@"

I should add that there is a Ruby on Rails application on the same server using the same database server and that there are no performance issues with that application, which is also using FastCGI.

Comments

damien tournoud’s picture

I should add that there is a Ruby on Rails application on the same server using the same database server and that there are no performance issues with that application, which is also using FastCGI.

It doesn't quite add up with that last information, but slow connection times like those are generally due to DNS issues. Try to confirm that the MySQL server can resolve the host name of the web server from its IP address properly and in a timely manner?

kbahey’s picture

I agree with Damien

Those are often DNS issues. Seems like an internal network trying to resolve the name of the server.

Either :

1. Add the host name of the db server to the /etc/hosts file on the web head, or

2. Just use the IP address like so:

$db_url = 'mysqli://username:password@10.1.1.1/dbname';

The only catch here is that you say RoR does work fine. Perhaps it is using the IP address of the server?

You can also verify if the command line mysql command takes a lot of time to load with the same host specified via the -h parameter.

Trejkaz’s picture

Additional information to confirm it's not DNS:

1. The host it's connecting to has an entry in /etc/hosts

2. This command takes around 5 seconds to connect: mysql -u drupal -p -h 192.168.222.123 drupal6
(It asks for the password straight away, and then takes around 5 seconds after entering it to open the connection.)

I think the fundamental problem here is that Drupal / PHP should be keeping the connection open, as connecting to a database is fundamentally an expensive operation. I'm sure on healthy systems it does work like this, but there is something funny going on with ours.

damien tournoud’s picture

I tried to point you in another direction in #1: even if the forward resolution works correctly, the MySQL server will have to do a reverse lookup of the IP of the web node to get its hostname. Please confirm that this reverse lookup works correctly. One way to do this is to run "host " on the database node.

Database connections are not cheap, but clearly shouldn't take 5 seconds.

kbahey’s picture

Indeed try what Damien said (add the other machine in the /etc/hosts of the database server).

Also try this:

mysql --skip-auto-rehash -u USER -p -h 192.168.222.123 drupal6

See if it made any difference.

For MySQL, connecting has almost no overhead, so it does not suffer from what other database solve via persistent connections.

Trejkaz’s picture

Status: Active » Closed (fixed)

Bingo... this helps a lot. Who would have thought that it would need to do it in reverse if all my grant rules are by IP anyway... *facepalm*

Apache is still dropping the processes as soon as one request goes through, but now the page render time is around 500ms, with the database query taking up around 150ms of that. Hopefully the remaining time is executing the PHP, which a persistent connection wouldn't help anyway unless I started to use one of those accelerators which cache the compiled PHP code...