TornadoRocking the Non-Blocking WebContact:Twitter:	Kurtiss Hare, CTO & Co-Founder of playhaven.com@kurtiss
What is Tornado?Scalable, Non-blocking Web ServerPowered www.friendfeed.comNow open-sourced by Facebook after FF acquisition
Why Tornado?
Why Tornado?Paul Buchheit
Why Tornado?Don’tBePaul Buchheit
Why Tornado?Processor/Thread ModelCherryPy, Mod_WSGI, uWSGI, …Lightweight ThreadsGevent, Eventlet, …IOLoop/Callback ModelTornado, Cogen, …What are you trying to do?
Why Tornado?Trying to address the c10k problem?10,000 concurrent connectionsProcessor/thread is known to fall overTrying to enable real-time/long-polling, WebSockets?Different problem than handling many short-lived, pipelined requests.Want to extend your arsenal with a tool that addresses these problems?Tornado might be for you.
Tornado’s Architecture~2000 clientstornado.ioloop._polltornado.web.RequestHandlertornado.httpserver.HTTPServersocket.sockettornado.ioloop.IOStreamtornado.httpserver.HTTPConnectiontornado.web.ApplicationRouting/MVCtornado.ioloop
Tornado’s Architecturetornado.ioloop._pollEdge-triggered when possible (epoll/kqueue)Falls back on level triggered (select)Handles:Callback registrationNew connectionsConnections with new dataHeart of Tornado’s approach to c10k
Hello, worldimport tornado.httpserverimport tornado.ioloopimport tornado.webclass MainHandler(tornado.web.RequestHandler):    def get(self):        self.write("Hello, world")application = tornado.web.Application([    (r"/", MainHandler),])if __name__ == "__main__”:    http_server = tornado.httpserver.HTTPServer(application)    http_server.listen(8888)    tornado.ioloop.IOLoop.instance().start()
Rocking the Non-Blockclass MainHandler(tornado.web.RequestHandler):    @tornado.web.asynchronous    def get(self):        http = tornado.httpclient.AsyncHTTPClient()        http.fetch("http://friendfeed-api.com/v2/feed/kurtiss",                   callback=self.async_callback(self.on_response))    def on_response(self, response):        if response.error: raise tornado.web.HTTPError(500)        json = tornado.escape.json_decode(response.body)        self.write("Fetched " + str(len(json["entries"])) + " entries ”)        self.finish()
Performance NotesSource: http://developers.facebook.com/blog/post/301
Performance NotesBetter ComparisonsNode.js – Tornado by 110% throughput [0]Twisted.Web – Tornado by 84% shorter average response time [1]Caveat Emptor, OK?http://nichol.as/benchmark-of-python-web-serversOf note, “Server Latency,” vs. gEvent, uWSGILikely due to CPU availabilityNothing beats a load test on your own environmentPlayHaven’s use is modest, but growing:<500 concurrent web requestsNo long polling … yet.[0] http://news.ycombinator.com/item?id=1089340[1] http://www.apparatusproject.org/blog/2009/09/twisted-web-vs-tornado-part-deux/
Let’s Code
Questions? Beer?

Tornado web