Já se foi o tempo em que para se desenvolver uma aplicação web em Python se utilizava o bom e velho mod_wsgi do Apache para servi-lá. Essa arquitetura vem deixando de ser utilizada por não escalar e performar tão bem como soluções que integram application servers escritos em Python com web servers como Apache e Nginx.
No meu último projeto, precisamos implementar uma solução em python altamente performática. Quando entrei nesse projeto a estrutura que definimos como inicial era a tradicional, quando digo tradicional entenda Apache + mod_wsgi. Não tinhamos muita experiência em desenvolvimento focado em performance, e foi bem difícil encontrar cases de sucesso que pudessem nos guiar. Diria que quando decidimos implementar o novo Cartola FC, fantasy game oficial do campeonato brasileiro, em python, entramos em um túnel completamente apagado e sem luz no final, fomos na cara e na coragem, a fim de provar que performance e escalabilidade não estão ligadas a linguagem e sim a arquitetura da sua aplicação.
Após definir que faríamos em python, pelos benefícios que a linguagem trás, começamos a pensar o que seria a arquitetura ideal de uma aplicação web escrita 100% em Python. Como não tinhamos muito tempo, definimos a estrutura tradicional e seguimos em frente no desenvolvimento, sem deixar de continuar pesquisando a melhor solução.
Após algumas semanas de testes com Apache + mod_wsgi, vimos que não chegava nem perto do que queríamos. Precisávamos de uma aplicação que atendesse 3 mil requisições simultâneas, por máquina. O mod_wsgi não chegava nem perto disso, além de travar com frequência. Foi nesse momento que encontrei uma apresentação feita na pycon de 2007, Scaling Python for High-Load Web Sites, que caiu como uma luva para o nosso problema. Por que não utilizar um web server escrito em Python? Pois é, pensei a mesma coisa!
Agora vem a segunda pergunta, qual utilizar? Sem tempo a perder inciamos os testes com o CherryPy, podereso e consolidado Python web server que se mostrou robusto e performático nos testes inciais. Só que como você já sabe, nosso problema principal é performance e como atender muitas requisições simultâneas. Sobre as requisições simultâneas, descobri que não era um problema tão novo, como relatado no The C10K Problem (o problema das 10 mil conexões simultâneas), e percebi que a solução passaria necessáriamente por um web server non-blocking I/O. Aconselho a leitura do post do Akita, que faz uma imersão legal sobre non-blocking.
CherryPy apesar de ser um excelente framework, não era non-blocking e isso representaria um problema para nossas pretenções. Pequisando sobre python web server non-blocking, descobri 2 bem legais, um é o Twisted, e o outro nosso amigo Tornado. Twisted é uma engine de rede escrita em python, com suporte a diversos protocolos e com um web server non-blocking. Ele é bem completo e complexo, talvez por isso a opção pelo Tornado, que é um framework bem enxuto, com um poderoso web server non-blocking e muito simples de ser implementado.
Antes de prosseguir na escolha do melhor python web server, nos questionamos sobre o uso do tradicional Apache. Lembro que começamos com aquela estrutura tradicional, que caiu por terra com o uso de um web server escrito em python, então porquê continuar com o Apache? Ele só serviria para fazer proxy com a instância do servidor da aplicação, isso enquanto tinhamos uma única instância de CherryPy rodando por máquina, agora já temos inúmeras instâncias, e como balancear a carga entre elas? Simples, utilizando o Nginx!

O Nginx foi uma descoberta e tanto, ele é um servidor HTTP, assim como o Apache, só que possui alguns módulos bem interessantes, dentre eles o HTTP Upstream, que faz balanceamento de carga via proxy com o servidor da aplicação. Além de possuir esse módulo, o Nginx é um dos inúmeros servidores escritos para resolver o The C10K Problem, pois implementa non-blocking I/O com uso de epoll event handler. Utilizando Nginx, estaríamos tratando nossas inumeras conexões simultâneas no front end e balanceando a carga entre as instâncias dos servidores de aplicação. Isso melhorou radicalmente nosso desempenho, saimos de 200 conexões simultâneas com apache+mod_wsgi para 3 mil conexões simultâneas, sem consumo de memória e com pouco uso de CPU. Agora já podemos voltar nossas atenções para o application server, que passa a ser o nosso limitante.

Resolvemos então fazer uma implementação com o Tornado e confrontar os resultados dos testes com o CherryPy. Com o CherryPy o throughput não se mantia estável com o aumento no número de usuários simultâneos, além do alto consumos de CPU por cada instância. Já com o Tornado esses números foram animadores, o throughput se mantia linear e estável a medida que aumentávamos o número de usuários simultâneos, além do baixo consumo de CPU e consumo quase 0 de memória.
Nesse momento havíamos definido nossa arquitetura final, quase no quarto mês de um projeto que seria finalizado no seu sexto mês, nada mal! Essa arquitetura contava com 9 máquinas (Intel Quad-Core Xeon 2.5 GHz), cada máquina rodando um Nginx, balanceando a carga entre 7 servidores de aplicação construídos com Tornado, onde cada máquina pode processar 300 R/S (requisições por segundo) que dá 3K conexões simultâneas, pois uma média de 10% das conexões estabelecidas estão realizando alguma operação simultâneamente.
Para quem entrou em um túnel totalmente escuro, acredito que saímos do outro lado com um belo legado de conhecimento e descobertas que pretendo ir compartilhando com vocês. A primeira e mais importante descoberta que fizemos foi essa, performance independe de linguagem. Construa uma boa arquitetura para sua aplicação, e se ela for escrita em python, aconselho utilizar Nginx + Tornado, pois funcionam muito bem juntos. Nos meus próximos posts, irei falar bastante do Tornado e sobre como extrair o máximo dele.
Qualquer dúvida ou sugestão, deixe seu comentário aqui em baixo, terei o maior prazer em respondê-lo.
8 Comments to “Python Web Performance, apache+modwsgi ou nginx+tornado?”
Post comment
sobre mim
Analista de sistemas, comecei a trabalhar em 2005 como desenvolvedor web, em petrópolis, minha cidade natal. Em 2007 ingressei na globo.com, onde tive a oportunidade participar de grandes projetos, como o portal móvel da globo.com, Temporeal e Cartola. Possuo conhecimentos avançados em Python, Java e PHP, com foco em performance e escalabilidade para sistemas de grande porte, além de ser entusiasta de metodologias e práticas ágeis de desenvolvimento. Participo de algumas das maiores comunidades de desenvolvimento, colaborando com alguns projetos open source. Tive o prazer de palestrar em alguns dos maiores eventos do brasil, como LinuxCon Brasil 2010 e Python Brasil 2010. Hoje em dia trabalho na minha própria empresa, onde venho me aventurando no mundo empreendedor.
@marcelnicolay
- Tambem sou filho de deus neh... Depois de trabalhar nesse sábados sol, uma parada certa! (@ Bar Pavāo Azul) http://t.co/5Lem6IvY 3 days ago
- Bendita seja... http://t.co/n0dj8wTh 4 days ago
- I just unlocked the “Flame Broiled” badge on @foursquare! Cheeseburgers all around! http://t.co/GD24zZlG 1 week ago
- More updates...
Posting tweet...



Felipe Pavao says:
Realment o cartola deu uma aula de inovacão. Parabéns aos amigos que participaram do projeto e trouxeram para empresa esses novos conhecimentos.
Abs!
Tweets that mention Python Web Performance, apache+modwsgi ou nginx+tornado? « Marcel Nicolay -- Topsy.com says:
[...] This post was mentioned on Twitter by Pavão Web, marcelnicolay. marcelnicolay said: voltando a postar no meu blog: Python Web Performance, apache+modwsgi ou nginx+tornado? http://twurl.nl/xcb0ww [...]
Demetrius Nunes says:
Excelente post, Marcel! Keep it coming!
Vinicius says:
Excelente post! Uma contribuição e tanto para a comunidade, principalmente no que diz respeito a escalabilidade e performance.
Parabéns
Paulo Suzart says:
Muito bom o post. Melhor ainda é apostar nesta excelente linguagem, e sem perder performance.
Quanto ao Tornado, é uma excelente opção para o GAE (Google App Engine). É possível notar um desempenho absurdamente melhor usando o módulo tornado.web, principalmente no quesito template/renderização. Aliando o Tornado ao memcache você tem uma combinação matadora no GAE.
Parabéns!
Fabrício says:
Muito bom o tutorial, realmente precisamos acabar com a imagem de que a linguagem é a responsável pela performance de um sistema.
Fiquei em dúvida na sua arquitetura, explicada em:
“Nesse momento havíamos definido nossa arquitetura final, quase no quarto mês de um projeto que seria finalizado no seu sexto mês, nada mal! Essa arquitetura contava com 9 máquinas (Intel Quad-Core Xeon 2.5 GHz), cada máquina rodando um Nginx, balanceando a carga entre 7 servidores de aplicação construídos com Tornado, onde cada máquina pode processar 300 R/S (requisições por segundo) que dá 3K conexões simultâneas, pois uma média de 10% das conexões estabelecidas estão realizando alguma operação simultâneamente.”
Os usuários estão acessando a aplicação por uma única máquina que redireciona para uma das nove com Nginx ? Ou o usuário acessa cada máquina Nginx de forma independente, precisando para isso de diferentes endereços para cada uma delas?
Você poderia fazer um desenho (um esquema) de sua arquitetura?
Abraços
marcelnicolay says:
As máquinas funcionam de forma independente. Cada máquina possui um Nginx e mais 7 instâncias de Tornado. Temos um balanceador físico na frente das 9máquinas que distribui a carga igualmente entre os servidores. Fiz uma apresentação com a nossa arquitetura dê uma olhada. http://blog.marcelnicolay.com/2010/06/apresentacao-do-novo-cartola-fc-2010/
Abs
Gustavo says:
Preciso fazer um webservice SOAPque tenha alta performance. Pensei usar essa arquitetura e ver se o SOAPPy e compativel com Tornado. Alquem tem uma experincia sobre webservices em python?