views:

359

answers:

3

When I update the code on my website I (naturally) restart my apache instance so that the changes will take effect.

Unfortunately the first page served by each apache instance is quite slow while it loads everything into RAM for the first time (5-7 sec for this particular site).

Subsequent requests only take 0.5 - 1.5 seconds so I would like to eliminate this effect for my users.

Is there a better way to get everything loaded into RAM than to do a wget x times (where x is the number of apache instances defined by ServerLimit in my http.conf)

Writing a restart script that restarts apache and runs wget 5 times seems kind of hacky to me.

Thanks!

+2  A: 

How are you running Django (mod_python vs mod_wsgi)?

If you're running mod_wsgi (in daemon mode), restarting Apache isn't necessary to reload your application. All you need to do is update the mtime of your wsgi script (which is done easily with touch).

mod_wsgi's documentation has a pretty thorough explanation of the process:

ReloadingSourceCode

Josh Wright
I've been wondering why it wasn't reloading the application! I'll have to replace my restart script with a touch wsgi script :) will that solve my first load issue though? or do I still need wget?
Jiaaro
It will reduce the time spent on the first load, but it won't eliminate it.
Josh Wright
A: 

You can solve a lot of issues as I found out using memcached

Another thing which I did for a high volume site is a create a cached page of the front page using a cache like Perlball

ramdaz
You'd still have the same problem with memcached (time to instantiate first object).
Kurt
+10  A: 

The default for Apache/mod_wsgi is to only load application code on first request to a process which requires that applications. So, first step is to configure mod_wsgi to preload your code when the process starts and not only the first request. This can be done in mod_wsgi 2.X using the WSGIImportScript directive.

Presuming daemon mode, which is better option anyway, this means you would have something like:

# Define process group.

WSGIDaemonProcess django display-name=%{GROUP}

# Mount application.

WSGIScriptAlias / /usr/local/django/mysite/apache/django.wsgi

# Ensure application preloaded on process start. Must specify the
# process group and application group (Python interpreter) to use.

WSGIImportScript /usr/local/django/mysite/apache/django.wsgi \
  process-group=django application-group=%{GLOBAL}

<Directory /usr/local/django/mysite/apache>

# Ensure application runs in same process group and application
# group as was preloaded into on process start.

WSGIProcessGroup django
WSGIApplicationGroup %{GLOBAL}

Order deny,allow
Allow from all
</Directory>

When you have made a code change, instead of touch the WSGI script file, which is only checked on the next request, send a SIGINT signal to the processes in the daemon process group instead.

With the 'display-name' option to WSGIDaemonProcess you can identify which processes by using BSD style 'ps' program. With 'display-name' set to '%{GROUP}', the 'ps' output should show '(wsgi:django)' as process name. Identify the process ID and do:

kill -SIGINT pid

Swap 'pid' with actual process ID. If more than one process in daemon process group, send signal to all of them.

Not sure if 'killall' can be used to do this in one step. I had problem with doing it on MacOS X.

In mod_wsgi 3.X the configuration can be simpler and can use instead:

# Define process group.

WSGIDaemonProcess django display-name=%{GROUP}

# Mount application and designate which process group and
# application group (Python interpreter) to run it in. As
# process group and application group named, this will have
# side effect of preloading application on process start.

WSGIScriptAlias / /usr/local/django/mysite/apache/django.wsgi \
  process-group=django application-group=%{GLOBAL}

<Directory /usr/local/django/mysite/apache>
Order deny,allow
Allow from all
</Directory>

That is, no need to use separate WSGIImportScript directive as can specific process group and application group as arguments to WSGIScriptAlias instead with side effect that it will preload application.

Graham Dumpleton