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
5 comments so far

"TORNADO WITH CONCURRENCY 100"--Time taken for tests: 12.020 seconds
TORNADO WITH CONCURRENCY 10 ---Time taken for tests: 13.124 seconds
why???
清晨迷雾

Hi amix, again you're up to the latest Python buzz :D

I'd be especially interested in a comparison to Spawning (http://pypi.python.org/pypi/Spawning) as another non-blocking server (though CherryPy has a good reputation as WSGI server, regardless of the framework part).

Jochen:
Interesting, I haven't heard about Spawning. Do you know more about this project? It seems to be last updated in January this year.

amix: I saw it quite some time ago in the Cheese Shop, but recently heard about it again and gave it a short try. Made a good impression on me, but I didn't get around to deploying it in production or benchmarking it so far.

The author of Spawning also develops the eventlet library (http://wiki.secondlife.com/wiki/Eventlet), which seems to originate from Second Life creator Linden Lab. I guess Spawning is somewhat stable and feature-complete by now, so the latest release is not that recent.

Here is a post on it by Eric Florenzano: http://www.eflorenzano.com/blo...

We've (blogg.se, yo.se) been running Spawning for a good while now. Haven't dug into benchmarks (usually no need since bottlenecks isn't found in web servers) - but Spawning gives me a "good feeling". Very easy to deploy (except daemonizing), starts and maintains threads/workers/processes as you wish and is built upon greenlet (think: stackless "tasklets") which is very lightweight.

I think most Python web servers has excellent diversity of functionality but fails in deploying and integration with your common init/start-stop-daemon setup.

(Yes – we're one of them that think Apache isn't the solution for everything)

Post a comment
Commenting on this post has expired.
© 2000-2009 amix. Powered by Skeletonz.