March 14, 2015 will

Saving processes and threads in a WSGI server with Moya

I have a webserver with 3 WSGI applications running on different domains (1, 2, 3). All deployed with a combination of Gunicorn and NGINX. A combination that works really well, but there are two annoyances that are only going to get worse the more sites I deploy:

A) The configuration for each server resides in a different location on the filesystem, so I have to recall & type a long path to edit settings.

B) More significantly, each server adds extra resource requirements. I follow the advice of running each WSGI application with (2 * number_of_cores + 1) processes, each with 8 threads. The threads may be overkill, but that ensures that the server can use all available capacity to handle dynamic requests. On my 4 core server, that's 9 processes, 72 threads per site. Or 27 processes, and 216 threads for the 3 sites. Clearly that's not scalable if I want to host more web applications on one server.

A new feature recently added to Moya fixes both those problems. Rather than deploy a WSGI application for each site, Moya can now optionally create a single WSGI application that serves many sites. With this new system, configuration is read from /etc/moya/, which contains a directory structure like this:

|-- logging.ini
|-- moya.conf
|-- sites-available
| |-- moyapi.ini
| |-- moyaproject.ini
| `-- notes.ini
`-- sites-enabled
|-- moyapi.ini
|-- moyaproject.ini
`-- notes.ini

At the top level is “moya.conf” which contains a few server-wide settings, and “logging.ini” which contains logging settings. The directories “sites-available” and “sites-enabled” work like Apache and NGINX servers; settings for each site are read from “sites-enabled”, which contains symlinks to files in “sites-available”.

Gunicorn (or any other wsgi server) can run these sites with a single instance by specifying the WSGI module as “moya.service:application”. This application object loads the sites from “sites-available” and is responsible for dispatching requests based on domains specified in the INI files.

Because all sites now go through a single Gunicorn instance, requests are shared amongst one optimal pool of processes / threads. This keeps the memory footprint low and negates the need to allocate resources based on traffic.

This new multi-server system is somewhat experimental, and hasn't been documented. But since I believe in eating my own dog-food, it has been live now for a whole hour–with no problems.

Use Markdown for formatting
*Italic* **Bold** `inline code` Links to [Google](http://www.google.com) > This is a quote > ```python import this ```
your comment will be previewed here
gravatar
Venelin Styokov
This looks very nice, bit I have one question. What about virtual environments? If every site use different virtual environment to track all of its dependencies then you can't use single gunicorn to serve all websites.
Is there a workaround or you need to forget about Moya and just run different gunicorn instances but with lowering the number of process/threads per site (especially if the site is not so popular and don't have so many visitors at the same time)

Actually in your variant I will try with only 4 process per site without threads.
gravatar
WIll McGugan
Venelin, this wouldn't work with virtualenvs. Don't think you have much options there, except to allocate resources like you suggested.
gravatar
Aigars Mahinovs
Why not simply switch to a smarter WSGI server, such as UWSGI? https://uwsgi-docs.readthedocs.org/en/latest/Emperor.html
gravatar
Will McGugan
Aigars, I didn't know uwsgi had such features. Thanks for the heads up.
gravatar
Aiden Smith
This is because mod_wsgi does not pass OS environment variables to the underlying application by default
gravatar
slav0nic
Why another framework? what wrong with django, pyramid, flask?
will be have answer for this question in the docs)