Diagnosticar disk IO lento no Linux com iostat e iotop
Identifique gargalos de disco no Linux usando iostat e iotop. Métricas %util, await, r/s, w/s explicadas com exemplos práticos pra sysadmins.
Aplicação lenta, load average alto e CPU mostrando 20% de uso quase
sempre apontam pro mesmo culpado: disco. O sintoma clássico é uma
query MySQL que normalmente roda em 50ms passar a levar 8 segundos
sem mudança no plano de execução, ou um deploy de Node.js que
demorava 30 segundos ficar travado em 5 minutos no npm install.
Antes de provisionar mais CPU ou RAM, você precisa confirmar que o
gargalo é IO de disco. CPU baixa com load alto é o primeiro sinal —
processos estão em estado D (uninterruptible sleep) esperando
operações de disco. Este tutorial mostra como usar iostat e
iotop pra confirmar isso em 5 minutos e identificar exatamente
qual processo está saturando seu storage.
A persona aqui é o sysadmin Linux que já fez o básico (top,
htop, free) e precisa cavar mais fundo. Tempo estimado de
execução: 10-15 minutos pra coletar evidência conclusiva.
Pré-requisitos
Você precisa de uma máquina Linux (Ubuntu 22.04+, Debian 12+, RHEL 9+
ou similar) com acesso sudo ou root. As ferramentas vêm em pacotes
separados que não fazem parte da instalação mínima padrão.
sysstat iotop root ou CAP_NET_ADMIN 5.4+ Confirme também que CONFIG_TASK_IO_ACCOUNTING está habilitado no
kernel — sem isso, iotop mostra valores zerados. Verifique com:
grep CONFIG_TASK_IO_ACCOUNTING /boot/config-$(uname -r)
A saída deve ser CONFIG_TASK_IO_ACCOUNTING=y. Em kernels custom ou
containers restritos pode aparecer como # CONFIG_TASK_IO_ACCOUNTING is not set — nesse caso, use pidstat -d como alternativa.
Instalando as ferramentas
A maioria das distribuições não inclui sysstat nem iotop na
instalação base. Eles ocupam menos de 5 MB combinados.
Instale sysstat (que fornece iostat, sar, pidstat, mpstat):
sudo apt update
sudo apt install -y sysstatEm RHEL/Rocky/Alma:
sudo dnf install -y sysstatInstale iotop:
sudo apt install -y iotopEm RHEL/Rocky/Alma:
sudo dnf install -y iotopConfirme as versões instaladas:
iostat -V
iotop --versionVersões mínimas recomendadas: sysstat 12.0+ e iotop 0.6+. Versões
muito antigas têm bugs conhecidos em cálculo de %util e na coluna
svctm.
Primeira leitura com iostat
iostat mostra estatísticas agregadas por dispositivo de bloco. A
primeira execução mostra médias desde o boot — descarte esses números
e olhe pras leituras subsequentes.
Rode iostat em modo estendido com intervalo de 2 segundos:
iostat -xz 2 5Flags importantes:
-x— estendido, mostra todas as colunas relevantes (await, %util)-z— omite dispositivos sem atividade (reduz ruído)2 5— 5 amostras de 2 segundos cada
A primeira amostra é a média desde o boot e deve ser ignorada. Analise da segunda em diante.
Identifique o dispositivo de interesse na coluna Device. Em VPS
modernas será algo como vda, sda ou nvme0n1. Particoes
(vda1, nvme0n1p1) também aparecem mas você quer o dispositivo
pai pra ver atividade total.
Interpretando as métricas
As colunas que importam pra diagnóstico estão concentradas em 6 campos. Ignore o resto até dominar esses.
| Métrica | Significado | Limiar de alerta |
|---|---|---|
r/s | Leituras por segundo (IOPS de leitura) | Depende do disco |
w/s | Escritas por segundo (IOPS de escrita) | Depende do disco |
rkB/s | Throughput de leitura em KB/s | Compare ao spec do disco |
wkB/s | Throughput de escrita em KB/s | Compare ao spec do disco |
await | Latência média por requisição em ms | >20ms suspeito, >100ms crítico |
%util | % do tempo com requisições pendentes | >80% saturação em HDD |
Em discos rotacionais (HDD), %util próximo de 100% indica saturação
real. Em SSDs e NVMes que processam IO em paralelo, %util de 100%
pode ocorrer com 10% da banda real em uso. Use await e compare
rkB/s + wkB/s contra o spec do disco pra avaliar saturação real em
mídia moderna.
A regra prática: se await está acima de 20ms num SSD ou acima de
100ms num NVMe, você tem latência anormal. Em HDDs, valores de
50-100ms já são esperados, mas acima de 200ms indica sobrecarga.
Exemplo de saída saudável
Device r/s w/s rkB/s wkB/s await %util
nvme0n1 142 89 8520 4310 0.42 12.30
42ms de latência num NVMe — normal. 12% util e ~12 MB/s combinados — disco respirando bem.
Exemplo de saída com gargalo
Device r/s w/s rkB/s wkB/s await %util
vda 890 1240 45200 78900 148.6 99.80
148ms de await é crítico — algo está fazendo muito IO sincronizado
ou o disco está saturado. %util em 99.8% num disco rotacional
confirma saturação. 2.130 IOPS combinados num disco que normalmente
faz 200 IOPS sustentados é evidência de batch job mal-comportado ou
swap thrashing.
Encontrando o processo culpado com iotop
iostat te diz QUE há gargalo. iotop te diz QUEM está causando.
Rode iotop em modo interativo:
sudo iotop -oFlags:
-o— mostra apenas processos com IO ativo (oculta os zerados)- Tecla
r— inverte ordenação - Tecla
o— alterna modo “only active” - Tecla
q— sai
Identifique a coluna DISK READ e DISK WRITE. Os processos no topo
da lista são os maiores consumidores de IO no momento.
Coluna IO> mostra o percentual do tempo que o processo passou
esperando IO. Valores acima de 30% sustentados indicam processo
IO-bound — não vai ficar mais rápido com mais CPU.
Pra capturar evidência sem deixar o iotop rodando indefinidamente,
use modo batch:
sudo iotop -o -b -n 5 -d 2 > /tmp/iotop-snapshot.txtIsso captura 5 snapshots de 2 segundos e sai. Útil pra coletar evidência durante uma janela de lentidão reportada e analisar depois.
Em containers ou kernels sem TASK_IO_ACCOUNTING, use pidstat -d 2 5 (vem no sysstat). Mostra IO por processo usando contadores
diferentes que não dependem do mesmo flag de kernel.
Verificação
Pra confirmar que sua hipótese de gargalo de disco está correta, combine 3 evidências:
iostat -xz 2 5mostrandoawaitalto e%utilalto sustentadosiotop -oapontando processo específico no topo da listatopouhtopmostrando processos em estadoD(uninterruptible sleep) — colunaSouSTATE
ps -eo pid,state,comm | awk '$2 == "D"'
Se essa lista tem processos diferentes do PID que iotop mostrou,
provavelmente são vítimas (esperando o disco liberado pelo culpado).
Se for o próprio culpado, ele está fazendo IO síncrono pesado.
Resolução de problemas
iotop retorna “Could not run iotop as a non-root user”
iotop precisa de privilégios pra ler estatísticas de processos
alheios. Execute com sudo. Se você quer permitir pra usuário
específico sem sudo toda hora, dê a capability:
sudo setcap 'cap_net_admin+eip' $(which iotop)
iostat mostra %util de 100% mas aplicação não está lenta
Caso clássico de SSD/NVMe onde %util perdeu significado. Olhe
rkB/s + wkB/s e compare com a banda nominal do disco. Se está
abaixo de 50% da banda spec, não é saturação real.
Latência alta intermitente que iostat não captura
iostat mostra médias num intervalo. Picos de latência sub-segundo
ficam escondidos na média. Use iostat -x 1 (intervalo 1s) durante a
janela problemática, ou bpftrace pra capturar latências de bloco
individuais.
Se iotop mostra kswapd0 ou [kswapd] no topo, seu sistema está em
swap thrashing — sem memória RAM, kernel está movendo páginas pra
disco constantemente. Solução não é otimizar IO; é adicionar RAM ou
encontrar o vazamento de memória. Verifique free -h e ajuste
vm.swappiness.
Próximos passos
Com o gargalo identificado, os caminhos comuns são:
- Aplicar tuning de IO scheduler —
mq-deadlinepra workloads transacionais,nonepra NVMe puro - Habilitar coleta histórica com
sar(parte dosysstat) pra análise de tendência ao longo de semanas - Investigar com
bpftraceouperfpra capturar stack traces dos syscalls de IO mais lentos - Avaliar migração pra storage NVMe se o workload exige IOPS sustentado acima de 10k
Se você está colocando uma aplicação IO-intensiva em produção, uma VPS Hostini com storage NVMe local já entrega latência consistente sub-1ms — o que elimina a maior fonte de variabilidade em diagnósticos de disco.
Perguntas frequentes
%util de 100% sempre significa que o disco é o gargalo?
Não. Em SSDs e NVMe, %util reflete apenas se há alguma requisição em voo, não saturação real. Um NVMe pode mostrar 100% util e ainda estar usando 5% da banda real. Confie em await, IOPS e throughput antes de concluir saturação em mídia moderna.
Qual a diferença entre await e svctm no iostat?
await é o tempo total que uma requisição passa no sistema (fila + serviço), em milissegundos. svctm tentava medir só o tempo de serviço, mas o cálculo era incorreto em kernels modernos e foi removido em versões recentes do sysstat. Use await como métrica principal de latência.
iotop mostra zero IO mas o sistema está lento — por quê?
iotop precisa de CONFIG_TASK_IO_ACCOUNTING habilitado no kernel. Em containers e alguns kernels customizados ele aparece zerado. Confirme com cat /proc/self/io — se o arquivo não existe ou está vazio, accounting está desabilitado e você precisa usar pidstat -d ou bpftrace.
Por que await alto mas %util baixo?
Geralmente indica disco remoto com latência de rede (NFS, iSCSI, storage de nuvem) ou throttling do hipervisor em ambientes virtualizados. O disco local não está saturado, mas cada requisição demora porque vai pela rede. Verifique o tipo de storage e métricas de rede.
iostat -x mostra rrqm/s e wrqm/s altos — isso é ruim?
Não, é o oposto. rrqm/s e wrqm/s são requisições mescladas pelo kernel antes de ir ao disco — significa que o IO scheduler está combinando operações sequenciais em batches maiores e mais eficientes. Valores altos aqui geralmente indicam workload sequencial bem otimizado.
Posso rodar iotop em produção sem impacto?
Sim, o overhead do iotop é baixo (~1-2% CPU em servidores ocupados). Use iotop -o -b -n 5 -d 2 pra capturar 5 snapshots de 2 segundos em modo batch e sair — ideal pra coletar evidência sem deixar processo rodando indefinidamente.