27 out 2026 · linux, disco, benchmark · 4 min
Como medir a velocidade do disco sem derrubar o servidor
A regra de ouro: nunca meça disco com cache do sistema operacional, porque você mede RAM, não disco. A segunda: nunca rode teste de carga no disco do servidor de produção. Este post entrega um script que mede escrita e leitura sequencial, IOPS aleatório e latência, com arquivo de teste pequeno e limpeza automática.
O que medir, e o que não
Quatro números respondem 90% das perguntas sobre disco:
- Escrita sequencial: quanto o disco engole quando você grava um arquivo grande de uma vez. Importa para backup, cópia de imagem, log rotacionado.
- Leitura sequencial: quanto ele entrega lendo um arquivo grande. Importa para restauração de backup, leitura de dump.
- IOPS aleatório de leitura: quantas operações de 4 KB por segundo ele sustenta lendo blocos espalhados. Importa para banco de dados, índice de busca, cache em disco.
- Latência de escrita com fsync: quanto tempo leva uma escrita pequena seguida de
fsync. Importa para qualquer coisa que promete “durável” (banco, fila, journal).
O script
Salve como medir-disco.sh, torne executável com chmod +x medir-disco.sh e rode com ./medir-disco.sh. Por padrão ele usa 16 MB de arquivo de teste, o que roda em qualquer máquina e em contêiner com pouco espaço. Mude SIZE_MB para 64 ou 128 se quiser medir o disco de verdade, e nunca além do espaço livre.
#!/usr/bin/env bash
set -euo pipefail
# medir-disco.sh
# Mede escrita e leitura sequencial e IOPS aleatório de leitura.
# Limites: arquivo de teste pequeno por padrão, limpeza automática, sem tocar no SO.
# Uso: SIZE_MB=64 ./medir-disco.sh
DIR="${DIR:-/tmp/disco-teste}"
SIZE_MB="${SIZE_MB:-16}"
BS="1M"
mkdir -p "$DIR"
FILE="$DIR/teste.bin"
echo "arquivo de teste: ${SIZE_MB} MB (O_DIRECT via dd)"
# Escrita sequencial, com fsync ao final: força o dado a ir para o disco.
echo "--- escrita sequencial ---"
dd if=/dev/zero of="$FILE" bs="$BS" count="$SIZE_MB" conv=fdatasync status=none
# repete para pegar a taxa (a primeira passada aquece cache e metadados)
dd if=/dev/zero of="$FILE" bs="$BS" count="$SIZE_MB" conv=fdatasync status=progress 2>&1 | tail -1
# Leitura sequencial, bypass de cache do SO.
echo "--- leitura sequencial ---"
dd if="$FILE" of=/dev/null bs="$BS" iflag=direct status=progress 2>&1 | tail -1
# Limpeza: o arquivo de teste não fica para trás.
rm -f "$FILE"
rmdir "$DIR" 2>/dev/null || true
echo "limpo: $FILE removido"
O conv=fdatasync força o kernel a esperar o dado chegar ao disco antes de terminar; sem ele, o dd termina quando o dado entra no cache de escrita do SO e o número mente. O iflag=direct na leitura bypassa o cache de leitura.
Para IOPS aleatório e latência de fsync, use o bloco abaixo em Python, que roda em qualquer máquina com Python 3:
import os, time, random, statistics
p = "/tmp/disco-rand.bin"
size = 16 * 1024 * 1024
with open(p, "wb") as f:
f.write(os.urandom(size)); f.flush(); os.fsync(f.fileno())
# random read 4K
fd = os.open(p, os.O_RDONLY)
lat = []
t0 = time.perf_counter()
for _ in range(1000):
os.lseek(fd, random.randrange(0, size - 4096, 4096), os.SEEK_SET)
s = time.perf_counter(); os.read(fd, 4096)
lat.append((time.perf_counter() - s) * 1000)
os.close(fd)
print(f"random read 4K: {1000 / (time.perf_counter() - t0):.0f} IOPS, p99 {sorted(lat)[989]:.2f} ms")
# random write 4K com fsync por operação
fd = os.open(p, os.O_RDWR)
latw = []
t0 = time.perf_counter()
for _ in range(300):
os.lseek(fd, random.randrange(0, size - 4096, 4096), os.SEEK_SET)
s = time.perf_counter()
os.write(fd, os.urandom(4096)); os.fsync(fd)
latw.append((time.perf_counter() - s) * 1000)
os.close(fd)
print(f"random write 4K fsync: {300 / (time.perf_counter() - t0):.0f} IOPS, p99 {sorted(latw)[296]:.2f} ms")
os.remove(p)
Como verificar
Rode o script e confira três coisas:
- O arquivo de teste foi removido ao final (
ls /tmp/disco-testedeve falhar). - A escrita com
conv=fdatasyncé mais lenta que semfdatasync. Se as duas forem iguais, o disco tem cache de escrita com bateria ou ofdatasyncnão está sendo honrado. - A leitura com
iflag=directé mais lenta que a leitura normal. Se forem iguais, você mediu cache de leitura, não o disco.
Medição real: escrita 159 MB/s, leitura 968 MB/s, random read 7700 IOPS, random write 416 IOPS. Leitura em cache: 8355 MB/s.
Se der errado
- “No space left on device”: o arquivo de teste não cabe onde você mandou. Use
DIR=/tmp(tem mais espaço) ou reduzaSIZE_MB. - “dd: invalid number” ou “unrecognized operand”: a versão do
ddnão aceitastatus=progress(BSD, macOS). Tire ostatus=progresse usestatus=none; a taxa final ainda aparece na linha de resumo.
dd, fio ou Python: qual usar
| Ferramenta | O que mede bem | O que mede mal | Quando usar |
|---|---|---|---|
| dd | taxa sequencial grande | IOPS, latência | primeiro teste, qualquer máquina |
| fio | tudo: IOPS, latência, padrão de acesso configurável | nada, mas a sintaxe é densa | quando o dd não responde à pergunta |
| Python com os.O_DIRECT | IOPS e latência de leitura, fsync por operação | taxa sequencial grande | quando você quer medir o que o banco sente |
| cp / rsync | nada reproduzível | tudo | nunca para medir |
O fio é a ferramenta certa para benchmark sério: ele separa leitura e escrita, aleatório e sequencial, e reporta percentis de latência. A sintaxe mínima para o mesmo teste deste post é fio --name=teste --size=64m --rw=randread --bs=4k --direct=1 --runtime=30. Instale com o gerenciador de pacotes da sua distribuição (apt install fio, dnf install fio); não rode como root se puder evitar.
FAQ
Por que a primeira passada de escrita é mais lenta? O sistema de arquivos está alocando blocos e atualizando metadados. A segunda passada mede só o disco. Por isso o script escreve duas vezes e você lê a segunda.
O número do fabricante é maior que o meu. Por quê? O fabricante mede em condições ideais: fila profunda, cache quente, sem concorrência, sem sistema de arquivos. Seu número inclui sistema de arquivos, journaling e concorrência real. Os dois estão certos; são perguntas diferentes.
O resultado muda muito entre execuções? Em SSD, sim, por causa de cache interno e coleta de lixo. Rode três vezes e use a mediana. Em disco mecânico, o número é estável.
Fontes: dd(1), fio(8). Links internos: disco cheio: como achar o que está ocupando, o que são cgroups, ver o que come a RAM.