3. ‣ huge potential userbase
‣ live sports events
1.000.000 ‣
‣
changing business model
unknown user behavior
‣ “beta” - small investment
‣ gotta keep it simple!
4. “It's time for web servers to handle ten thousand clients simultaneously,
don't you think? After all, the web is a big place now.”
5. as simple as you need - as robust as you want
nginx nginx tornado mongo
frontend backend
filer
filesystem
6. ‣ “there’s a lot of caching”
‣ scores, current transmissions etc. are updated quickly
‣ out of bounds to the general public - closed beta
‣ authentication and authorization from separate systems
‣ just checking if cookies exist on the frontend
7. import tornado.ioloop
import tornado.web
‣ plain Python class MainHandler(tornado.web.RequestHandler):
def get(self):
‣ good looking Python self.write("Hello, world")
‣ sweet! application = tornado.web.Application([
(r"/", MainHandler),
])
‣ fast!
if __name__ == "__main__":
‣ ab req/s: 2987.96 application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
8. import json
import tornado.ioloop
import tornado.web
import tornado.httpclient
search = 'http://search.twitter.com/search.json?
‣ non-blocking web server q=pythonbrasil&result_type=mixed&count=1'
class MainHandler(tornado.web.RequestHandler):
‣ so please don’t block it! def get(self):
self.write("Hello blocking Twitter!n")
http_client = tornado.httpclient.HTTPClient()
‣ the blocking way... response = http_client.fetch(search)
last_tweet = json.loads(response.body)['results'][0]['text']
self.write(last_tweet)
‣ ab req/s: 0.81 application = tornado.web.Application([
(r"/", MainHandler),
(over our poor local wi-fi) ])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
10. import tornado.ioloop
import tornado.web
from db import users
class HomeHandler(tornado.web.RequestHandler):
def get(self):
if 'signed_in' == self.get_secure_cookie('access'):
self.write('Hello to your world!')
else:
self. write('Hello, world!')
‣ secure cookies class SigninHandler(tornado.web.RequestHandler):
def post(self):
if self.get_attribute('login') in users:
‣ not persisted self.set_secure_cookie('access', 'signed_in',
expires_days=None)
self.redirect('/')
‣ served from any class SignoutHandler(tornado.web.RequestHandler):
def get(self):
instance self.clear_cookie('access')
self.redirect('/')
application = tornado.web.Application([
(r"/", HomeHandler), (r"/signin", SigninHandler),
(r"/signout", SignoutHandler),
], **{
'cookie_secret': 'i_should_be_reading_that_from_env'
})
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
11. ‣ what else?
‣ templates extensions
‣ semi-standardized project structure
‣ pre-rendered data for frequently updated data - scores
12. ‣ most URLs are served as fast
as nginx can
‣ on a single 24 processors
17.000 server our load tests got us
to 17k req/s served by
Tornado
‣ few pages with heavy DB
access served less than 4k
req/s