Ao integrar um serviço de back-end ao balanceador de carga de aplicativo, é importante medir o desempenho de um serviço de back-end por conta própria, na ausência de um balanceador de carga. O teste de carga em condições controladas ajuda a avaliar as compensações do planejamento de capacidade entre diferentes dimensões de desempenho, como capacidade e latência. Como um planejamento cuidadoso da capacidade ainda pode subestimar a demanda real, recomendamos que você use testes de carga para determinar proativamente como a disponibilidade de um serviço é afetada quando o sistema está sobrecarregado.
Metas de teste de carga
Um teste de carga típico mede o comportamento visível externamente do serviço de back-end em diferentes dimensões de carga. Algumas das dimensões mais relevantes desse teste são:
- Capacidade de solicitação: o número de solicitações exibidas por segundo.
- Simultaneidade de solicitação: o número de solicitações processadas simultaneamente.
- Capacidade de conexão: o número de conexões iniciadas por clientes por segundo. A maioria dos serviços que usam Transport Layer Security (TLS) têm alguma sobrecarga de transporte de rede e negociação de TLS associada a cada conexão que é independente do processamento de solicitação.
Simultaneidade de conexão: o número de conexões de clientes processadas simultaneamente.
Latência da solicitação: o tempo total decorrido entre o início da solicitação e o final da resposta.
Taxa de erros: a frequência com que as solicitações causam erros, como erros HTTP 5xx e conexões fechadas prematuramente.
Para avaliar a integridade do servidor sob carga, um procedimento de teste de carga também pode coletar as seguintes métricas de serviço interno:
Uso de recursos do sistema: recursos do sistema, como CPU, RAM e identificadores de arquivos (soquetes), geralmente são expressos em porcentagem.
A importância dessas métricas varia de acordo com a implementação do serviço. Os aplicativos apresentam desempenho reduzido, perda de carga ou falha quando esgotam os recursos. Portanto, torna-se essencial determinar a disponibilidade de recursos quando um host está sob carga pesada.
Uso de outros recursos limitados: recursos que não são do sistema e que podem estar esgotados durante o carregamento, como na camada do aplicativo.
Veja alguns exemplos desses recursos:
- Um pool limitado de threads ou processos de worker.
- Para um servidor de aplicativos que usa linhas de execução, é comum limitar o número de linhas de execução de trabalho que operam simultaneamente. Os limites de tamanho do pool de linhas de execução são úteis para evitar o esgotamento da memória e da CPU, mas as configurações padrão geralmente são muito conservadoras. Limites muito baixos podem impedir o uso adequado dos recursos do sistema.
- Alguns servidores usam pools de processos, em vez de pools de linhas de execução. Por exemplo, um servidor Apache, quando configurado com o Prefork Multi-Processing Model, atribui um processo a cada conexão do cliente. Portanto, o limite de tamanho do pool determina o limite superior da simultaneidade de conexão.
- Um serviço implantado como front-end para outro serviço que tenha um pool de conexões de back-end de tamanho limitado.
Planejamento de capacidade versus teste de sobrecarga
As ferramentas de teste de carga ajudam você a medir diferentes dimensões de escalonamento individualmente. Para o planejamento de capacidade, determine o limite de carga para o desempenho aceitável em várias dimensões. Por exemplo, em vez de medir o limite absoluto de uma solicitação de serviço, avalie o seguinte:
- A taxa de solicitação em que o serviço pode exibir com latência do 99o percentil inferior a um número especificado de milissegundos. O número é especificado pelo SLO do serviço.
- A taxa de solicitação máxima que não faz com que a utilização de recursos do sistema exceda os níveis ideais. A utilização ideal varia de acordo com o aplicativo e pode ser significativamente inferior a 100%. Por exemplo, com 80% de pico de utilização da memória, o aplicativo pode ser capaz de lidar com picos menores de carga melhor do que se a utilização de pico fosse de 99%.
Embora seja importante usar os resultados do teste de carga para formar as decisões de planejamento de capacidade, é igualmente importante entender como um serviço se comporta quando a carga excede a capacidade. Alguns comportamentos do servidor que geralmente são avaliados usando testes de sobrecarga são os seguintes:
Deslocamento de carga: quando um serviço recebe solicitações ou conexões de entrada excessivas, ele pode desacelerar todas as solicitações ou rejeitar algumas solicitações para manter o desempenho aceitável das restantes. Recomendamos a última abordagem para evitar tempos limite do cliente antes de receber uma resposta e para reduzir o risco de esgotamento da memória reduzindo a simultaneidade de solicitação no servidor.
Resiliência contra o esgotamento de recursos: um serviço geralmente evita a falha de esgotamento de recursos porque é difícil para solicitações pendentes fazer mais progresso se o serviço falhou. Se um serviço de back-end tem muitas instâncias, a robustez de instâncias individuais é essencial para a disponibilidade geral do serviço. Enquanto uma instância é reiniciada a partir de uma falha, outras instâncias podem sofrer mais carga, o que pode causar uma falha em cascata.
Diretrizes gerais de teste
Ao definir os casos de teste, considere as diretrizes a seguir.
Criar testes em pequena escala
Crie testes de pequena escala para medir os limites de desempenho do servidor. Com capacidade excessiva do servidor, há o risco de um teste não revelar os limites de desempenho do próprio serviço, mas pode revelar gargalos em outros sistemas, como os hosts de cliente ou a camada de rede.
Para melhores resultados, considere um caso de teste que use uma única instância de máquina virtual (VM, na sigla em inglês) ou um pod do Google Kubernetes Engine (GKE) para testar o serviço de maneira independente. Para atingir a carga total no servidor, se necessário, use várias VMs, mas lembre-se de que elas podem complicar a coleta de dados de desempenho.
Escolher padrões de carga de loop aberto
A maioria dos geradores de carga usa o padrão de loop fechado para limitar o número de solicitações simultâneas e atrasar novas solicitações até que as anteriores sejam concluídas. Não recomendamos essa abordagem porque os clientes de produção do serviço podem não exibir esse comportamento de limitação.
Por outro lado, o padrão de loop aberto permite que os geradores de carga simulem a carga de produção enviando solicitações a uma taxa estável, independentemente da taxa em que as respostas do servidor chegam.
Executar testes usando geradores de carga recomendados
Recomendamos os seguintes geradores de carga para o teste de carga do serviço de back-end:
Nighthawk
O Nighthawk é uma ferramenta de código aberto desenvolvida em conjunto com o projeto Envoy. Use-o para gerar carga do cliente, visualizar comparativos de mercado e avaliar o desempenho do servidor para a maioria dos cenários de teste de carga de serviços HTTPS.
Testar HTTP/1
Para testar HTTP/1, use o seguinte comando:
nighthawk_client URI \ --duration DURATION \ --open-loop \ --no-default-failure-predicates \ --protocol http1 \ --request-body-size REQ_BODY_SIZE \ --concurrency CONCURRENCY \ --rps RPS \ --connections CONNECTIONS
Substitua:
URI
: o URI a ser comparado.DURATION
: tempo total de execução do teste em segundosREQ_BODY_SIZE
: tamanho do payload POST em cada solicitaçãoCONCURRENCY
: o número total de loops de evento simultâneosEsse número precisa corresponder à contagem de núcleos da VM do cliente
RPS
: a taxa de destino de solicitações por segundo, por loop de eventos.CONNECTIONS
: o número de conexões simultâneas, por loop de evento.
Veja o exemplo a seguir:
nighthawk_client http://10.20.30.40:80 \ --duration 600 --open-loop --no-default-failure-predicates \ --protocol http1 --request-body-size 5000 \ --concurrency 16 --rps 500 --connections 200
A saída de cada execução de teste apresenta um histograma de latências de resposta. No exemplo da documentação do Nighthawk (em inglês), observe que a latência do 99o percentil é de aproximadamente 135 microssegundos.
Initiation to completion samples: 9992 mean: 0s 000ms 113us pstdev: 0s 000ms 061us Percentile Count Latency 0 1 0s 000ms 077us 0.5 4996 0s 000ms 115us 0.75 7495 0s 000ms 118us 0.8 7998 0s 000ms 118us 0.9 8993 0s 000ms 121us 0.95 9493 0s 000ms 124us 0.990625 9899 0s 000ms 135us 0.999023 9983 0s 000ms 588us 1 9992 0s 004ms 090us
Testar HTTP/2
Para testar o HTTP/2, use o seguinte comando:
nighthawk_client URI \ --duration DURATION \ --open-loop \ --no-default-failure-predicates \ --protocol http2 \ --request-body-size REQ_BODY_SIZE \ --concurrency CONCURRENCY \ --rps RPS \ --max-active-requests MAX_ACTIVE_REQUESTS \ --max-concurrent-streams MAX_CONCURRENT_STREAMS
Substitua:
URI
: o URI a ser comparado.DURATION
: tempo total de execução do teste em segundosREQ_BODY_SIZE
: tamanho do payload POST em cada solicitaçãoCONCURRENCY
: o número total de loops de evento simultâneosEsse número precisa corresponder à contagem de núcleos da VM do cliente
RPS
: a taxa de destino de solicitações por segundo para cada loop de evento.MAX_ACTIVE_REQUESTS
: o número máximo de solicitações ativas simultâneas para cada loop de evento.MAX_CONCURRENT_STREAMS
: o número máximo de streams simultâneos permitidos em cada conexão HTTP/2
Veja o exemplo a seguir:
nighthawk_client http://10.20.30.40:80 \ --duration 600 --open-loop --no-default-failure-predicates \ --protocol http2 --request-body-size 5000 \ --concurrency 16 --rps 500 \ --max-active-requests 200 --max-concurrent-streams 1
ab (ferramenta de comparativo de mercado do Apache)
O ab
é uma alternativa menos flexível ao Nighthawk, mas está disponível como um pacote
em quase todas as distribuições do Linux. ab
é recomendado apenas para testes rápidos e simples.
Para instalar o ab
,
use o seguinte comando:
- No Debian e no Ubuntu, execute
sudo apt-get install apache2-utils
. - Em distribuições baseadas no RedHat, execute
sudo yum install httpd-utils
.
Depois de instalar o ab
, use o seguinte comando para executá-lo:
ab -c CONCURRENCY \ -n NUM_REQUESTS \ -t TIMELIMIT \ -p POST_FILE URI
Substitua:
CONCURRENCY
: número de solicitações simultâneas a serem executadas.NUM_REQUESTS
: número de solicitações a serem executadasTIMELIMIT
: número máximo de segundos para gastar em solicitaçõesPOST_FILE
: arquivo local que contém o payload HTTP POST.URI
: o URI a ser comparado.
Veja o exemplo a seguir:
ab -c 200 -n 1000000 -t 600 -P body http://10.20.30.40:80
O comando no exemplo anterior envia solicitações com uma simultaneidade de 200 (padrão de loop fechado) e para depois de 1.000.000 (um milhão) de solicitações ou 600 segundos de tempo decorrido. O comando também inclui o conteúdo do arquivo body
como um payload HTTP POST.
O comando ab
produz histogramas de latência de resposta semelhantes aos do Nighthawk, mas a resolução é limitada a milissegundos, em vez de microssegundos:
Percentage of the requests served within a certain time (ms) 50% 7 66% 7 75% 7 80% 7 90% 92 95% 121 98% 123 99% 127 100% 156 (longest request)