Appearance
Benchmarking e Performance
Para analisar a performance da aplicação e identificar gargalos em endpoints, utilizamos a gem derailed_benchmarks. Este guia explica como configurar e executar medições de performance, além de como analisar os resultados utilizando flamegraphs.
1. Preparação do Ambiente
- Configuração de Banco de Dados: Utilize um dump de produção (se seguro/possível) ou uma base com volume de dados significativo.
- Ambiente e Credenciais:
- É possível configurar credenciais no
config/application.ymle passarRAILS_ENV=developmentnos comandos do derailed. - Se quiser uma análise mais detalhada simulando a aplicação com configurações de produção, você terá que garantir (seja editando
config/credentials/production.yml.encouconfig/database.yml) que está sendo usada uma conexão com um banco de dados local no ambiente de produção. - Como os testes geralmente visam comparar resultados rodados no mesmo ambiente, o uso de
RAILS_ENV=developmenté suficiente na maioria das vezes. Utilize o ambiente de produção apenas quando desejar extrair um resultado que reflita fielmente como o endpoint responderá em produção.
- É possível configurar credenciais no
2. Autenticação nos Endpoints
A aplicação possui um hook no ApplicationController que facilita o bypass de autenticação durante os benchmarks. Você pode usar duas variáveis de ambiente para isso:
MOCK_AUTH=true: Essa variável de ambiente pode ser usada para testar endpoints que necessitem de um usuário autenticado, mas não importa qual o usuário. Autentica automaticamente como o primeiro usuário do banco (User.first).HTTP_AUTHORIZATION='Bearer <user_id_or_username>': Autentica como um usuário específico, passando o seuIDouusernameatravés da env, em formatoBearer <user_id_or_username>.
Exemplo:
bash
RAILS_ENV=development MOCK_AUTH=true PATH_TO_HIT='/api/v1/some_endpoint' bundle exec derailed exec perf:ips3. Comandos de Benchmarking
Exame Geral (IPS)
O comando perf:ips (Iterations Per Second) fornece uma visão geral de quantas vezes o endpoint consegue ser processado por segundo. É útil para comparações rápidas antes e depois de uma mudança. Quanto maior o valor do ips, melhor a performance do endpoint.
bash
RAILS_ENV=development MOCK_AUTH=true PATH_TO_HIT='/some_endpoint' IPS_TIME=10 bundle exec derailed exec perf:ipsIPS_TIME: Tempo em segundos para a execução do teste (default: 5).
Análise Detalhada (StackProf)
O comando perf:stackprof examina a call stack do endpoint para identificar exatamente onde o tempo está sendo gasto (bottlenecks).
bash
RAILS_ENV=development TEST_COUNT=100 MOCK_AUTH=true PATH_TO_HIT='/some_endpoint' bundle exec derailed exec perf:stackprofPara entender o resultado do StackProf, é necessário primeiro entender como ele é calculado. O StackProf é um profiler que examina a pilha de funções do programa (call stack) a partir de amostragens periódicas (Sampling Call-Stack Profiler). Ele tira snapshots periódicos da pilha de funções do programa, vendo as funções presentes na pilha naquele momento. Ele executa o teste uma quantidade iterativa de vezes (valor da env TEST_COUNT), e então o output do StackProf no terminal é gerado apresentando uma tabela com colunas como:
- TOTAL: Representa o número total de samples em que essa função estava na pilha, ou seja, é a quantidade de samples em que esta função ou qualquer uma das funções que são chamadas a partir dela estava presente.
- SAMPLES: Representa o número de samples em que essa função estava no topo da pilha, ou seja, representa quantas vezes essa função específica estava sendo executada no momento da amostragem (sem contar o tempo gasto em suas funções filhas).
Funções com um alto valor de SAMPLES são geralmente os melhores alvos para otimização, pois indicam que o tempo está sendo gasto diretamente nelas.
4. Gerando Flamegraphs
Para uma visualização mais intuitiva da call stack, podemos gerar um Flamegraph. Para isso, utilizamos a variável de ambiente STACKPROF_RAW (implementada via patch no projeto) para capturar dados brutos.
Passo 1: Gerar o Dump
Execute o benchmark com STACKPROF_RAW=true. Isso criará um arquivo .dump na pasta tmp/.
bash
RAILS_ENV=development TEST_COUNT=100 STACKPROF_RAW=true MOCK_AUTH=true PATH_TO_HIT='/some_endpoint' bundle exec derailed exec perf:stackprofPasso 2: Gerar o HTML do Flamegraph
Use o comando stackprof para converter o dump gerado em um gráfico interativo:
bash
# Substitua pelo nome do arquivo gerado em tmp/
stackprof tmp/2026-05-16-stackprof-cpu-myapp.dump --d3-flamegraph > tmp/flamegraph.htmlAbra o arquivo tmp/flamegraph.html no seu navegador para explorar a árvore de chamadas.
5. Como Analisar os Resultados
- IPS: Procure por números maiores. Se uma refatoração reduziu o IPS significativamente, houve regressão.
- StackProf (Terminal): Atente-se às colunas
TOTALeSAMPLESpara identificar gargalos. O que está no topo geralmente é o que consome mais CPU. - Flamegraph:
- Estrutura: As funções que iniciam a chamada estão na base (embaixo), e o topo da pilha são as últimas funções chamadas.
- Interatividade: É possível usar o hover do mouse para pegar o nome completo e detalhes da função. Há também uma barra de pesquisa no topo da página para buscar por uma função específica.
- Largura: Representa o tempo gasto. Quanto mais largo o bloco, mais tempo aquela função (e suas filhas) demorou. A porcentagem de
samplesapresentada equivale aproximadamente ao tempo gasto de cada função no endpoint, considerando como o samples é calculado. - Pilha (Vertical): Representa a hierarquia de chamadas (call stack).
- Identificando Gargalos: Procure por "platôs" largos na pilha. Eles indicam funções que demoram muito para executar mas não chamam muitas outras funções (o tempo é gasto diretamente nelas).
Dicas Extras
- Consistência: Sempre execute o benchmark múltiplas vezes para garantir consistência.
- Isolamento: Desligue outros processos pesados na sua máquina durante o teste.
- Parâmetros na URL: Se o endpoint exigir parâmetros, inclua-os no
PATH_TO_HIT:PATH_TO_HIT='/api/search?q=teste'. - Customização da Request:
- É possível escolher o método HTTP usado por meio da env
REQUEST_METHOD(ex:POST). O default é o métodoGET - Passar body por meio da env
REQUEST_BODY. Necessita que o content-type seja passado também. - Passar content-type por meio da env
CONTENT_TYPE. Dica: geramente éCONTENT_TYPE="application/json". - Passar headers extras por meio de envs no formato
HTTP_<UPPER_HEADER_NAME>(ex:HTTP_X_REQUEST_ID='123').
- É possível escolher o método HTTP usado por meio da env
- Identificando Problemas Típicos:
- N+1 Queries: Se você vir muitas chamadas repetitivas de métodos do ActiveRecord (como
load,find) de forma sequencial, pode indicar um problema de N+1. No Flamegraph, isso se manifesta como muitos blocos pequenos e repetidos. - Slow Regex: Se métodos de String ou Regexp aparecerem com alto
SAMPLES, verifique se há regexes complexas sendo executadas em loops. - Alocação de Objetos: Um alto tempo em métodos como
map,eachou inicializadores de classes pode indicar alocação excessiva de memória/objetos, o que impacta o Garbage Collector. - JSON Parsing/Rendering: Se o tempo estiver concentrado em bibliotecas de JSON, considere otimizar os serializers ou usar uma biblioteca mais rápida (como
oj).
- N+1 Queries: Se você vir muitas chamadas repetitivas de métodos do ActiveRecord (como