SlideShare a Scribd company logo
globo   Tornado + Nginx = 17k req/s
.com
two servers, one goal
‣   huge potential userbase
            ‣   live sports events

1.000.000   ‣

            ‣
                changing business model
                unknown user behavior
            ‣   “beta” - small investment
            ‣   gotta keep it simple!
“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.”
as simple as you need - as robust as you want


    nginx          nginx         tornado        mongo
  frontend        backend




                     filer
                 filesystem
‣   “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
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()
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()
import json
                                     import tornado.ioloop
                                     import tornado.web
                                     import tornado.httpclient
                                     from tornado.web import asynchronous

                                     search = 'http://search.twitter.com/search.json?
                                     q=pythonbrasil&result_type=mixed&count=1'
‣   the non-blocking way...          class MainHandler(tornado.web.RequestHandler):

    ‣   ab req/s: 7.25                   @asynchronous
                                         def get(self):
                                             self.write("Hello blocking Twitter!n")
        (over our poor local wi-fi)           http_client = tornado.httpclient.AsyncHTTPClient()
                                             response = http_client.fetch(search, self.handle_response)

                                         def handle_response(self, response):
                                             last_tweet = json.loads(response.body)['results'][0]['text']
                                             self.finish(last_tweet)

                                     application = tornado.web.Application([
                                         (r"/", MainHandler),
                                     ])

                                     if __name__ == "__main__":
                                         application.listen(8888)
                                         tornado.ioloop.IOLoop.instance().start()
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()
‣   what else?
    ‣   templates extensions
    ‣   semi-standardized project structure
    ‣   pre-rendered data for frequently updated data - scores
‣   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
Valeu!
Danilo Moret - Globo.com / Webmedia / Vídeos 3
moret@corp.globo.com - http://moret.pro.br/ - @moret1979

More Related Content

PPTX
Tornado web
PPTX
Python, async web frameworks, and MongoDB
PDF
An Introduction to Tornado
PDF
Tornado in Depth
PDF
Tornado Web Server Internals
PPTX
Tornado - different Web programming
PDF
Tornadoweb
PDF
Rapid web development using tornado web and mongodb
Tornado web
Python, async web frameworks, and MongoDB
An Introduction to Tornado
Tornado in Depth
Tornado Web Server Internals
Tornado - different Web programming
Tornadoweb
Rapid web development using tornado web and mongodb

What's hot (20)

PPT
Real time server
PDF
Even faster django
KEY
Building a real life application in node js
KEY
PyCon US 2012 - State of WSGI 2
PPTX
Java script at backend nodejs
PDF
What is nodejs
PDF
Coroutines for Kotlin Multiplatform in Practise
PPTX
introduction to node.js
PDF
Web Crawling with NodeJS
PDF
用Tornado开发RESTful API运用
PDF
Introduction to Flask Micro Framework
KEY
Writing robust Node.js applications
PDF
Original slides from Ryan Dahl's NodeJs intro talk
PPT
RESTful API In Node Js using Express
KEY
A language for the Internet: Why JavaScript and Node.js is right for Internet...
KEY
Introduction to node.js
PDF
Nodejs Explained with Examples
KEY
node.js: Javascript's in your backend
PDF
Node.js - A Quick Tour
PPTX
Phl mongo-philly-tornado-2011
Real time server
Even faster django
Building a real life application in node js
PyCon US 2012 - State of WSGI 2
Java script at backend nodejs
What is nodejs
Coroutines for Kotlin Multiplatform in Practise
introduction to node.js
Web Crawling with NodeJS
用Tornado开发RESTful API运用
Introduction to Flask Micro Framework
Writing robust Node.js applications
Original slides from Ryan Dahl's NodeJs intro talk
RESTful API In Node Js using Express
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Introduction to node.js
Nodejs Explained with Examples
node.js: Javascript's in your backend
Node.js - A Quick Tour
Phl mongo-philly-tornado-2011
Ad

Similar to Nginx + Tornado = 17k req/s (20)

PDF
服务框架: Thrift & PasteScript
PDF
An opinionated intro to Node.js - devrupt hospitality hackathon
PDF
Flask patterns
PDF
Implementing new WebAPIs
PDF
Implementing New Web
PDF
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
PDF
Build powerfull and smart web applications with Symfony2
PPT
Sanjeev ghai 12
KEY
A language for the Internet: Why JavaScript and Node.js is right for Internet...
PDF
Developing Cacheable PHP Applications - PHP SP 2024
PPTX
Async task, threads, pools, and executors oh my!
PPTX
Serverless archtiectures
PPTX
Practical AngularJS
PDF
Weave Your Microservices with Istio
PDF
All Things Open 2019 weave-services-istio
PDF
Ato2019 weave-services-istio
PDF
Tasks: you gotta know how to run them
PDF
The Open Web and what it means
PDF
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
PDF
Using google appengine
服务框架: Thrift & PasteScript
An opinionated intro to Node.js - devrupt hospitality hackathon
Flask patterns
Implementing new WebAPIs
Implementing New Web
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Build powerfull and smart web applications with Symfony2
Sanjeev ghai 12
A language for the Internet: Why JavaScript and Node.js is right for Internet...
Developing Cacheable PHP Applications - PHP SP 2024
Async task, threads, pools, and executors oh my!
Serverless archtiectures
Practical AngularJS
Weave Your Microservices with Istio
All Things Open 2019 weave-services-istio
Ato2019 weave-services-istio
Tasks: you gotta know how to run them
The Open Web and what it means
IstSec'14 - İbrahim BALİÇ - Automated Malware Analysis
Using google appengine
Ad

Recently uploaded (20)

PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PDF
cuic standard and advanced reporting.pdf
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Spectral efficient network and resource selection model in 5G networks
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Empathic Computing: Creating Shared Understanding
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
Big Data Technologies - Introduction.pptx
PDF
KodekX | Application Modernization Development
PDF
Modernizing your data center with Dell and AMD
PDF
Approach and Philosophy of On baking technology
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
cuic standard and advanced reporting.pdf
MYSQL Presentation for SQL database connectivity
Dropbox Q2 2025 Financial Results & Investor Presentation
Spectral efficient network and resource selection model in 5G networks
The AUB Centre for AI in Media Proposal.docx
Network Security Unit 5.pdf for BCA BBA.
Building Integrated photovoltaic BIPV_UPV.pdf
Empathic Computing: Creating Shared Understanding
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
Big Data Technologies - Introduction.pptx
KodekX | Application Modernization Development
Modernizing your data center with Dell and AMD
Approach and Philosophy of On baking technology
Understanding_Digital_Forensics_Presentation.pptx
Diabetes mellitus diagnosis method based random forest with bat algorithm

Nginx + Tornado = 17k req/s

  • 1. globo Tornado + Nginx = 17k req/s .com
  • 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()
  • 9. import json import tornado.ioloop import tornado.web import tornado.httpclient from tornado.web import asynchronous search = 'http://search.twitter.com/search.json? q=pythonbrasil&result_type=mixed&count=1' ‣ the non-blocking way... class MainHandler(tornado.web.RequestHandler): ‣ ab req/s: 7.25     @asynchronous     def get(self):         self.write("Hello blocking Twitter!n") (over our poor local wi-fi)         http_client = tornado.httpclient.AsyncHTTPClient()         response = http_client.fetch(search, self.handle_response)     def handle_response(self, response):         last_tweet = json.loads(response.body)['results'][0]['text']         self.finish(last_tweet) application = tornado.web.Application([     (r"/", MainHandler), ]) 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
  • 13. Valeu! Danilo Moret - Globo.com / Webmedia / Vídeos 3 moret@corp.globo.com - http://moret.pro.br/ - @moret1979

Editor's Notes