terça-feira, 19 de fevereiro de 2013

Como testar o desempenho de suas aplicações web de forma fácil e rápida

Você acabou de finalizar os últimos retoques no seu site ou aplicação. O cliente já fez exaustivos testes além dos testes realizados por você mesmo. Tudo pronto para colocar em produção aquele código no qual você passou meses trabalhando. E de repente, quando mais de 30 usuários estão fazendo requisições ao mesmo tempo, as requisições demoram a serem respondidas. Parece que a página inicial do site não vai aparecer nunca. Clicar em "salvar" naque formulário de cadastro se torna uma bela desculpa para uma pausa para café.

"Mas como isso está acontecendo?" Você se pergunta. Nos testes realizados as resquisições demoravam poucas dezenas de milisegundos. Como isso foi acontecer? Bom, provavelmente os testes foram realizados com apenas um usuário acessando o servidor, talvez dois. Com o site ou aplicação se tornando popular vários usuários vão fazer seu código ser executado em várias requisições ao mesmo tempo. E é neste momento que estas supresas aparecem.

Para te ajudar a tentar prever como seu código vai se comportar com várias requisições simultâneas existe uma ferramenta muito útil chamada ab (Apache Benchmark), sobre a qual já falei aqui. Em uma máquina com gerenciador de pacotes como o apt-get instalá-la é muito fácil. Basta usar o comando:
#apt-get install apache2-utils

Sua execução básica é assim:
$ab -c 10 -t 30 http://localhost/sitecobaia/

Este comando vai abrir 10 conexões simultâneas e enviar requisições durante 30 segundos para o endereço indicado. Uma variação deste comando é adicionar um parâmetro para que as conexões sejam do tipo keep-alive(comum nas as requisições enviadas por navegadores).
$ab -kc 10 -t 30 http://localhost/sitecobaia/

Quanto aos números você é livre para alterá-los como quiser. Se você for realmente sádico coloque algo como 100 requisições simultâneas durante 60 segundos e veja seu servidor sofrer.

Um exemplo de saída ao comando ab pode ser visto abaixo:

This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Finished 484 requests


Server Software:        Apache/2.2.20
Server Hostname:        localhost
Server Port:            80

Document Path:          /sitecobaia/
Document Length:        43666 bytes

Concurrency Level:      10
Time taken for tests:   30.022 seconds
Complete requests:      484
Failed requests:        0
Write errors:           0
Keep-Alive requests:    0
Total transferred:      21502202 bytes
HTML transferred:       21134344 bytes
Requests per second:    16.12 [#/sec] (mean)
Time per request:       620.291 [ms] (mean)
Time per request:       62.029 [ms] (mean, across all concurrent requests)
Transfer rate:          699.43 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       2
Processing:   349  614 108.0    608     950
Waiting:      344  598 105.6    591     932
Total:        349  614 108.0    608     950

Percentage of the requests served within a certain time (ms)
  50%    608
  66%    658
  75%    688
  80%    707
  90%    750
  95%    798
  98%    845
  99%    875
 100%    950 (longest request)


Alguns números mostrados são interessantes. Como por exemplo a média de requisições por segundo(Requests per second) que neste caso foi de 16,12. Quanto mais alto este número mais requisições seu servidor servirá em menos tempo. A média de tempo(Time per request) por requisição também é interessante de ser observada. Neste caso temos dois valores, o primeiro, indica o tempo médio em milisegundos que o servidor demorou para responder uma única requisição, neste caso 620,291 ms. Ou seja com 10 conexões concorrentes a resposta demourou em média pouco mais de meio segundo para chegar(1 segundo tem 1000 milisegundos). O segundo valor da média de tempo por requisição é o resultado da divisão do tempo total para todas as requisições(30,22 segundos ou 30022 milisegundos) pelo número de requisições completas (484) o que dá o valor de 62,029 milisegundos por requisição.

No final temos um resumo da porcentagem de requsições respondidas dentro de um certo tempo em milisegundos. Observem que 50% das requisições demoraram no máximo 608 ms para serem respondidas. E a requisição mais demorada demorou 950 ms.

Um resultado que pode deixar-nos confusos quando usamos o ab com sites dinâmicos é o seguinte:

Failed requests:        32951
   (Connect: 0, Receive: 0, Length: 32951, Exceptions: 0)


Você pensa: "Porque ele reportou que 32951 requisições falharam?". Mas observe que o tipo de erro foi de tamanho(Length), isso acontece porque o ab considera que quando os tamanhos das respostas diferem da primeira resposta obtida do servidor acontece um erro de Length. Como em páginas dinâmicas coisas como identificadores de sessão, cookies ou até mesmo o conteúdo da resposta podem mudar de uma requisição para outra este tipo de "erro" pode aparecer frequentemente.