Como usar bpftrace para profiling dinâmico de aplicações em produção
1. Introdução ao bpftrace e ao Profiling Dinâmico
1.1. O que é bpftrace
bpftrace é uma ferramenta de tracing de alto nível baseada em eBPF (Extended Berkeley Packet Filter) que permite analisar sistemas Linux em tempo real com baixo overhead. Diferente de ferramentas tradicionais de profiling que exigem reinicialização ou recompilação de aplicações, o bpftrace possibilita a inserção dinâmica de pontos de observação (probes) em kernels e processos em execução, sem modificar o código ou interromper o serviço.
1.2. Profiling estático vs dinâmico
O profiling estático exige instrumentação prévia do código (como adicionar logs ou usar profilers embutidos), o que muitas vezes não é viável em sistemas legados ou de terceiros. O profiling dinâmico, por outro lado, permite:
- Anexar probes a funções específicas sem modificar binários
- Coletar dados apenas quando necessário, reduzindo overhead
- Analisar problemas intermitentes que são difíceis de reproduzir em ambientes de teste
Em produção, essas características são cruciais para diagnosticar gargalos sem comprometer a estabilidade.
1.3. Pré-requisitos
- Kernel Linux 4.9+ (recomendado 5.4+ para recursos completos)
- Suporte a eBPF habilitado (verificar com
cat /proc/sys/kernel/bpf_stats_enabled) - Instalação do bpftrace (versão 0.19+ recomendada)
- Acesso root ou capabilities:
CAP_BPF,CAP_SYS_ADMIN,CAP_PERFMON
2. Instalação e Configuração Inicial do bpftrace
2.1. Instalação via gerenciador de pacotes
# Ubuntu/Debian
sudo apt install bpftrace
# RHEL/CentOS/Fedora
sudo dnf install bpftrace
# Compilação manual (última versão)
git clone https://github.com/bpftrace/bpftrace.git
cd bpftrace
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
sudo make install
2.2. Verificação de dependências
# Checar suporte a BTF (BPF Type Format)
ls /sys/kernel/btf/vmlinux
# Verificar permissões
sudo bpftrace -e 'BEGIN { printf("OK\n"); exit(); }'
Se ocorrer erro de permissão, configure capabilities:
sudo setcap cap_bpf,cap_sys_admin,cap_perfmon+ep $(which bpftrace)
2.3. Teste rápido
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("%s %s\n", comm, str(args->filename)); }'
Este comando exibe o nome do processo e o arquivo sendo aberto em cada chamada open().
3. Sintaxe e Conceitos Fundamentais do bpftrace
3.1. Estrutura de um one-liner
A sintaxe básica é: probe/filter { action }
# Exemplo: contar chamadas ao sistema write por processo
bpftrace -e 'kprobe:sys_write { @[comm] = count(); }'
3.2. Probes comuns
- kprobes: Funções do kernel (
kprobe:do_sys_open) - uprobes: Funções de user-space (
uprobe:/usr/lib/libc.so.6:malloc) - tracepoints: Pontos fixos do kernel (
tracepoint:syscalls:sys_enter_read) - software events: Eventos como CPU ciclos (
software:task-clock:100)
3.3. Mapas e agregações
# Histograma de latência para chamadas read()
bpftrace -e 'kprobe:sys_read { @start[tid] = nsecs; }
kretprobe:sys_read /@start[tid]/ {
@latency = hist(nsecs - @start[tid]);
delete(@start[tid]);
}'
4. Profiling de Aplicações em Produção com bpftrace
4.1. Rastreamento de chamadas de sistema
Identifique gargalos de I/O:
# Top 5 syscalls por processo
bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe, comm] = count(); }
END { printf("%-30s %-20s %10s\n", "Syscall", "Process", "Count");
print(@, 5); clear(@); }'
4.2. Análise de funções de usuário com uprobes
Para aplicações C/C++:
# Rastrear chamadas a malloc em um processo específico
bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /pid == 1234/ {
@[comm] = count();
}'
Para Python (com CPython):
# Rastrear chamadas a PyEval_EvalFrame (execução de frame Python)
bpftrace -e 'uprobe:/usr/lib/python3.10/libpython3.10.so:PyEval_EvalFrame {
@[ustack] = count();
}'
4.3. Monitoramento de alocação de memória
# Detectar vazamentos de memória com malloc/free imbalance
bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc {
@alloc[tid] = count();
}
uprobe:/lib/x86_64-linux-gnu/libc.so.6:free {
@free[tid] = count();
}
END {
printf("TID MALLOC FREE IMBALANCE\n");
print(@alloc); print(@free);
}'
5. Casos Práticos de Profiling Dinâmico
5.1. Latência em servidores web (Nginx)
# Rastrear operações de abertura de arquivo no Nginx
bpftrace -e 'kprobe:do_sys_open /comm == "nginx"/ {
@start[tid] = nsecs;
}
kretprobe:do_sys_open /@start[tid]/ {
@latency = hist(nsecs - @start[tid]);
delete(@start[tid]);
}'
5.2. Contenção de locks em aplicações multithread
# Monitorar aquisição de mutex (glibc)
bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libpthread.so.0:pthread_mutex_lock {
@lock_acquire[comm] = count();
}
uprobe:/lib/x86_64-linux-gnu/libpthread.so.0:pthread_mutex_unlock {
@lock_release[comm] = count();
}'
5.3. Operações de disco e sistema de arquivos
# Rastrear escritas no sistema de arquivos ext4
bpftrace -e 'kprobe:ext4_file_write_iter {
@file[tid] = str(args->file->f_path.dentry->d_name.name);
@size[tid] = args->len;
}
kretprobe:ext4_file_write_iter /@file[tid]/ {
printf("Written %d bytes to %s (ret: %d)\n",
@size[tid], @file[tid], retval);
delete(@file[tid]); delete(@size[tid]);
}'
6. Boas Práticas e Segurança em Produção
6.1. Minimizando overhead
- Use filtros precisos (ex.:
/pid == 1234/) - Prefira tracepoints a kprobes quando possível
- Limite a duração da coleta com
timeoutouENDcondition - Utilize amostragem com
sample_rate()para alta frequência
# Amostragem: coleta 1 a cada 100 eventos
bpftrace -e 'kprobe:sys_read /sample_rate(100)/ { @[comm] = count(); }'
6.2. Permissões e isolamento
# Executar com usuário não-root via sudo e capabilities
sudo -u appuser bpftrace -e '...'
# Verificar logs do kernel para erros de segurança
dmesg | grep bpf
6.3. Saída estruturada e integração
# Exportar para JSON
sudo bpftrace -e '...' -o result.json
# Integração com Prometheus via ebpf_exporter
# (configuração YAML do exporter com probes bpftrace)
7. Troubleshooting e Limitações do bpftrace
7.1. Erros comuns
- "BTF not found": Kernel sem suporte a BTF (use
--no-btfou compile comCONFIG_DEBUG_INFO_BTF=y) - "Probe not supported": Função não exportada ou inlined (tente
kprobe:func_namevstracepoint) - "Script too large": Limite de 512 instruções eBPF (divida scripts complexos)
7.2. Debugging de scripts
# Modo verbose: mostra probes resolvidas
sudo bpftrace -v script.bt
# Modo debug: exibe código eBPF gerado
sudo bpftrace -d script.bt
# Verificar se probe existe
sudo bpftrace -l 'kprobe:do_sys_open'
7.3. Alternativas e complementos
- perf: Para amostragem de CPU e hardware counters
- systemtap: Similar, mas com maior overhead e sintaxe mais complexa
- ebpf_exporter: Exporta métricas bpftrace para Prometheus
- bcc: Biblioteca Python para ferramentas eBPF mais complexas
Referências
- Documentação oficial do bpftrace — Repositório oficial com guias, exemplos e referência completa de sintaxe.
- bpftrace One-Liners Tutorial — Tutorial prático com 50+ one-liners para diagnóstico rápido.
- eBPF.io - What is eBPF? — Introdução ao ecossistema eBPF, incluindo bpftrace e suas aplicações.
- Brendan Gregg's bpftrace Examples — Coleção de casos reais de profiling dinâmico por um dos criadores da ferramenta.
- Linux Kernel BPF Documentation — Documentação oficial do kernel sobre BPF, com detalhes técnicos sobre probes e segurança.
- bpftrace Reference Guide — Guia de referência completo com todos os probes, funções e mapas suportados.
- Profiling Production Systems with bpftrace — Artigo da InfoQ com estudos de caso de profiling em produção.