Nginx, gunicorn, FreeBSD and some jails

I was wondering what impact on performances can a jail have, so I made a VM and, installed a fresh FreeBSD 9.1, setup nginx on host, and tried various configurations for gunicorn, running a django application in and outside of jail.

Summary

For the impatient a small summary in a table. The values are in requests per second.

| -      | TCP          | UNIX         |
| ------ | ---          | ----         |
| Native | 769 (96.97%) | 793 (100%)   |
| Jail   | 708 (89.28%) | 731 (92.18%) |

If you want more, keep reading, you can also reach to the end directly to my conclusions.

Testing procedure

This benchmark has been done inside a kvm virtual machine on my main computer, all test running the same vm with the same version of kvm to be the performances were relevant to each other.

Software used in the VM:

  • OS

    • FreeBSD 9.1 amd64
    • Jails base system were installed from FreeBSD 9.1 base system
  • Service

    • Django 1.4.3
    • Python 2.7.2
    • Nginx 1.2.8
    • Gunicorn 0.17.2
  • Benchmark

    • Siege 2.70

I provided siege with an url file containing only urls served by the Django application, avoiding all static files served directly by nginx as they are not relevant to this test.

The Django web application is my girlfriend's website running locally, accessed via a localhost address, but that should be sufficient as what we want here is to compare the same test with changing parameters.

Setup

In both setup, the socket can be either TCP on UNIX and both will be tested.

Native

 +----+----------------------------+
 |host|                            |
 +----+                            |
 |                                 |
 |  +-----+    tcp     +--------+  |
 |  |NGINX|------------|gunicorn|  |
 |  +-----+   socket   +--------+  |
 |     |                           |
 |   +-----+                       |
 |   |siege|                       |
 |   +-----+                       |
 |                                 |
 +---------------------------------+

Nginx configuration for TCP:

location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 20;
    proxy_read_timeout 20;
    proxy_pass http://127.0.0.1:8000
}

Nginx configuration for UNIX:

location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 20;
    proxy_read_timeout 20;
    proxy_pass http://unix:/tmp/django.sock;
}

Jail

+----+----------------------------+
|host|             +----+--------+|
+----+             |jail|        ||
|                  +----+        ||
|  +-----+    tcp  |  +--------+ ||
|  |NGINX|---------|--|gunicorn| ||
|  +-----+   socket|  +--------+ ||
|     |            |             ||
|   +-----+        |             ||
|   |siege|        |             ||
|   +-----+        |             ||
|                  +-------------+|
+---------------------------------+

Nginx configuration for TCP:

location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 20;
    proxy_read_timeout 20;
    proxy_pass http://jail_ip:8000
}

Nginx configuration for UNIX:

location / {
    proxy_pass_header Server;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_connect_timeout 20;
    proxy_read_timeout 20;
    proxy_pass http://unix:/tmp/django.sock;
}

Siege Results

Native TCP

siege -b -c 10 -t30S -f urls_dj.txt > /dev/null
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege...

Lifting the server siege...      done.
Transactions:                  22544 hits
Availability:                 100.00 %
Elapsed time:                  29.30 secs
Data transferred:              35.21 MB
Response time:                  0.01 secs
Transaction rate:             769.50 trans/sec
Throughput:                     1.20 MB/sec
Concurrency:                    9.97
Successful transactions:       21924
Failed transactions:               0
Longest transaction:            0.05
Shortest transaction:           0.00

Native UNIX

siege -b -c 10 -t30S -f urls_dj.txt > /dev/null  _24.png">
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege...

Lifting the server siege...      done.
Transactions:                  23614 hits
Availability:                 100.00 %
Elapsed time:                  29.77 secs
Data transferred:              36.88 MB
Response time:                  0.01 secs
Transaction rate:             793.33 trans/sec
Throughput:                     1.24 MB/sec
Concurrency:                    9.98
Successful transactions:       22964
Failed transactions:               0
Longest transaction:            0.06
Shortest transaction:           0.00

Jail TCP

siege -b -c 10 -t30S -f urls_dj.txt > /dev/null [230/462]
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege...

Lifting the server siege...      done.
Transactions:                  21234 hits
Availability:                 100.00 %
Elapsed time:                  29.95 secs
Data transferred:              33.62 MB
Response time:                  0.01 secs
Transaction rate:             708.91 trans/sec
Throughput:                     1.12 MB/sec
Concurrency:                    9.97
Successful transactions:       20644
Failed transactions:               0
Longest transaction:            0.07
Shortest transaction:           0.00

Jail UNIX

siege -b -c 10 -t30S -f urls_dj.txt > /dev/null
** SIEGE 2.70
** Preparing 10 concurrent users for battle.
The server is now under siege...

Lifting the server siege...      done.
Transactions:                  21960 hits
Availability:                 100.00 %
Elapsed time:                  30.01 secs
Data transferred:              34.78 MB
Response time:                  0.01 secs
Transaction rate:             731.81 trans/sec
Throughput:                     1.16 MB/sec
Concurrency:                    9.97
Successful transactions:       21357
Failed transactions:               0
Longest transaction:            0.07
Shortest transaction:           0.00

Conclusions

  • Fastest is obviouly the Native UNIX test, which will be used as a 100% reference.
  • Both TCP on UNIX socket shows about 8% performance loss when running in jail.
  • TCP impact is about the same between native and jailed, a tad over 3% slower than UNIX.

graph