Skip to content

Teste de Carga

Pessoal agora vamos pensar em como vamos testar nosso sistema! Até aqui criamos, mas como vamos testar para ver se tudo está funcionando? E se tudo estiver funcionando, até quando conseguimos segurar diversos usuários?

O teste de carga é uma técnica de teste de software que visa avaliar o comportamento de um sistema sob condições de carga específicas. O objetivo é verificar se o sistema é capaz de suportar a carga esperada, garantindo que o mesmo funcione de forma eficiente e eficaz.

Mas Murilo, quando fazemos uma requisição com o Insomnia, Postman ou até mesmo acessamos uma página web, não estamos realizando um teste de carga?

Sim, de certa forma estamos realizando um teste de carga, porém, o teste de carga que estamos falando é um pouco mais complexo. Ele é realizado com o intuito de avaliar o comportamento do sistema sob condições de carga específicas, como por exemplo, o número de usuários simultâneos, a quantidade de requisições por segundo, entre outros.

O teste de carga é uma etapa muito importante no ciclo de desenvolvimento de software, pois ele permite avaliar o comportamento do sistema sob condições de carga específicas, garantindo que o mesmo funcione de forma eficiente e eficaz.

Além disso, o teste de carga permite identificar possíveis gargalos e problemas de desempenho no sistema, possibilitando a correção dos mesmos antes que o sistema seja disponibilizado para os usuários finais.

Para realizar um teste de carga, é necessário seguir os seguintes passos:

  1. Definir os objetivos do teste: Antes de iniciar o teste, é importante definir os objetivos que se deseja alcançar com o mesmo. Por exemplo, verificar se o sistema é capaz de suportar um determinado número de usuários simultâneos, a quantidade de requisições por segundo, entre outros.

  2. Definir as métricas de avaliação: Após definir os objetivos do teste, é importante definir as métricas que serão utilizadas para avaliar o comportamento do sistema. Por exemplo, tempo de resposta, taxa de erro, entre outros.

  3. Elaborar o plano de teste: Com os objetivos e métricas definidos, é necessário elaborar o plano de teste, que consiste em definir as condições de carga que serão aplicadas ao sistema, como por exemplo, o número de usuários simultâneos, a quantidade de requisições por segundo, entre outros.

  4. Executar o teste: Após elaborar o plano de teste, é necessário executar o teste, aplicando as condições de carga definidas ao sistema e coletando os resultados obtidos.

  5. Analisar os resultados: Por fim, é necessário analisar os resultados obtidos, verificando se o sistema foi capaz de suportar a carga esperada e se o mesmo funcionou de forma eficiente e eficaz.

Durante o teste de carga, é importante avaliar algumas métricas de desempenho que podem indicar possíveis problemas no sistema. Algumas das métricas mais comuns são:

  • Tempo de Resposta: Tempo que o sistema leva para responder a uma requisição.

  • Taxa de Erro: Porcentagem de requisições que resultaram em erro.

  • Taxa de Transferência: Quantidade de dados transferidos por segundo.

  • Utilização de Recursos: Porcentagem de utilização dos recursos do sistema, como CPU, memória, disco, entre outros.

Tadjudin faz uma definição bastante interessante de tipos de teste de carga em seu trabalho Load Testing with Python. Vamos avaliar as definições que ele pontua:

Verifica como o sistema se comporta sob uma carga específica, como por exemplo, o número de usuários simultâneos, a quantidade de requisições por segundo, entre outros.

(Referência: link)

Verifica como o sistema se comporta sob uma carga extrema, como por exemplo, o número máximo de usuários simultâneos, a quantidade máxima de requisições por segundo, entre outros. O objetivo deste teste é verificar o limite do sistema e identificar possíveis problemas de desempenho.

(Referência: link)

Verifica como o sistema se comporta sob uma carga constante, por um longo período de tempo. O objetivo deste teste é verificar se o sistema é capaz de manter o desempenho ao longo do tempo, identificando possíveis problemas de vazamento de recursos.

(Referência: link)

Nesta seção pessoal, vamos avaliar as aplicações que serão testadas durante nosso estudo sobre os testes de carga. Elas são aplicações construídas com alguns frameworks de Python e todas estão dockerizadas 🐳.

Peço que vocês dediquem uma quantidade de tempo para verificar como elas foram desenvolvidas e quais são as diferenças entre elas. Todos os códigos fonte estão disponíveis no repositório do GitHub.

Aqui temos um breve descritivo de cada uma das aplicações que serão testadas.

Essa aplicação foi construída com o framework Flask e utiliza o banco de dados SQLite. Ela é uma aplicação simples que permite a criação de usuários e a listagem de todos os usuários cadastrados.

O CRUD foi implementado utilizando a biblioteca sqlite3 do Python e comandos SQL. A aplicação foi dockerizada e está pronta para ser executada. O link para ela pode ser visto aqui.

Um ponto importante para se observar, essa implementação foi deployada com o servidor built-in do Flask, o que não é recomendado para ambientes de produção.

6.3 Aplicação 2 - Flask com SQLite e Servidor Gunicorn

Section titled “6.3 Aplicação 2 - Flask com SQLite e Servidor Gunicorn”

Está aplicação é igual a anterior, mas utilizando o servidor Gunicorn para servir a aplicação. O Gunicorn é um servidor HTTP WSGI para Python que é amplamente utilizado para servir aplicações web Python em produção.

Você pode acessar o código fonte aqui.

Agora pessoal, vamos para uma aplicação construída com o framework FastAPI. O FastAPI é um framework moderno e rápido para construir APIs web com Python 3.6+ baseado em anotações de tipo.

Vamos utilizar a mesma base de código da aplicação 1, mas agora com o FastAPI. O link para o código fonte pode ser acessado aqui.

Pessoal ainda podemos criar diferentes aplicações para testar. Essas são apenas algumas aplicações base que utilizam diferentes frameworks de Python.

Pessoal agora vamos falar sobre as ferramentas de teste que serão utilizadas para avaliar as aplicações que foram construídas. Cada ferramenta apresentada aqui tem suas particularidades e é importante entender como elas funcionam.

Nosso objetivo será compreender como elas são utilizadas. Vamos realizar todos os testes na aplicação 1. A comparação com as demais aplicações fica como tarefa de implementação de vocês.

O Locust é uma ferramenta de teste de carga de código aberto que permite que você escreva cenários de teste em Python. Ele é altamente escalável e pode ser usado para testar aplicações web, APIs e outros sistemas. Sua documentação oficial pode ser acessada aqui.

Vamos testar nossa aplicação 1 com o Locust. Para isso, vamos seguir os seguintes passos:

Terminal window
# criar um venv
python3 -m venv venv
# ativar o venv
source venv/bin/activate
# instalar o locust
pip install locust

Agora vamos criar um arquivo chamado locustfile.py com o seguinte conteúdo:

from locust import HttpUser, task, between
class WebsiteUser(HttpUser):
wait_time = between(1, 5)
@task
def criar_usuario(self):
self.client.post("/usuarios", json={"nome": "Fulano", "email": "mail@mail.com" })
@task
def pegar_usuarios(self):
self.client.get(f"/usuarios")

Agora no terminal execute a aplicação com o comando:

Terminal window
locust -f locustfile.py

Acesse o endereço http://localhost:8089 e configure o número de usuários e a taxa de requisições. Depois clique em Start Swarming para iniciar o teste.



Pessoal vamos analisar aqui um caso um pouco mais completo agora. Vamos ter nossa API primeiro rodando com o Flask e se conectando em um banco de dados SQLite. Mas vamos servir ela de uma maneira diferente para a aplicação. Vamos colocar um proxy reverso na frente dela.

“Calma lá Murilão, vamos colocar o que?”

Um Proxy Reverso é um servidor que fica entre o cliente e a nossa aplicação. Ele é utilizado para gerenciar como as requisições externas chegam até nossa aplicação interna. Com ele, conseguimos manter nossa aplicação rodando com comunicação HTTP internamente, enquanto usamos HTTPS externamente, com certificados SSL sendo gerenciados no proxy.

“Murilo, pera ai, o que é um proxy então?”

Boa pergunta! Um proxy comum é uma forma de interceptar conexões de saída em uma rede. Ele atua em nome do cliente, repassando requisições internas para a internet, aplicando políticas como controle de acesso, autenticação ou caching. Já o proxy reverso faz o caminho contrário: ele recebe requisições externas e as encaminha para os servidores internos.

CaracterísticaProxy (normal)Proxy Reverso
Quem configuraO clienteO servidor
Esconde quem?O cliente (usuário final)O servidor (backend/API)
Protege quem?O clienteO servidor
Exemplo típicoAcesso controlado à webBalanceamento de carga
Ferramentas comunsSquid, TinyProxyNGINX, HAProxy, Traefik

Legal, agora que falamos dele, vamos configurar!! Vamos fazer isso utilizando uma ferramenta chamada Nginx.

Vamos trabalhar com a aplicação em Python:

app.py