Tornado - The fastest WSGI server?

Tornado Python

Tornado is a non-blocking web server from the FriendFeed hackers. There are different hello world benchmarks, but none that are really interesting to me since all of my web-applications are WSGI applications.

I wanted to find out how Tornado performs running WSGI applications. Currently, I run my WSGI applications on CherryPy's WSGI server.

Fortunately, anandology has hacked support for running arbitrary WSGI applications on Tornado. His version seems to be incomplete thought and there are two bugs:

  • StringIO is not imported
  • start_response can take an additional parameter called exec_info

My patch of wsgiserver.py that runs on Tornado can be fetched here:

So how does Tornado perform?

Based on my limited benchmarks, it seems to perform really good and a lot better than CherryPy's WSGI server (at least 2x!) It also seems to scale much better when concurrent connections are increased.

This benchmark is run on rendering a Plurk profile. Both Tornado and CherryPy are proxied to via nginx. CherryPy runs in a threaded mode with 8 threads.

Tornado with concurrency 10

Concurrency Level:      10
Time taken for tests:   13.124 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22546000 bytes
HTML transferred:       22336000 bytes
Requests per second:    76.20 [#/sec] (mean)
Time per request:       131.238 [ms] (mean)
Time per request:       13.124 [ms] (mean, across all concurrent requests)
Transfer rate:          1677.68 [Kbytes/sec] received

CherryPy with concurrency 10

Concurrency Level:      10
Time taken for tests:   34.102 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22473000 bytes
HTML transferred:       22336000 bytes
Requests per second:    29.32 [#/sec] (mean)
Time per request:       341.020 [ms] (mean)
Time per request:       34.102 [ms] (mean, across all concurrent requests)
Transfer rate:          643.55 [Kbytes/sec] received

Tornado with concurrency 100

Concurrency Level:      100
Time taken for tests:   12.020 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      22546000 bytes
HTML transferred:       22336000 bytes
Requests per second:    83.20 [#/sec] (mean)
Time per request:       1201.982 [ms] (mean)
Time per request:       12.020 [ms] (mean, across all concurrent requests)
Transfer rate:          1831.77 [Kbytes/sec] received

CherryPy with concurrency 100

Concurrency Level:      100
Time taken for tests:   60.950 seconds
Complete requests:      1000
Failed requests:        735
   (Connect: 0, Receive: 0, Length: 735, Exceptions: 0)
Write errors:           0
Non-2xx responses:      265
Total transferred:      16659620 bytes
HTML transferred:       16518455 bytes
Requests per second:    16.41 [#/sec] (mean)
Time per request:       6094.989 [ms] (mean)
Time per request:       60.950 [ms] (mean, across all concurrent requests)
Transfer rate:          266.93 [Kbytes/sec] received

Evaluation?

Like I said before one should take benchmarks with a grain of salt. This said, here is what can be seen from my benchmarks:

  • on concurrency level 10 Tornado is over 2 times faster than CherryPy
  • on concurrency level 100 Tornado is around 5 times faster than CherryPy!
  • CherryPy seems to be bad at handling concurrency level 100, failing at 735 of 1000 requests...
  • Tornado seems to scale really well on an increased concurrency. This is probably because of the non-blocking nature
Benchmarks · Code · Python 13. Sep 2009
© Amir Salihefendic. Powered by Skeletonz.