Artigo Java Magazine 11 - Testes de carga com JMeter
Projeto antigo do Grupo Apache, o JMeter foi inicialmente concebido para a criação e execução de testes de carga em aplicações web.
Uma das coisas que mais aprecio no vôo livre (faço vôos de parapente) são os preparativos. Gosto de observar todos os apetrechos que levo comigo: GPS, variômetro, bússola, rádio, apito, canivete suíço, lanterna, máquina fotográfica e um monte de coisas mais. O divertido é pensar em como tudo aquilo vai ser útil em determinado momento do vôo. Seria possível voar sem nenhum destes equipamentos, sendo necessário usar apenas a vela e a selete (a cadeira onde o piloto fica alojado), mas o vôo certamente não seria o mesmo. Grande parte dos equipamentos é exigida por segurança; outros são capazes de auxiliar na hora de ganhar altura, ou de saber que lugar exatamente se está sobrevoando.
Guia do artigo:
- JMeter
- Planos de testes
- Defaults, Controladores e Requisições
- Gravação de Requisições
- Testes em Bancos de Dados
- JMeters Simultâneos
- Elementos do JMeter
- Planos via Ant
Mas por que esse papo de vôo livre se a revista é sobre Java? Acontece que tenho a mesma sensação quando ligo meu laptop, abro meu IDE e vejo ali os plug-ins e outros componentes instalados, e que me ajudam na hora de desenvolver, testar, depurar ou otimizar minhas aplicações Java. Eu poderia, é claro, escrever meus sistemas usando apenas o JSDK e um editor de textos, mas o desenvolvimento não seria tão divertido – nem eficaz – do que usando as ferramentas corretas. Uma dessas ferramentas é o Apache JMeter, que apresento neste artigo.
O JMeter
Projeto antigo do Grupo Apache, o JMeter foi inicialmente concebido para a criação e execução de testes de carga em aplicações web. Com ele é possível simular usuários simultâneos acessando diversas páginas e seguindo fluxos de navegação distintos. Como resultado dos testes, o JMeter fornece relatórios e gráficos que auxiliam a visualizar – e compreender – como a aplicação reagiu. São apresentados tempos médios, máximos e mínimos de resposta, o número de requisições aceitas e negadas, e uma série de outras informações. O JMeter vem evoluindo e incorporando mais tipos de testes e relatórios: hoje é possível testar, além de aplicações web, servidores FTP, bancos de dados e web services, entre outros.
Você pode obter uma cópia da ferramenta no site de downloads do Jakarta (veja links). Feito o download, descompacte o pacote em um diretório à sua escolha. Serão criados os seguintes subdiretórios:
- bin: contém scripts para inicialização do console gráfico e do servidor, além dos arquivos de propriedades do JMeter;
- docs: documentos HTML com informações básicas sobre a ferramenta, manual do usuário e exemplos de planos de testes;
- extras: arquivos relacionados com a task Ant para automação de planos de testes, incluindo bibliotecas e modelos de relatórios (veja o quadro "JMeter via Ant");
- lib: bibliotecas utilizadas pelo JMeter (você pode copiar drivers JDBC e outros JARs para esse diretório para torná-los acessíveis durante os testes);
- printable_docs: inclui o manual no diretório docs, mas sem frames para facilitar a impressão.
Planos de testes
Um plano de testes (Test Plan) representa a navegação de usuários por uma aplicação web. Em uma livraria virtual, por exemplo, essa navegação poderia iniciar-se por uma página de autenticação, indo para a busca de livros, depois para os resultados da busca e seguindo para páginas de resumo e confirmação. Criar um plano de testes nesse caso exigiria representar requisições HTTP e cookies, além de um temporizador para estabelecer pausas entre requisições (já que o cliente passa algum tempo escolhendo livros, por exemplo) – isso para citar apenas alguns elementos.
Nesse sentido, o JMeter oferece componentes que representam grupos de threads, requisições, configurações básicas, sessões e cookies, entre muitos outros necessários para testes de aplicações web. Os componentes são organizados em categorias e podem ser criados e manipulados através do console gráfico da ferramenta.
Primeiro Plano
Vamos criar um plano de testes simples para uma aplicação de exemplo do Tomcat que acessa uma página JSP:
http//localhost:8080/examples/jsp/dates/date.jsp
Inicialize o console gráfico do JMeter chamando jmeter.bat (jmeter, no Linux). Veja a Figura 1. Vamos simular o acesso concorrente de 10 usuários e gerar relatórios com os resultados. O primeiro passo é adicionar um Thread Group, componente responsável pela criação de threads. Clique com o botão direito em Test Plan, na árvore de componentes, e escolha Add > Thread Group (veja a Figura 2); mude o nome para "Primeiro Exemplo" e o número de threads para 10. O campo Ramp-up period é utilizado caso se queria aumentar gradualmente o número de threads durante a execução, o que é útil para verificar a escalabilidade de uma aplicação; não vamos usá-lo nesse primeiro exemplo.
Desmarque o checkbox Forever e altere o valor de Loop Count para 1 (o teste será executado apenas uma vez). A opção Scheduler foi adicionada na versão 1.9.1 e permite agendar um horário para início e o final dos testes, o que é bastante útil para executar testes durante uma determinada quantidade de tempo, sem fixar o número de repetições.
Vamos adicionar um Sampler do tipo HTTP Request, que faz requisições HTTP contra um servidor web. Clique com o botão direito no Thread Group e selecione Add > Samplers> HTTP Request. Defina o Name e altere o endereço do servidor para "localhost" (note que não é incluído o protocolo). Deve-se adicionar a porta caso ela seja diferente da default (80): usaremos a porta padrão do Tomcat: 8080. Escolha também o método HTTP a ser usado, que nesse exemplo simples será GET, e defina o path como /examples/jsp/dates/date.jsp. Veja a Figura 3.
Saiba mais: Serviços RESTful: verbos HTTP
Por último, vamos adicionar dois Listeners para apresentar o resultado dos testes. No menu de contexto do Thread Group, selecione Add > Listener > Aggregate Report. Repita o processo, adicionando o listener View Results in Table.
Você já pode executar os testes, chamando o comando Run > Start. O JMeter criará 10 threads e todas solicitarão a página date.jsp. Os resultados serão apresentados nos dois listeners. O Aggregate Report (Figura 4) apresenta o número total de requisições e os tempos médio, mínimo e máximo de resposta (em milissegundos), além do percentual de erros e da taxa de respostas por segundo. O listener View Results in Table mostra o tempo de resposta de cada solicitação e se ela foi atendida com sucesso (veja a Figura 5).
Terminamos o primeiro exemplo. Você pode salvar o plano de testes (com Save|Test Plan). O arquivo (XML) será gravado com a extensão .jmx.
Defaults, Controladores e Requisições
Vamos a um exemplo mais completo que utiliza sessões, componentes de configuração e outras funcionalidades do JMeter. Usaremos outra aplicação de exemplo do Tomcat, chamada "Calendar", acessível em http://localhost:8080/examples/jsp/cal/login.html. Um fluxo típico para esta aplicação é:
- Exibir a página com o formulário de login;
- Submeter os dados de login;
- Selecionar uma data e um horário para um novo compromisso;
- Submeter o compromisso.
O objetivo dos testes será medir o tempo médio de resposta para todas as requisições e identificar a página que mais consome tempo durante a execução. Novamente vamos simular dez usuários simultâneos.
Sabendo o fluxo de navegação e o que pretendemos testar, vamos ao plano de testes. Vamos acessar as seguintes URLs, usando o método HTTP GET para as primeiras três e POST para a última:
- http://localhost:8080/examples/jsp/cal/login.html
- http://localhost:8080/examples/jsp/cal/cal1.jsp?name=Handerson&email=handerson.gomes%40summa-tech.com
- http://localhost:8080/examples/jsp/cal/cal2.jsp?time=9am
- http://localhost:8080/examples/jsp/cal/cal1.jsp
Observe que as URLs são muito semelhantes. Imagine como seria mais simples se fosse possível configurar valores default para evitar a entrada do nome do servidor e do número da porta para todas as requisições. Pensando nesses casos, a equipe do JMeter criou os componentes Config Elements, que permitem definir valores padrão para requisições.
Crie um plano de testes (chame-o de "JSP Calendar") e adicione a ele um Config Element do tipo HTTP Request Defaults. Defina as configurações conforme a Figura 6 (observe que foi adicionado o endereço e a porta do servidor).
O suporte a cookies é fundamental nesse exemplo. Adicione outro Config Element, um HTTP Cookie Manager, que é capaz de interceptar uma requisição HTTP, verificar se há cookies em anexo, salvá-los e enviá-los de volta nas requisições posteriores.
O próximo passo é configurar as requisições HTTP. Devemos especificar as URLs e os parâmetros enviados para a aplicação web. Crie um Thread Group e a ele adicione dois elementos do grupo Logic Controller – um Once Only Controller (Figura 7), que irá conter as requisições de Login (que acontecem uma única vez); e um Simple Controller, para a requisição de adição de compromisso.
Adicione um HTTP Request ao Once Only Controller (usando Add > Sampler > HTTP Request) e defina as opções conforme a Figura 8. Observe que os campos Server Name or IP e Port Number ficam em branco – o JMeter buscará essas informações no elemento HTTP Request Defaults criado anteriormente.
Crie mais um HTTP Request (com nome "JSP de Login"), esta requisição utiliza os parâmetros name e email. Para adicioná-los, clique em Add e faça preencha o nome e o valor como na Figura 9.
Adicione outros dois HTTP Requests, agora ao Simple Controller. Faça as configurações como nas Figuras 10 e 11 (lembre-se de preencher o campo Path com os caminhos das URLs mostradas anteriormente). O console do JMeter tem suporte a "Copiar e Colar" e permite arrastar objetos de um grupo para outro. Esta é uma funcionalidade adicionada nas versões mais recentes, e que fez muita falta nos primeiros releases da ferramenta.
Com todos os elementos de requisições adicionados, faltam apenas definir os listeners, para apresentação dos resultados. Crie os seguintes: Aggregate Report, View Results Tree, View Results in Table.
Você já pode executar os testes e verificar os resultados obtidos. No ambiente montado para o artigo, o Aggregate Report informou que a “Página de novo Compromisso” teve a média de tempo de resposta mais alta, 64 ms, mas foi prejudicada por um tempo máximo de 421 ms. O valor de Rate (que significa quantas requisições puderam ser atendidas por segundo) é semelhante para todas as requisições, na casa de 9.7 (Figura 12). Outra coluna a ser observada é count – note que todas as páginas foram executadas 10 vezes, mesmo as que estavam no Once Only Controller, pois o teste foi feito com dez usuários simultâneos.
O View Results Tree mostra informações mais detalhadas sobre as respostas, apresentando o cookie utilizado (em Cookie Data), o tempo de resposta (em Load Time) e a página HTML retornada com duas visualizações: o código fonte e um preview do HTML (veja a Figura 13).
Gravação de Requisições
Se o seu plano de testes fizer a navegação por um site com muitas páginas, a criação de HTTP Requests para cada uma se tornará trabalhosa e repetitiva. Para simplificar, o JMeter oferece um servidor de proxy que intercepta as requisições feitas por um navegador web e cria automaticamente< HTTP Requests. Para o proxy é possível também definir filtros de páginas, evitando criar Requests para imagens ou applets, por exemplo.
Vamos criar um plano de testes utilizando o proxy para simular a navegação de um usuário pelo site da Java Magazine, percorrendo as páginas da matéria “A Escolha Certa” (você pode usar qualquer outro site para simular os testes, é claro). Crie um novo plano de testes e adicione em WorkBech um elemento HTTP Proxy Server, usando Add > Non-Test Elements > HTTP Proxy Server. Defina a porta do proxy – a default é 8080, mas como esta é utilizada pelo Tomcat, usamos a 1010.
Defina também um filtro para que não sejam criados HTTP Requests para imagens e folhas de estilo (.css). Os tipos de arquivos ignorados são definidos usando expressões regulares no campo Patterns to Exclude, no caso: .*\.jpg, .*\.gif e .*\.css.
Adicione um Thread Group e dentro dele um Recording Controller, que é um componente do tipo Logic Controller responsável por gerar os HTTP Requests acessados através do proxy. Inicie o proxy clicando no botão Start (veja a Figura 14).
É necessário configurar seu navegador para fazer uso do proxy. No Internet Explorer 6.0, por exemplo, chame Tools|Internet Options > Connections > LAN Settings e selecione a opção Use a proxy server for your LAN e adicione as entradas específicas (Figura 15). Outros browsers como o Mozilla têm configurações semelhantes.
Com o plano de testes montado, o proxy em execução e o browser configurado, basta navegar pelo site e abrir as páginas desejadas. Ao final será criado no Recording Controller vários HTTP Requests (Figura 16). Se estes não aparecerem, verifique se o browser não está recuperando páginas do cache (nesse caso experimente forçar o recarregamento da página, com CTRL+R ou Shift+F5). Finalizados os testes, você pode parar o proxy.
Se você visitou as quatro páginas do artigo "Ecolha Certa", deve ter agora cinco HTTP Request criados. Em cada um deles, haverá um elemento do tipo HTTP Header Manager, que armazena os atributos de cabeçalhos HTTP enviados pelo servidor, por exemplo Cache-control e User-Agent. As propriedades If-Modified-Since e If-None-Match, adicionadas automaticamente, são responsáveis pelas informações de cache. Se você as mantiver nos HTTP Requests, o servidor HTTP (no caso, o Tomcat) vai assumir que o browser, ou o JMeter, mantém uma cópia da página localmente e que esta será usada, não enviando portanto uma página quando solicitado. Para evitar esse problema, remova do primeiro HTTP Request o elemento Browser-Derived Headers (em HTTP Header Manager).
Adicione também os seguintes listeners ao Thread Group: View Results Tree, Graph Results e Aggregate Report. Altere tanto o número de threads como o Loop Count para 10.
Execute os testes. Você verá que apenas a primeira página realmente foi retornada pelo servidor HTTP, o que fica claro quando analisamos os resultados em View Results Tree. No Aggregate Report, verificamos que a primeira requisição levou em média 4.6 ms para ser retornada (Figura 17).
Observe que o gráfico em Graph Results (Figura 18) apresenta linhas com poucas variações, indicando um tempo de resposta constante. Cada ponto destacado no gráfico representa o tempo de resposta de uma requisição.
Testes em Bancos de Dados
Outros testes que podem ser realizados com o JMeter são de consultas SQL, drivers JDBC e da capacidade de processamento de banco de dados. Como exemplo, vamos acessar um banco de dados HSQLDB (no entanto será fácil portar o exemplo para o banco de dados mais acessível para você). Veja na Listagem 1 o script para criação da tabela com a inserção de alguns registros.
Localize o diretório onde o JMeter foi instalado (por exemplo, c:\jakarta-jmeter-1.9.1) e copie para seu subdiretório lib o driver JDBC do banco. Se o JMeter estiver em execução, reinicie-o para que o driver seja adicionado ao classpath da ferramenta.
Crie um plano de testes e adicione um Config Element do tipo JDBC Database Login Defaults. Este componente armazena as informações de acesso ao banco. Para uma conexão ao HSQLDB use as seguintes configurações:
- JDBC URL: jdbc:hsqldb:hsql://localhost
- Driver Class: org.hsqldb.jdbcDriver
- Username: sa
Por default, o HSQLDB não define uma senha para o usuário “sa”, portanto o campo Password pode ficar vazio.
Adicione também um Config Element do tipo JDBC Database Connection Pool Defaults. Neste componente são definidas configurações para o pool de conexões usado pelo JMeter. Se sua aplicação web faz o acesso ao banco de dados através de um pool (do servidor de aplicações, por exemplo), uma possibilidade é configurá-lo da mesma forma que foi configurado o pool do servidor, ou seja, com o mesmo número máximo de conexões. Dessa forma é possível fazer os testes das consultas SQL num ambiente semelhante ao de execução.
Adicione um Thread Group e, nele, um Simple Controller. Dentro do Controller insira quatro Samplers do tipo JDBC Request que conterão as consultas SQL a serem enviadas ao banco:
- select * from CLIENTES order by NOME desc
- select * from CLIENTES
- select * from CLIENTES where ID = 1
- select * from CLIENTES where ID+1 = 3
Preencha os campos SQL Query String com a consulta SQL; para o campo Name, costumo usar o próprio comando SQL, já que este é mostrado em alguns relatórios (como o Aggregate Report). Os outros campos serão substituídos na execução dos testes, pelos valores definidos nos Config Elements.
Por fim, adicione os listeners Aggregate Report e Graph Results. Execute os testes com um usuário (1 thread), 50 vezes (Loop Count = 50). Os resultados sumarizados são mostrados na Figura 19.
JMeters Simultâneos
Ao utilizar o JMeter para simular vários usuários simultâneos, poderemos ter problemas no lado do cliente quanto ao uso de recursos. Dependendo do número de usuários simulados e da velocidade de resposta do servidor, a máquina cliente poderá ser insuficiente para tratar todas as requisições.
Para resolver este problema é possível rodar instâncias remotas do JMeter em vários computadores da rede, dividindo o trabalho de execução dos testes. As instâncias remotas executam os testes em paralelo e reportam o resultado para um único cliente que faz a sumarização, tornando possível alcançar um grande número de requisições sem sobrecarregar os clientes. Veja mais sobre esse recurso.
create table CLIENTES (
ID INTEGER not null, NOME VARCHAR(255) not null,
EMAIL VARCHAR(255), CIDADE VARCHAR(255) );
insert into CLIENTES values (1, 'Handerson Ferreira Gomes',
'handerson.gomes@summa-tech.com','Sao Paulo');
insert into CLIENTES values (2,'Joao da Silva',
'joao@silva.com', 'Curitiba');
insert into CLIENTES values (3,'Maria Aparecida',
'maria@aparecida.com', 'Rio de Janeiro');
Elementos do JMeter
- Thread Groups: São o ponto inicial dos planos de teste. Além de disparar threads e agrupar componentes, é nos Thread Groups que definimos o número de usuários concorrentes, o incremento gradual do número de threads, o número de vezes que o teste deve ser repetido e o tempo total de execução.
- Logic Controllers: Nesta categoria entram os elementos responsáveis pela lógica dos testes. Os controles mais usados são o Once Only Controller, que faz com que os componentes aninhados sejam executados apenas uma vez; o Interleave Controller, para a execução alternada de Samplers (um para cada iteração); o Loop Controller, que repete a execução dos componentes o número de vezes especificado; e o Simple Controller, usado apenas para agrupamento.
- Samplers: Neste grupo estão os elementos responsáveis por requisições de serviços, como o HTTP Request, JDBC Request, FTP Request, SOAP-RPC Request e outros.
- Listeners: Elementos que geram os diversos relatórios de testes. Novos relatórios podem ser desenvolvidos e adicionados ao JMeter (veja links).
- Timers: Permitem especificar pausas entre a execução de threads ou de Samplers. Por default, o JMeter executa todos os Samplers (por exemplo, HTTP Requests) em seqüência e sem pausas, o que, além de não ser um comportamento comum para muitas aplicações, pode levar a uma sobrecarga desnecessária do servidor.
- Assertions: Asserções podem ser adicionadas aos Samplers para verificar se a resposta enviada pelo servidor é a esperada. Podem validar o tamanho e o conteúdo da resposta e suportam o uso de expressões regulares. Os resultados são enviados para o listener Assertions Result.
- Configuration Elements: Neste grupo estão os elementos que armazenam configurações padrão para alguns Samplers, além de elementos de controle como o HTTP Cookie Manager, utilizado no segundo exemplo deste artigo.
Dicas
- ique sempre atento ao consumo de CPU e de memória onde o JMeter está sendo executado. Se a CPU alcançar 100% de uso é melhor diminuir o número de threads, mudar para uma máquina melhor, ou dividir o processamento em várias instâncias do JMeter rodando em máquinas separadas;
- Quanto mais rápido o servidor responder, mais trabalho terá o JMeter. Isso pode influenciar os resultados dos testes, já que a ferramenta pode não ser capaz de tratar as respostas em tempo hábil;
- Evite executar o JMeter no servidor onde a aplicação está instalada; se o fizer, serão compartilhados recursos de memória e de CPU possivelmente afetando os resultados. Isso vale para servidores de aplicações, servidores web e de banco de dados e outros que sejam usados pela aplicação;
- A execução de testes de performance pode levar alguns dias, nos quais os testes são executados diversas vezes depois de ajustes na aplicação e no ambiente. Certifique-se de ter um ambiente dedicado durante o período, com o banco de dados, o servidor de aplicações e o servidor web sendo acessados apenas pela equipe de testes. Se isso não for garantido será difícil mensurar com precisão o resultado dos ajustes feitos durante as várias sessões de testes;
- É possível desativar itens de um plano de testes: clique com o botão direito sobre o item e selecione Disable/Activate;
- Listeners podem ser adicionados a Thread Groups, Logic Controllers ou Samplers. Os dados dos relatórios relacionados conterão apenas os elementos do grupo a que pertencem. Esse recurso é útil para extrair dados de um determinado universo do plano de testes;
- A ordem dos Samplers no plano de testes define a seqüência de sua execução. É possível reorganizar esses elementos arrastando-os para um novo grupo ou alterando sua posição dentro de um grupo.
Planos via Ant
O console gráfico não é a única forma de executar um plano de testes do JMeter. Através de um task do Ant é possível executar um conjunto de planos de testes e gerar relatórios com os resultados obtidos. A integração JMeter/Ant abre a possibilidade de ter uma equipe fazendo testes contínuos de performance, ou testes agendados, sem a necessidade de trabalhar com o console.
Os relatórios são convertidos para HTML usando a task padrão do Ant XSLT. Dois modelos de relatórios são fornecidos: um resumido semelhante ao Aggregate Report e um detalhado. O arquivo de resultados gerado (com extensão .jtl) pode ser aberto no console do JMeter, permitindo com isso acesso a outras visualizações como o Graph Results (para carregar um arquivo .jtl, selecione a opção Browse no menu de contexto de um listener).
Para poder executar um plano do JMeter com o Ant deve-se copiar o arquivo \extras\ant-jmeter\ant-jmeter.jar para o diretório lib do Ant e utilizar a task jmeter no buildfile. Abaixo está um exemplo de buildfile que faz uso da task, além de uma captura do relatório gerado:
target>
Conclusões
Os testes de carga fazem parte de uma etapa fundamental no desenvolvimento de qualquer software multi-usuário. Os resultados obtidos podem identificar problemas de performance ou o uso excessivo de recursos do servidor – e usar uma ferramenta como o JMeter é fundamental nesses casos.
Confira também
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo