IO lento: medir o disco antes de culpar o provedor
A aplicação ficou lenta, a CPU está ociosa e a suspeita recai sobre o disco. Antes de abrir chamado, dá para medir — e na maioria das vezes a causa está dentro da própria máquina.
Equipe EasyOps Cloud · · 8 min de leitura
A aplicação está lenta. A CPU aparece ociosa, memória sobrando, rede tranquila. Só sobra o disco — e a conclusão natural é que o armazenamento do provedor está com problema.
Às vezes está. Bem mais frequentemente, o disco está entregando o esperado e quem está pedindo demais é a própria máquina: um banco sem índice varrendo tabela, um log em modo de depuração, um backup rodando no horário de pico.
A diferença entre os dois cenários é mensurável em poucos minutos, e vale medir antes de abrir chamado — porque a conversa muda completamente quando você chega com números.
Primeiro: confirmar que é disco
O sinal mais direto vem do vmstat:
vmstat 1 10Duas colunas respondem. A wa mostra o percentual de tempo em que a CPU ficou
parada esperando entrada e saída; a b mostra quantos processos estão bloqueados
nessa espera.
wa acima de 20% com us e sy baixos é o retrato de disco como gargalo. Se wa está
próximo de zero, o problema é outro, e o diagnóstico de latência cobre as demais
hipóteses.
O indicador de pressão dá a mesma informação com mais precisão:
cat /proc/pressure/iosome avg60 acima de 20% significa que os processos passaram mais de um quinto do
último minuto parados esperando disco. É um número acionável, ao contrário do
load average, que mistura CPU e disco na mesma conta.
Ler o iostat sem se enganar
sudo apt install sysstat
iostat -xz 2 5Ignore a primeira amostra — ela é a média desde o boot. As colunas que importam:
| Coluna | O que é | Sinal de alerta |
|---|---|---|
| r/s, w/s | Operações por segundo | Contexto; sozinho não diz nada |
| rkB/s, wkB/s | Volume por segundo | Comparar com o esperado do disco |
| r_await, w_await | Latência média, em ms | Acima de 20 ms em SSD é ruim |
| aqu-sz | Fila média | Acima de 2 indica saturação |
| %util | Tempo com pedido pendente | Ver ressalva abaixo |
A coluna %util é a mais mal interpretada. Em disco mecânico, 100% significava
saturação. Em SSD e em armazenamento de rede, que atendem várias operações em
paralelo, %util em 100% apenas informa que sempre havia algo pendente — pode
estar longe do limite.
O par que realmente diz é latência com fila: await alto e aqu-sz alto significa
saturação real. await alto com fila baixa significa que cada operação é lenta
individualmente, o que aponta para o armazenamento em si.
Como referência grosseira, um SSD saudável entrega leitura entre 0,1 e 2 ms. Acima de 10 ms de forma sustentada, há algo errado — na carga ou no disco.
Quem está escrevendo
Confirmado que há pressão, a pergunta seguinte é quem a causa:
sudo apt install iotop
sudo iotop -oPaO -o mostra apenas processos com atividade, -P agrupa por processo em vez de
thread, e -a acumula desde o início da execução — o que revela o consumidor
real, em vez de quem por acaso estava escrevendo naquele instante.
Sem iotop, o kernel também informa:
sudo grep -H . /proc/*/io 2>/dev/null | grep write_bytes | \
sort -t: -k3 -rn | head -10Os culpados costumam ser previsíveis: banco em consulta que ordena em disco, log em modo de depuração, backup ou dump em horário ruim, e reindexação de busca.
Se for banco, vale ir direto às estatísticas dele — o artigo sobre Postgres em VPS mostra como achar a consulta que escreve arquivo temporário, que é a causa mais comum de disco saturado por banco.
Medir a capacidade real
Para saber o que o disco entrega, é preciso testar. O fio é a ferramenta certa,
e exige cuidado: apontado para um dispositivo, ele sobrescreve o conteúdo. Use
sempre um arquivo dentro de um diretório.
sudo apt install fio
cd /var/tmpO teste que mais importa para banco de dados e aplicação web é o de operações pequenas e aleatórias:
fio --name=aleatorio --filename=teste.fio --size=2G \
--rw=randrw --rwmixread=70 --bs=4k \
--ioengine=libaio --iodepth=32 --direct=1 \
--runtime=60 --time_based --group_reportingE o de escrita sequencial, que representa backup e cópia de arquivo grande:
fio --name=sequencial --filename=teste.fio --size=2G \
--rw=write --bs=1M --ioengine=libaio --iodepth=8 \
--direct=1 --runtime=30 --time_based --group_reporting
rm -f teste.fioO --direct=1 ignora o cache do sistema operacional, medindo o disco de fato. Sem
ele, você mede a memória e obtém números irrealisticamente bons.
Na saída, olhe IOPS e a latência clat — especialmente os percentis. Uma média
boa com percentil 99 péssimo indica variação, que é o que a aplicação sente como
travada intermitente.
Rode o teste em horário de baixa e por tempo suficiente. Teste de dez segundos pega apenas o cache; testes curtos são a principal razão de resultados que não se reproduzem.
As causas mais comuns, em ordem
Antes de concluir que o problema é o armazenamento, verifique:
- Falta de índice no banco. Uma consulta varrendo milhões de linhas gera leitura massiva. É a causa número um, com folga.
- Log em modo de depuração. Aplicação registrando cada requisição com corpo completo escreve muito mais do que parece.
- Backup no horário errado. Dump concorrendo com o pico do dia.
- Swap ativo. Se a memória acabou, o disco vira memória e tudo fica lento. O artigo sobre OOM killer e swap mostra como distinguir swap saudável de *thrashing*.
- Disco quase cheio. Sistema de arquivos acima de 90% degrada por fragmentação e por falta de espaço contíguo.
- Sistema de arquivos com opção ruim.
atimeatualiza a data de acesso a cada leitura, gerando escrita desnecessária.
Este último tem correção barata:
# /etc/fstab — acrescente noatime nas opções
UUID=xxxx / ext4 defaults,noatime 0 1sudo mount -o remount /Em servidor com muita leitura de arquivo pequeno, noatime reduz escrita de forma
perceptível e não quebra nada em uso comum.
Reduzir a pressão sem trocar de disco
Antes de aumentar recurso, algumas medidas costumam resolver:
- Mover arquivo grande para bucket. Mídia e dump em Object Storage saem do disco da VM, que é o armazenamento mais caro e mais disputado que você tem.
- Ajustar o log. Nível adequado em produção, e retenção definida como no artigo sobre disco cheio.
- Escalonar as tarefas pesadas. Backup, reindexação e relatório em horários diferentes, não todos às 3h.
- Dar mais memória ao cache. Boa parte da leitura desaparece quando o conjunto
quente cabe na RAM — e
shared_buffersbem dimensionado economiza mais IO que qualquer ajuste de disco.
Quando o problema é mesmo do outro lado
Se depois de tudo isso os números continuarem ruins, aí sim vale abrir chamado. E vale chegar com evidência, o que torna a conversa objetiva:
- A saída do
fiocom os parâmetros usados. iostat -xzdurante o período problemático.- O horário exato e a duração das ocorrências.
- A confirmação de que a carga da máquina estava normal no momento.
Vale conferir também o *steal time* no mesmo período — se a CPU estava sendo disputada, a lentidão pode ter outra origem, como descrito no artigo sobre load average. Descartar essa hipótese antes evita um chamado sobre disco quando o assunto era outro.
Um baseline vale mais que um limiar
A conclusão que se repete em quase todo diagnóstico de disco é que faltava comparação. "Está lento" só significa alguma coisa em relação a um estado anterior conhecido.
Vale rodar o fio uma vez em cada máquina nova, com os mesmos parâmetros, e
guardar o resultado junto da documentação do servidor. Leva cinco minutos e cria
a referência que responde à pergunta certa depois: o disco piorou, ou a carga
aumentou?
Sem esse número, toda investigação começa do zero e termina em suposição. Com ele, a comparação é imediata — e nas duas direções: se o desempenho bruto está igual ao do primeiro dia, o problema é a aplicação, e nenhuma troca de armazenamento vai resolver.
Vale também registrar o await médio em operação normal. É a métrica que muda de
forma mais visível quando algo se degrada, e a que dá o alerta mais cedo.
Escrita que dá para eliminar
Vale fechar com o ângulo mais produtivo: a operação de disco mais rápida é a que não acontece.
Antes de medir capacidade ou pedir armazenamento melhor, três reduções costumam ter efeito imediato e não custam nada além de configuração.
A primeira é o log de acesso do servidor web em conteúdo estático. Cada imagem servida gera uma linha, e um site com trinta recursos por página multiplica isso por visita. Desligar o registro só nos estáticos, como mostrado no artigo sobre nginx, corta um volume expressivo sem perder informação relevante.
A segunda é a sincronização síncrona onde ela não é necessária. Banco de desenvolvimento e cache não precisam garantir gravação em disco a cada operação. Em produção, a decisão é outra — mas vale saber que ela existe e quanto custa.
A terceira é o dado que não deveria estar em disco local. Arquivo enviado por usuário, dump e histórico em bucket saem da disputa por IO da máquina, além de ficarem mais baratos e sobreviverem a ela.
Depois dessas três, o que sobra é carga legítima — e aí a conversa sobre capacidade passa a fazer sentido.