Na primeira parte desta série eu comentei sobre como utilizar a ferramenta WCF Load Test para gerar testes unitários para serviços WCF. Como eu havia comentado lá, o grande intuito da geração daqueles testes é justamente a integração que podemos ter com outros tipos de testes fornecidos pelo próprio Visual Studio.
O principal tipo de teste a ser utilizado por serviços WCF é o teste de carga (Load Test). Testes de carga são usados para verificar se sua aplicação/serviço irá se comportar bem enquanto sofre uma grande quantidade de acessos simultâneos. A ideia aqui será combinar com os testes unitários que fizemos no artigo anterior, e com isso reproduzir a(s) chamada(s) para o(s) serviço(s) através de N usuários concorrentes dentro de um período de tempo, e que serão configurados através deste tipo de teste.
A ideia do teste de carga é especificar a quantidade, distribuição, periodicidade dos acessos, tentando estressar ao máximo o serviço/aplicação, afim de detectar possíveis cenários, onde depois de um certo número, a aplicação/serviço possa começar a não dar mais conta de atender todas as requisições que chegam para ela.
Para criar um teste de carga para serviços WCF, podemos utilizar o mesmo projeto criado anteriormente, e incluir nele um teste chamado Load Test, assim como é mostrado na imagem abaixo:
Ao incluir este teste, um wizard será iniciado para nos conduzir nas configurações do teste de carga. O primeiro que é exigido é a escolha do think time, que determina o período de tempo que existe entre as requisições (delay), que podemos geralmente utilizar a opção padrão. Já no passo seguinte temos o modelo do teste de carga, que controla a frequência em que os testes envolvidos serão executados. Podemos escolher uma entre quatro opções disponíveis:
-
Based on the total number of tests
-
Based on the number of virtual users
-
Based on user pace
-
Based on sequential test order
Além disso, uma das principais configurações do teste de carga é justamente a quantidade de usuários que acessarão o serviço. Há duas opções disponíveis: Constant Load e Step Load. A primeira exige um número inteiro que corresponde ao número de usuários, e que serão disparadas o mais rápido possível ao aplicação/serviço. A segunda opção, Step Load, permite aumentar gradativamente o número de usuários que acessam a aplicação/serviço, até atingir um número máximo de usuários, que pode ser mais próximo ao mundo real. A imagem abaixo ilustra essas configurações:
Dentro de um teste de carga, ainda podemos criar vários cenários, onde cada um deles poderá conter testes do tipo Web Performance Test (usado por aplicações Web) ou Unit Test, e cada teste sendo executado para um cenário específico, como por exemplo, N usuários, a distribuição das requisições durante o tempo estipulado, qual navegador está sendo utilizado para acesso (útil para aplicações Web), através de qual meio de conexão (LAN ou DialUp), etc.
Ao clicar no método Add para adicionar, serão listados os Unit Tests, inclusive aquele que criamos anteriormente, para o consumo do serviço WCF. A imagem abaixo ilustra esta tela e o teste já selecionado:
Na última tela temos as configurações que determinam por quanto tempo o teste irá rodar. Através da opção Load Test Duration, podemos especificar um tempo para warm-up, que determina a partir de quanto tempo os dados começarão a serem coletados. Isso é interessante porque permite ignorarmos inicializações que o serviço eventualmente faça, para que isso não seja contemplado nos resultados; além disso, temos a opção Run Duration, que determina a quantidade de tempo que em que o teste rodará. E para finalizar, esta tela conta também com o campo chamado Sampling Rate, que determina o tempo em que as informações serão coletadas e exibidas.
Com essas configurações feitas, o teste de carga é criado no Visual Studio, e a qualquer momento permitirá a alteração de alguma configuração previamente definida. Você pode também estar interessado em monitorar contadores de performance específicos, como é o caso dos contadores do ASP.NET e do WCF, que ajudarão nos diagnósticos de eventuais gargalos. A imagem abaixo resume a configuração realizada:
Tudo o que precisamos fazer agora é rodar o teste. Neste momento, o Visual Studio irá começar a executar o teste que criamos, respeitando todas as configurações lá colocadas e, principalmente, coletando as informações que você está interessado, e que será exibida graficamente através da leitura os contadores de performance que você escolheu. A imagem abaixo exibe o resultado do processamento do teste, onde podemos visualizar a quantidade de requisições, duração de cada uma delas, instâncias criadas, etc.
O serviço que criamos no artigo anterior, está sem qualquer configuração extra no WCF, ou seja, o gerenciamento de instâncias padrão é definido como PerSession e a sincronização como sendo Single. Outra configuração que pode afetar aqui é o throttle, apesar de que na versão 4.0 do WCF, seus limites foram incrementados. Apenas para constar, abaixo temos os limites de throttle em ambas as versões:
-
WCF 3.0
-
MaxConcurrentSessions: 10
-
MaxConcurrentCalls: 16
-
MaxConcurrentInstances: 26 (MaxConcurrentSessions + MaxConcurrentInstances)
-
-
WCF 4.0
-
MaxConcurrentSessions: 100 * Número de Processador
-
MaxConcurrentCalls: 16 * Número de Processador
-
MaxConcurrentInstances: MaxConcurrentSessions + MaxConcurrentInstances
-
Para o nosso caso, podemos alterar o serviço para haver uma única instância para todas as requisições, e garantir o acesso concorrente ao método Buscar, e para fazer essa alteração, devemos incluir o atributo ServiceBehaviorAttribute para customizar isso:
[ServiceBehavior(
InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServicoDeBusca : IBuscador { }
Quando temos a configuração acima, o único parâmetro que nos interessa no throttle é a quantidade máxima de chamadas concorrentes (MaxConcurrentCalls), que está limitado em 16 * número de processadores. Vamos incrementar isso para 150, incluindo um behavior de serviço, conforme é mostrado no código abaixo. Para mais detalhes sobre throttle, consulte este artigo.
<serviceThrottling maxConcurrentCalls=”150″ />
Após essa alteração aplicada ao serviço, se rodarmos o mesmo teste, veremos que a quantidade de requisições é elevada, conseguindo atender mais requisições simultâneamente.
Conclusão: Com as informações geradas por este teste, é possível diagnosticar e realizar alguns ajustes finos no WCF (throttling, por exemplo), no IIS e no pipeline de execução do ASP.NET, para conseguirmos dar mais vazão ao processamento das requisições. De qualquer forma, existem outras ferramentas que nos permite extrair informações de custo de processamento, memória e threading e que serão abordados em um futuro artigo.