-
Go: Go e Gin: criando API rest com simplicidade
⤴️ Índice
📗 Sobre
💻 Rodando o Projeto
📊 Diagramas
📰 Gerando documentação com swagger
📷 Imagens do Projeto
🚋 Teste de Carga
🔍 Profilling
🔨 Ferramentas
👏 Boas Práticas
🔢 Versões
🤖 Uso de IA
Este projeto visa aprimorar a API
de Alunos do curso Go e Gin: criando API rest com simplicidade de forma estritamente educativa. Continuo incorporando padrões e melhorias para estudar aplicações práticas.
Não considero colisões nos números de CPF
e RG
, pois o objetivo é criar uma API que lide com alta carga de inserções no momento, simulando um game day (dia de uso intenso em condições adversas)
Para alcançar essas melhorias, adotei as seguintes medidas que não estavam presentes no curso original:
- Técnicas de debbuging
- Teste de carga com Gatling
- Técnicas de
Caching
usandoredis
- Técnica de
Fila
commessageBroker
para criacao de aluno usandoRabbitMQ
- POC de Escalabilidade Horizontal nos workers
- Feature Flag para acionar
caching
emessageBroker
- Profiling da aplicação para identificar os pontos de "stress".
- Profiling acionados por feature flag
- Profiling em middleware
O projeto foi desenvolvido no SO Ubuntu e testado tanto no Ubuntu quanto no Windows, informações de desenvolvimento estão voltadas para o sistema operacional Linux.
Crie uma cópia do arquivo sample.env
com o nome .env
e rode o comando docker compose up
(de acordo com sua versão do docker compose
) no diretorio raiz do projeto:
$ docker compose up
✍️ Observação:
🪟 Troubleshooting com Windows Configurações de atributos do Git que podem afetar o caractere de fim de linha não estão funcionando como esperado. Portanto, para executar o projeto no Windows, será necessário fazer a alteração no arquivo
./tests/gatling/entrypoint.sh
. Converta o arquivos deLF
paraCRLF
no seu editor de texto de preferência.
Aguarde até que as imagens sejam criadas e acesse:
http://localhost:8080/alunos
Rota para APIhttp://localhost:8080/aluno/{uuid}
Rota para APIhttp://localhost:8080/aluno/cpf/{cpf}
Rota para API- etc... *
*maiores detalhes de rotas em: swagger
http://localhost:8080/readiness
Rota de readinesshttp://localhost:8080/liveness
Rota de livenesshttp://localhost:15672
Rota de RabbitMQ (verificar.env
para senha)
http://localhost:8080/swagger/index.html
Rota para documentação Swaggerhttp://localhost:8082
Rota para ultimo resultado de teste de cargahttp://localhost:8080/debug/pprof
Rota de Profiling, disponível apenas casoPPROF_FEATURE_FLAG_ENABLED=1
. Consulte Profiling para maiores informações.
🚩 Flag | ✔️ Efeito quando ligada |
---|---|
PPROF_CPU_FEATURE_FLAG_ENABLED | Habilita rota de Profiling direto na controller |
CACHE_FEATURE_FLAG_ENABLED | Habilita estratégia de cache em redis para as rotas via middleware |
POST_ALUNO_AS_MESSAGE_FEATURE_FLAG_ENABLED | Rota de criação de aluno publica mensagens via middleware para workers consumirem ao invés de criar direto no DB |
A feature flag POST_ALUNO_AS_MESSAGE_FEATURE_FLAG_ENABLED
quando acionada faz o sistema enviar mensagens de criação de alunos para o RabbitMQ na rota POST aluno
. No arquivo docker-compose.yml
. Você pode ajustar a quantidade de réplicas do worker, que começa com 1
, para aumentar a capacidade de inserção de dados no banco de dados. Para que essa abordagem surta efeito comente a linha container_name: worker-gin
e hostname: worker-gin
. Nomear containers conflita com a funcionalidade replicas
do docker
101 worker-gin:
102 deploy:
103 replicas: 1
104 # container_name: worker-gin
105 # hostname: worker-gin
Embora seja desnecessária a instalação local de nada além do Docker para levantar o projeto, pode haver a necessidade de desenvolver/debbugar localmente.
Recomendo a instalação do GVM para controle de versões da linguagem
Recomendo a instalação da extensão Golang do VsCode
Fluxo do Serviço Alunos:
graph LR
subgraph Ações Admin Alunos
A(fa:fa-user ADMIN User)
B["fa:fa-globe Cria novo aluno"]
C["fa:fa-globe Obtém a lista completa de alunos"]
D["fa:fa-globe Busca aluno por uuid"]
E["fa:fa-globe Deleta aluno por uuid"]
F["fa:fa-globe Edita aluno por uuid"]
G["fa:fa-globe Busca aluno por CPF"]
end
subgraph Backend
subgraph Message Broker
RabbitMQ(["fa:fa-envelope Aluno-RabbitMQ"])
end
subgraph CMD
subgraph WORKER
Worker["fa:fa-gears Aluno-Worker"]
end
subgraph API
CriaNovoAluno["fa:fa-code CriaNovoAluno"]
ExibeTodosAlunos["fa:fa-code ExibeTodosAlunos"]
BuscaAlunoPorUUId["fa:fa-code BuscaAlunoPorUUId"]
DeletaAluno["fa:fa-code DeletaAluno"]
EditaAluno["fa:fa-code EditaAluno"]
BuscaAlunoPorCPF["fa:fa-code BuscaAlunoPorCPF"]
end
subgraph CACHE
Aluno-Redis(["fa:fa-memory Aluno-Redis"])
end
subgraph Models
Aluno["fa:fa-cube Aluno"]
end
end
subgraph DATABASE
Aluno-DB[("fa:fa-database Aluno-DB")]
end
end
A --> B
A --> C
A --> D
A --> E
A --> F
A --> G
C -->|GET| ExibeTodosAlunos
D -->|GET| BuscaAlunoPorUUId
E -->|DELETE| DeletaAluno
F -->|PATCH| EditaAluno
G -->|GET| BuscaAlunoPorCPF
ExibeTodosAlunos --> Aluno-Redis
BuscaAlunoPorUUId --> Aluno-Redis
BuscaAlunoPorCPF --> Aluno-Redis
Aluno-Redis ---|cached| Aluno
DeletaAluno --> Aluno
EditaAluno --> Aluno
Aluno -->|Queries| Aluno-DB
B -->|POST| CriaNovoAluno
CriaNovoAluno -.->|Publica| RabbitMQ
RabbitMQ -.->|Consome| Worker
Worker --> Aluno
Sequência de criação de aluno:
sequenceDiagram
participant A as ADMIN User
participant B as "Cria novo aluno"
participant CriaNovoAluno as CriaNovoAluno
participant RabbitMQ as Aluno-RabbitMQ
participant Worker as Aluno-Worker
A ->> B: Inicia a criação de um novo aluno
B ->> CriaNovoAluno: Envia a solicitação de criação
CriaNovoAluno -->> RabbitMQ: Produz mensagem
RabbitMQ -->> Worker: Consome mensagem
Como a imagem api-gin-rest
rodando, digite:
$ docker exec -ti api-gin-rest swag init --parseDependency --parseInternal --generalInfo cmd/api/main.go
Para os desenvolvedores que irão manipular o código ou se inspirar para seus próprios desenvolvimentos, há uma particularidade na documentação Swagger. O comando padrão do swaggo/gin-swagger (uma ferramenta que gera documentação Swagger para Go) não consegue ler structs
que utilizam gorm.Model
, e isso não está explicitamente mencionado em sua documentação. Pesquisando por uma solução, encontrei o comando apropriado para a geração.
Teste de Carga Gatling

Com o projeto instalado e em execução após o comando docker compose up
, acesse a rota que renderiza o resultado do teste mais recente em http://localhost:8082
. Caso você tenha acabado de iniciar o ambiente, nenhum teste terá ocorrido até o momento. Em um novo terminal e, estando na raiz do projeto, execute o comando:
docker exec -ti gatling-api-test /entrypoint run-test
Aguarde alguns segundos para o aquecimento dos testes (que inclui o download de dependências, caso não existam, e a execução dos próprios testes). Assim que os testes forem concluídos, o endpoint http://localhost:8082
apresentará os resultados.
Toda vez que desejar executar os testes novamente, basta rodar o comando a seguir: docker exec -ti gatling-api-test /entrypoint run-test
.
Estrutura da pasta de testes do Gatling:
$ tree
api-gin-rest
└── tests
| └── gatling
| ├── bundle # Binários e arquivos instalados do Gatling
| | ├── .keep
| | └── ... # Diretórios e arquivos gatling instalados após primeiro teste
| ├── results # Resultados dos testes
| | ├── history # Histórico com todos os testes já performados e a pagina default
| | | ├── default # Dados de teste padrão, exibidos quando nenhum teste ainda foi performado
| | | └── ... # Diretórios de testes já performados
| | └── latest # Arquivos do último teste performado
| | ├── .keep
| | └── ... # Diretórios e arquivos do resultado mais recente
| ├── user-files
| | ├── resources # Arquivos de recursos utilizados nos testes: tsv, etc...
| | | └── api-gin-rest
| | | └── alunos.tsv # Arquivo de dados de post paylod de alunos
| | └── simulations # Pasta dos roteiros de testes, simulações
| | └── api-gin-rest
| | └── AlunosSimulation.scala # Roteiro de testes em scala
| ├── Dockerfile
| └── entrypoin.sh # As automações do Gatling estão aqui.
|
$ tree
.
Usamos uma imagem com o Gatling instalado para performar testes de carga de maneira automatizada. A imagem responsável por fornecer essa saída também é responsável por processar o teste.
Importante: Isso não limpa as inserções feitas no banco de dados.
docker exec -ti gatling-api-test /entrypoint clean-test
Isso limpa as inserções feitas no banco de dados.
docker exec -ti gatling-api-test /entrypoint clean-db
Caso deseje alterar as configurações padrão do teste, modifique o arquivo tests/gatling/user-files/simulations/AlunosSimulation.scala
. O método setUp
lhe proporciona flexibilidade na criação de cenários de simulação.
setUp(
testAlunos.inject(rampUsers(1000).during(20.seconds))
).protocols(httpProtocol)
Visualização de logs de requisições do Gatling (apenas em ambiente local para fins de depuração):
Após a instalação do Gatling, que ocorre na primeira vez que você solicita a execução de um teste, vá até o arquivo api-gin-rest/tests/gatling/bundle/conf/logback.xml
e descomente a linha 13
.
11 <!-- uncomment and set to DEBUG to log all failing HTTP requests -->
12 <!-- uncomment and set to TRACE to log all HTTP requests -->
13 <logger name="io.gatling.http.engine.response" level="TRACE" />
O profiling da aplicação para fins de testes e validação está vinculado às rotas. O processo não é executado de maneira dockerizada, necessitando ter o Go e o Graphviz instalados na sua máquina.
$ sudo apt-get install graphviz
Para ativar o profiling de rotas, basta alterar o valor da variável de ambiente PPROF_FEATURE_FLAG_ENABLED
para 1
no arquivo .env
:
PPROF_FEATURE_FLAG_ENABLED=1
Com isso, a seguinte rota fica ativa e apresenta resultados dos profiles disponíveis:
http://localhost:8080/debug/pprof
Podemos agora, com Go
e Graphviz
na máquina hospedeira, ligar a coleta de métricas. Observe a imagem com dois terminais, no terminal 1 foi inserido o comando:
$ go tool pprof http://localhost:8080/debug/pprof/profile
Isso fará com que, durante os próximos trinta segundos, as requests feitas na API gerem massa de dados para o profiler.
Assim que o comando go tool pprof
for iniciado, em outro terminal ja tenha o comando do Teste de Carga preparado para rodar e gerar insumos para o pprof. Comando no terminal 2:
$ docker exec -ti gatling-api-test /entrypoint run-test
Após o Teste de Carga rodar sua saida sera similar a seguinte:
No terminal do pprof
o cursor deve estar aguardando o proximo comando para continuar o profiling, digite web
no cursor e de enter
, aguarde seu navegador o exibir a árvore de processamento de sua aplicação.
Fetching profile over HTTP from http://localhost:8080/debug/pprof/profile
Saved profile in /home/jtony/pprof/pprof.main.samples.cpu.003.pb.gz
File: main
Type: cpu
Time: Oct 10, 2023 at 5:27pm (-03)
Duration: 30.01s, Total samples = 410ms ( 1.37%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) web
Bibliografia: Profiling gin with pprof
As seguintes ferramentas foram usadas na construção do projeto:
-
Linguagem:
-
Framework & Libs:
-
Infra & Tecnologias
-
GUIs:
Seguindo boas práticas de desenvolvimento:
As tags de versões estao sendo criadas manualmente a medida que os estudos avançam com melhorias notáveis no projeto. Cada funcionalidade é desenvolvida em uma branch a parte quando finalizadas é gerada tag e mergeadas em master.
Para obter mais informações, consulte o Histórico de Versões.
O cabeçalho desta página foi criado com o auxílio de inteligência artificial e um mínimo de
retoque e construção no Gimp
Foram utilizados os seguintes prompts para sua criação no Bing IA:
Gopher com roupa de estudante bebendo gin
"Gopher simbolo da linguagem golang azul em cores cartoon chapadas em uniforme escolar segurando um copo de drink com uma garrafde gin no chaco e fundo branco"(sic)IA também é utilizada em minhas pesquisas e estudos como ferramenta de apoio; no entanto, artes e desenvolvimento são, sobretudo, atividades criativas humanas.
Contrate artistas para projetos comerciais ou mais elaborados e Aprenda Engenhosidade!