Rastreando gargalos de armazenamento no Linux com eBPF: além do iostat

      Lucas Ferreira 10 min de leitura
      Rastreando gargalos de armazenamento no Linux com eBPF: além do iostat

      Abandone as médias do iostat. Aprenda a usar eBPF, biolatency e biosnoop para visualizar a latência de cauda (p99) e identificar gargalos de disco invisíveis em tempo real.

      Compartilhar:

      Você está olhando para o painel do Grafana. O cliente está reclamando de timeouts intermitentes na aplicação. Você abre o terminal, digita iostat -x 1 e vê uma latência média (await) de 2ms. O disco parece estar dormindo. No entanto, os logs da aplicação mostram transações demorando 500ms para commitar no banco de dados.

      O que está acontecendo? Você está sendo enganado pela média.

      Ferramentas tradicionais como iostat e sar foram projetadas em uma era onde discos giravam a 5400 RPM e latências eram medidas em dezenas de milissegundos. Hoje, com arrays All-Flash e dispositivos NVMe capazes de centenas de milhares de IOPS, olhar para médias de um segundo é como tentar assistir a uma corrida de Fórmula 1 através de uma apresentação de slides: você perde tudo o que acontece entre os quadros.

      Para ver o invisível, precisamos parar de contar estatísticas globais e começar a rastrear eventos individuais. É aqui que o eBPF (Extended Berkeley Packet Filter) muda o jogo da observabilidade de armazenamento.

      Resumo em 30 segundos

      • Médias mentem: O iostat mostra a média de latência em um intervalo (ex: 1s), escondendo picos de latência (tail latency) que causam timeouts na aplicação.
      • Custo do contexto: Ferramentas antigas de trace (como blktrace) podem derrubar a performance de discos NVMe rápidos devido ao overhead de enviar eventos para o espaço do usuário.
      • Agregação no Kernel: O eBPF permite medir cada I/O individualmente e gerar histogramas dentro do kernel, com custo computacional quase zero, permitindo identificar qual processo (PID) exato está saturando o disco.

      O mito da média: por que o iostat ignora sua latência de cauda

      O iostat lê dados de /proc/diskstats. O kernel mantém contadores simples: quantos reads, quantos writes, quantos setores e quanto tempo total foi gasto. Quando você roda iostat 1, ele pega o delta desses contadores e divide pelo tempo.

      O problema matemático é simples: se você tem 99 requisições que levam 0.1ms (NVMe rápido) e 1 requisição que leva 100ms (um garbage collection do SSD ou contenção de lock), a média será aproximadamente 1ms.

      Para o iostat, o disco está voando. Para o usuário que caiu na requisição de 100ms, o sistema travou. Isso é a latência de cauda (tail latency). Em sistemas distribuídos e bancos de dados de alta performance, o P99 (o 99º percentil) importa muito mais que a média.

      Comparativo visual: A ilusão da média estável versus a realidade caótica dos picos de latência revelada por histogramas. Figura: Comparativo visual: A ilusão da média estável versus a realidade caótica dos picos de latência revelada por histogramas.

      💡 Dica Pro: Se o seu avgqu-sz (tamanho médio da fila) no iostat estiver alto, mas a latência baixa, você tem paralelismo. Se a latência subir linearmente com a fila, você atingiu o limite físico do dispositivo ou do link SATA/SAS/PCIe.

      A falácia do blktrace e o custo do context switch

      Antigamente, quando precisávamos de detalhes, usávamos o blktrace. Ele é poderoso, mas funciona enviando eventos de trace do kernel para o userspace para serem processados.

      Em um HDD fazendo 150 IOPS, isso é trivial. Em um SSD NVMe Gen4 capaz de 1.000.000 IOPS, o blktrace tenta gerar e transferir um milhão de eventos por segundo. Isso causa uma tempestade de interrupções e trocas de contexto (context switches) que podem consumir 20-30% da CPU apenas para observar o disco.

      É o princípio da incerteza de Heisenberg aplicado à infraestrutura: a ferramenta de medição altera o resultado da medição. Você pode causar um incidente tentando diagnosticar um.

      Anatomia de um I/O: dissecando a struct bio no kernel

      Para entender como o eBPF resolve isso, precisamos descer ao nível do kernel Linux. Todo I/O de bloco no Linux é representado por uma estrutura chamada struct bio.

      Quando um banco de dados (como PostgreSQL ou MySQL) pede para ler um bloco, o fluxo simplificado é:

      1. VFS Layer: O sistema de arquivos recebe o pedido.

      2. Block Layer: O pedido é transformado em uma struct bio.

      3. Driver NVMe/SCSI: O bio é enviado para a fila do dispositivo.

      Com eBPF, podemos anexar "sondas" (kprobes ou tracepoints) em pontos específicos desse ciclo de vida sem recompilar o kernel e sem parar o sistema.

      Os pontos de trace mais críticos para storage são:

      • block_rq_issue: Quando o pedido é enviado ao driver do disco.

      • block_rq_complete: Quando o disco confirma que terminou.

      A diferença de tempo entre esses dois eventos é a latência real do hardware (service time), livre de ruídos de filas do sistema operacional ou agendadores de I/O.

      O caminho do dado: Onde o eBPF intercepta a struct bio para medir a latência real do dispositivo, ignorando a latência do sistema de arquivos. Figura: O caminho do dado: Onde o eBPF intercepta a struct bio para medir a latência real do dispositivo, ignorando a latência do sistema de arquivos.

      Observabilidade granular: rastreando latência por PID

      A mágica do eBPF é a agregação no kernel. Em vez de enviar 1 milhão de eventos para o userspace, o programa eBPF captura o evento, calcula a latência (delta de tempo), atualiza um mapa de histograma na memória do kernel e descarta o evento. O userspace lê apenas o resumo final a cada poucos segundos. O overhead é insignificante.

      Isso nos permite usar ferramentas do pacote BCC (BPF Compiler Collection) ou bpftrace para diagnósticos cirúrgicos.

      1. Biolatency: A verdade em histogramas

      Em vez de uma média, o biolatency mostra a distribuição de probabilidade da latência.

      Tracing block device I/O... Hit Ctrl-C to end.
      ^C
      disk = 'nvme0n1'
           usecs               : count     distribution
               0 -> 1          : 0        |                                        |
               2 -> 3          : 0        |                                        |
               4 -> 7          : 152      |                                        |
               8 -> 15         : 4582     |*************                           |
              16 -> 31         : 12400    |****************************************|
              32 -> 63         : 6201     |********************                    |
              64 -> 127        : 98       |                                        |
             128 -> 255        : 2        |                                        |
             256 -> 511        : 0        |                                        |
             512 -> 1023       : 1        |                                        |
            1024 -> 2047       : 0        |                                        |
            2048 -> 4095       : 0        |                                        |
            4096 -> 8191       : 5        |                                        |
      

      Note o detalhe acima: a maioria dos I/Os está entre 16-31 microssegundos (excelente para NVMe). Mas temos 5 operações na faixa de 4-8ms (4096-8191 usecs). O iostat diria que a média é 0.02ms. O biolatency mostra que alguém esperou 8ms.

      2. Biosnoop: Isolando o vizinho barulhento

      Em um servidor de virtualização (Proxmox, KVM) ou um storage server (TrueNAS Scale), muitas vezes o disco está lento porque um processo específico está abusando. O iostat não mostra PIDs. O iotop mostra throughput, mas não latência.

      O biosnoop imprime cada I/O com o PID responsável:

      TIME(s)     COMM           PID    DISK    T  SECTOR    BYTES   LAT(ms)
      0.000000    kworker/u32:1  189    nvme0n1 W  2341234   4096       0.01
      0.000451    postgres       4521   nvme0n1 R  9928112   16384      0.02
      0.000912    backup-job     9912   nvme0n1 R  123123    1048576  155.00
      

      ⚠️ Perigo: O biosnoop imprime cada evento. Em discos muito rápidos, use-o por poucos segundos e redirecione para um arquivo, ou você será inundado por texto, o que paradoxalmente pode causar lentidão no terminal.

      Comparativo: ferramentas de análise de storage

      Para situar onde o eBPF brilha, vamos comparar as abordagens.

      Característica iostat / sar blktrace eBPF (biolatency/biosnoop)
      Fonte de Dados /proc/diskstats (Contadores) Tracepoints (Raw) Tracepoints + Mapas BPF
      Overhead Muito Baixo Alto (em NVMe rápido) Muito Baixo
      Granularidade Média do dispositivo Evento individual Evento individual ou Histograma
      Visibilidade Dispositivo inteiro Dispositivo + Metadados Processo (PID), Latência, Flags
      Segurança em Prod Segura Risco de travar CPU Segura (Sandbox)
      Caso de Uso Monitoramento geral Debug profundo (lab) Análise de latência em produção

      Dados de alta cardinalidade: o cenário real

      Imagine um cenário comum em Home Labs ou Enterprise: Um pool ZFS com 6 discos. A performance de escrita cai drasticamente a cada 10 minutos.

      Usando zpool iostat, você vê a banda cair. Usando iostat -x, você vê a utilização dos discos em 100%. Ao rodar um script eBPF customizado que rastreia zfs_write, você descobre que não é o throughput que está saturando, mas sim a latência de sync de um disco específico que está morrendo silenciosamente. Ele não falhou no SMART, mas está tentando recuperar setores (retries), elevando a latência de gravação de 0.1ms para 200ms.

      O ZFS espera o disco mais lento. O eBPF aponta exatamente qual disco (pelo identificador do dispositivo) e qual tipo de operação (flush/sync) está causando o gargalo, algo que métricas agregadas jamais mostrariam com clareza.

      Diagnóstico preciso: O eBPF atua como um scanner de raio-x, identificando qual processo específico está entupindo o fluxo de dados em um ambiente compartilhado. Figura: Diagnóstico preciso: O eBPF atua como um scanner de raio-x, identificando qual processo específico está entupindo o fluxo de dados em um ambiente compartilhado.

      O fim da adivinhação

      A era de adivinhar performance de storage baseada em médias acabou. Discos modernos são rápidos demais e complexos demais para serem resumidos em um único número a cada segundo.

      Se você gerencia storage, seja um cluster Ceph de petabytes ou um TrueNAS em casa, a transição para ferramentas baseadas em eBPF não é apenas uma melhoria incremental; é a diferença entre saber que "o sistema está lento" e saber que "o processo de backup está causando latência de 45ms no disco sdb durante operações de flush".

      Instale o bcc-tools ou bpftrace na sua distro hoje. Comece a ver o que você estava perdendo.

      Referências & Leitura Complementar

      • Gregg, Brendan. BPF Performance Tools. Addison-Wesley Professional, 2019. (A bíblia do eBPF).

      • Kernel.org. Linux Block Layer IO accounting. Documentação oficial sobre como o kernel contabiliza estatísticas de disco.

      • Jens Axboe. fio - Flexible I/O Tester. (Ferramenta essencial para gerar cargas de trabalho controladas para testar sua observabilidade).

      • NVMe Express. NVM Express Base Specification. (Para entender as filas de comando e latências nativas do protocolo).

      Qual é o overhead de usar eBPF em produção comparado ao blktrace? O eBPF é projetado para ser extremamente leve. Enquanto o blktrace pode causar degradação significativa de performance ao enviar todos os eventos para o userspace (context switching), o eBPF agrega os dados dentro do próprio kernel (in-kernel aggregation), gerando overhead quase imperceptível, ideal para ambientes de produção sensíveis.
      Preciso recompilar meu kernel para usar ferramentas como biolatency? Geralmente não. A maioria das distribuições Linux modernas (kernel 4.9+) já vem com suporte a eBPF habilitado (CONFIG_BPF). Você precisará apenas instalar o pacote de ferramentas BCC (BPF Compiler Collection) ou bpftrace disponíveis nos repositórios oficiais da sua distro.
      Como o eBPF ajuda a identificar problemas em discos NVMe rápidos? Discos NVMe modernos têm latências na casa dos microssegundos. Ferramentas tradicionais que amostram a cada segundo perdem esses eventos rápidos. O eBPF permite capturar e medir cada operação individual de I/O na granularidade de nanossegundos, permitindo visualizar 'micro-stutters' que passariam despercebidos.
      #eBPF #Linux Storage #Latência de Disco #Observabilidade #NVMe #Performance Tuning #BCC Tools #bpftrace
      Lucas Ferreira
      Assinatura Técnica

      Lucas Ferreira

      Engenheiro de Observabilidade

      "Transformo o caos de logs, métricas e traces em clareza operacional. Minha missão é eliminar pontos cegos e garantir que nada permaneça invisível na infraestrutura."