Quem nunca sentiu um certo receio no momento do release de um novo site? Será que a performance será a esperada? Ou ainda: o site atual simplesmente resolveu dar um problema no meio da madrugada… as luzes piscam por todo o lugar na sala de operação. Se o seu sistema foi incrivelmente bem projetado, feito sem pressão de entrega, possui logs muito bem organizados e está bem documentado a ponto da operação resolver tudo sozinha, bom pra você! Mas sabemos que não é assim e, provavelmente, você que está lendo este artigo já foi acordado no meio da madrugada.
Existem diversas formas de se prevenir (recomendo muito a leitura do excelente Release It!) mas não existe um passo a passo para a criação de um site que possua uma boa performance e que seja estável 100% do tempo. Tenho alguns anos de experiência no desenvolvimento do globoesporte.com, sportv.com e do Cartola FC e acredito que este artigo possa ajudar outros desenvolvedores.
Apenas para contextualizar, o globoesporte.com é o maior portal de esportes de toda a América Latina. Recebemos cerca de 20 milhões de visitantes únicos por mês e diversos foram os desafios ao longo dos anos. Não é segredo que nós utilizamos Python / Django e acredito que muitos já tenham lido que Django não escala (ou ainda: que o próprio Python não escala). Porém, acredito fortemente que a performance vem da arquitetura da sua aplicação e não da linguagem propriamente dita.
Basicamente, nossos gargalos são três, não necessariamente nesta ordem de criticidade. O primeiro deles, é o MySQL, devido ao uso intensivo de requisições ao sistema. Deve-se tomar muito cuidado ao desenhar sua aplicação utilizando o Django pois ele pode fazer diversas sub requisições sem que você saiba. O segundo, é o Virtuoso (um banco de triplas), devido a demora de resposta. Por último, temos bastante I/O devido a consultas intensiva a APIs
Para reduzir esses gargalos, demos três passos, a saber.
Caching
O primeiro passo foi a utilização de um mecanismo de caching. Nós desenvolvemos uma estratégia de uso cache para lidar com nossas necessidades de desempenho e reduzir o espaço de memória utilizada (a solução é detalhada no artigo Uso otimizado de cache para performance de aplicações WEB). Use cache sempre que possível! Quando não for possível, reveja sua arquitetura!
Pré-Geração de Conteúdo
O segundo passo foi impedir que requisições do usuário iniciassem processos críticos. Algumas das páginas do globoesporte.com possuem integração com diversas APIs internas e externas e, por mais enxuto e otimizado que nosso código seja, depender de processamento externo é sempre um risco. Assim, sempre que possível, utilizamos um mecanismo de pré-geração de conteúdo, disparado por um evento de publicação editorial. Atualmente, utilizamos o staticgenerator (https://github.com/timetric/django-staticgenerator) para gerar o conteúdo estático de nossas homes e matérias.
Server Side Include (SSI)
O terceiro passo, dado relativamente a pouco tempo, consistiu em dividir nossas páginas em blocos com ciclos de cache diferentes. Na prática, isso significou eliminar chamadas Ajax e trocá-las por blocos de HTML incluídos pelo servidor WEB (SSI). A home do Flamengo, por exemplo, possui um componente de classificação que é atualizado a cada 10 minutos e um componente de “últimas notícias” atualizado a cada 2 minutos. Ambos são incluídos na página através de SSI. Essa técnica, inclusive, melhora a performance client-side ao reduzir a quantidade de javascript executado pelo navegador.
Performance Client-Side
E, por falar em performance client-side, deve-se prestar atenção à quantidade de arquivos estáticos (CSS, JS e imagens) que sua página terá e que implicarão em requests (e processamento) ao servidor web. Algumas técnicas simples reduzem a quantidade de requests:
- minify de CSS e JS: utilize uma ferramenta avança, como o compass, para atingir esse objetivo;
- caching do browser: seu navegador é experto o suficiente para guardar arquivos com o mesmo nome no cache. Assim, procure criar blocos de CSS e JS comuns às páginas. O globoesporte.com possui centenas de páginas de times. Além do conteúdo, a única diferença entre elas é a cor específica de cada time. Dessa forma, temos um grande bloco de CSS que se repete e é cacheado pelo browser;
- junte as imagens em arquivos chamados “sprite”. Desenvolvemos o nosso próprio gerador dinâmico de sprites, o Spriter;
- configure um tempo de expiração adequado para seus estáticos;
- ative o gzip no seu servidor web. Os navegadores modernos suportam essa compressão.
- sirva os arquivos estáticos em uma farm separada;
É importante que seu servidor esteja configurado corretamente. Abaixo, um exemplo de resposta do servidor do globoesporte.com:
HTTP/1.1 200 OK Server: nginx Date: Thu, 16 Jan 2014 23:54:40 GMT Content-Type: text/html; charset=utf-8 Accept-Encoding:gzip,deflate,sdch Connection: close Last-Modified: Thu, 16 Jan 2014 23:52:33 GMT Expires: Thu, 16 Jan 2014 23:57:33 GMT Cache-Control: max-age=30
Após aplicar as técnicas descritas aqui no artigo, não esqueça de monitorar a performance da sua aplicação! Destaco três ferramentas:
- Apache HTTP server benchmarking tool: não é apenas para o Apache e deve ser usada com frequência para verificar se a performance da aplicação está conforme o esperado;
- monit: utiliitário open source e gratuito para o gerenciamento e monitoração de processos, programas, arquivos, diretórios e filesystems em um sistema UNIX;
- webpagetest.org: apresenta informações detalhadas sobre a performance client-side e o que você deve fazer para melhorá-la.
[Crédito da imagem: Performance – Acuity Business Solutions, Performance – ShutterStock]
Oi Victor.
Para mim que não sou programador e sim um Evangelista de Computação em Nuvem, chamou a atenção a questão da escalabilidade não estar ligada a linguagem e sim a arquitetura, o que concordo plenamente com você.
Acrescento aí a escolha de uma hospedagem capaz de escalar a aplicação, que pode ser na Amazon, se você for capaz de configurar Elastic Load Balance, CloudWatch, puppet entre outros, ou partir para uma solução de plataforma como Heroku e aqui em terras brasileiras temos a Getup Cloud.
Falando em banco de dados, Amazon RDS tem sido minha principal indicação quando se trata de um banco que necessite performance.