SaltyCrane Blog — Notes on JavaScript and web development

Notes on switching my Djangos to mod_wsgi

I'm slowly trying to make my Django web servers conform to current best practices. I've set up an Nginx reverse proxy for serving static files, started using virtualenv to isolate my Python environments, and migrated my database to PostgreSQL. I ultimately want to implement memcached+Nginx caching in my reverse proxy, but the next task on my to-do list is switching from mod_python to mod_wsgi.

Within the past year (or maybe before), mod_wsgi has become the preferred method for serving Django applications. I also originally thought switching from mod_python to mod_wsgi would save me some much needed memory on my 256MB VPS. But after trying it out, running with a single Apache process in each case, the memory footprint was about the same. Even switching from mod_wsgi's embedded mode to daemon mode didn't make a significant difference. Likely the performance is better with mod_wsgi, though.

Here are my notes on installing mod_wsgi.

Configuration References

Advice from mod_wsgi author Graham Dumpleton

Install mod_wsgi and apache mpm-worker

I'm not 100% sure about prefork vs. worker mpm, but Graham Dumpleton favors worker mpm.

sudo apt-get install libapache2-mod-wsgi
sudo apt-get install apache2-mpm-worker

Create .wsgi application file

My virtualenv is located at /srv/python-environments/saltycrane. My Django settings files is at /srv/SaltyCrane/iwiwdsmi/settings.py.

/srv/SaltyCrane/saltycrane.wsgi:

import os
import sys
import site

site.addsitedir('/srv/python-environments/saltycrane/lib/python2.5/site-packages')

os.environ['DJANGO_SETTINGS_MODULE'] = 'iwiwdsmi.settings'

sys.path.append('/srv/SaltyCrane')

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Edit Apache's httpd.conf file

I went back and forth between using embedded mode or daemon mode. I've ended up with embedded mode for now since it seems to use a tad less memory and is supposed to be a little bit faster. However, Graham Dumpleton seems to recommend daemon mode for people on VPSs. I may change my mind again later. To use daemon mode, I just need to uncomment the WSGIDaemonProcess and WSGIProcessGroup lines. I have StartServers set to 1 because I can only afford to have one Apache process running. This is assuming nginx is proxying requests to apache. For more on my nginx setup, see here.

Edit /etc/apache2/httpd.conf:

<IfModule mpm_worker_module>
    StartServers 1
    ServerLimit 1
    ThreadsPerChild 5
    ThreadLimit 5
    MinSpareThreads 5
    MaxSpareThreads 5
    MaxClients 5
    MaxRequestsPerChild 500
</IfModule>

KeepAlive Off
NameVirtualHost 127.0.0.1:8080
Listen 8080

<VirtualHost 127.0.0.1:8080>
    ServerName www.saltycrane.com
    # WSGIDaemonProcess saltycrane.com processes=1 threads=5 display-name=%{GROUP}
    # WSGIProcessGroup saltycrane.com
    WSGIScriptAlias / /srv/SaltyCrane/saltycrane.wsgi
</VirtualHost>

<VirtualHost 127.0.0.1:8080>
    ServerName supafu.com
    # WSGIDaemonProcess supafu.com processes=1 threads=5 display-name=%{GROUP}
    # WSGIProcessGroup supafu.com
    WSGIScriptAlias / /srv/Supafu/supafu.wsgi
</VirtualHost>

<VirtualHost 127.0.0.1:8080>
    ServerName handsoncards.com
    # WSGIDaemonProcess handsoncards.com processes=1 threads=5 display-name=%{GROUP}
    # WSGIProcessGroup handsoncards.com
    WSGIScriptAlias / /srv/HandsOnCards/handsoncards.wsgi
</VirtualHost>

Restart Apache

sudo /etc/init.d/apache2 restart

Comments


#1 Graham Dumpleton commented on :

You don't need to use 'processes=1' as WSGIDaemonProcess defaults to single process if that option is not used. If you do use 'processes' option, even for '1' process, it has side effect of setting 'wsgi.multiprocess' to be 'True' rather than 'False'. This is intentional to provide a wide of saying a single process is part of a multiprocess application when load balancing across multiple servers each with a single daemon mode process. In your case, still having 'wsgi.multiprocess' be 'False' is better as technically then allows you to use WSGI debuggers or components which can only function when application is within a single process and so guaranteed that requests always return to same process.

Other than that, if you are restricting Apache to single server child process, then yes, memory usage wouldn't be terribly different in the context of a fat Python web application, compared to using mod_python.


#2 Eliot commented on :

Graham, Thanks very much for your response! I will try removing the processes=1 option when using daemon mode.

Thank you for confirming my experience with memory usage of mod_python and mod_wsgi for a single process. I originally had a lot of Apache processes and ran into memory problems and I had to reduce the number of processes-- eventually to 1.


#3 Rama Vadakattu commented on :

Thanks for sharing your notes.iam also planning to move from mod_python to mod_wsgi.


#4 Eliot commented on :

Rama, you're welcome. Good luck with your move!