Saiph TI

O banco de dados trava. A query está certa. Quem não aguenta é o disco.

CPU ociosa, query certa, banco travado: o gargalo é o disco. O que medir e quando um servidor dedicado para banco de dados resolve.

Saiph TI #Infraestrutura#Cloud#Storage

O padrão é este: o sistema trava no horário de pico, a CPU está ociosa, a memória não estourou e o EXPLAIN da query que todo mundo culpa volta limpo. Index seek, custo baixo, sem sequential scan. Alguém reescreve a consulta. Alguém sobe o shared_buffers. Alguém aponta o dedo para a aplicação. No dia seguinte o banco trava de novo.

Quem não está aguentando é o disco. Um servidor dedicado para banco de dados entra nessa conversa aqui: não porque “dedicado é mais rápido” como slogan, mas porque o recurso que a query está esperando (operações por segundo, vazão e, principalmente, latência previsível) some quando o armazenamento é compartilhado, fatiado ou cobrado como linha extra da fatura.

Como saber que o banco está esperando o disco

No PostgreSQL, a prova mora em pg_stat_activity. Se o processo está active e o wait_event_type é IO, a query está rodando e parada num I/O. A documentação do PostgreSQL 18 descreve esse tipo de espera exatamente assim: o backend aguarda uma operação de I/O terminar. Em carga transacional, os nomes que mais aparecem são literais:

  • DataFileRead / DataFileWrite: espera no arquivo da tabela ou do índice.
  • WalWrite: espera de escrita no WAL.
  • WalSync: espera o WAL chegar em armazenamento durável.

Esse último é o que dói no commit. O próprio PostgreSQL explica que uma transação só está comprometida depois que o registro de WAL foi descarregado em disco permanente. A query pode ser perfeita. O fsync do commit ainda paga a latência do disco, inteira, em cada transação.

No MySQL e no MariaDB o equivalente vive no Performance Schema (wait/io/file/...). No SQL Server, em PAGEIOLATCH_*. O motor muda. O sinal não: sessão ativa, CPU longe de 100%, tempo em espera de I/O.

No sistema operacional, iostat (await) e %iowait no mpstat fecham o quadro. CPU ociosa com iowait alto não é servidor folgado. É servidor esperando o disco. Se você já opera monitoramento 24x7, esse sinal deveria estar no painel antes de o usuário reclamar.

A query está certa. O plano também. E mesmo assim trava

O plano diz qual caminho a query vai seguir. Não diz quanto tempo cada página leva para chegar.

Uma consulta que lê 2 mil páginas por índice, cada uma em 0,1 ms de cache, termina em fração de segundo. A mesma consulta, com as mesmas 2 mil páginas vindo do disco a 5 ms cada, passa de dez segundos. O EXPLAIN não muda. O usuário muda de humor.

Três mecanismos produzem exatamente esse quadro com query “certa”:

  1. O conjunto quente não cabe na memória. Cada cache miss vira leitura de disco. O PostgreSQL ainda avisa que pg_stat_io e as views pg_statio_* não separam o que veio do disco do que já estava no page cache do kernel. Hit ratio alto no banco não prova que o disco está folgado.
  2. Muitas transações pequenas. Cada commit sincroniza WAL. Cem commits por segundo são cem fsync. O plano de cada INSERT é trivial. A fila no disco não é.
  3. Checkpoint e vacuum no pior horário. Nenhum dos dois aparece no EXPLAIN da query do usuário, e os dois competem pelo mesmo disco.

Reescrever a query continua sendo o primeiro passo certo. Só não é o último quando o plano já está limpo e o wait event continua IO.

Três números do disco, e por que latência manda

Quando o diagnóstico aponta para o disco, três grandezas descrevem o que ele consegue entregar. Nenhuma delas é o título do problema. Todas são a prova.

  • IOPS (operações de I/O por segundo): quantas idas ao disco cabem num segundo. OLTP faz muita operação pequena e aleatória (8 KiB, 16 KiB, espalhada). É o número que satura primeiro nesse perfil.
  • Vazão (MiB/s): quantos bytes passam. Relatório, dump, vacuum pesado, carga analítica.
  • Latência: quanto tempo uma operação demora para voltar. É o que o usuário sente. Uma query de 50 leituras a 5 ms cada já saiu de “instantânea”.

Disco mecânico e SSD não falham no mesmo número. Num HDD a 7.200 rpm o prato dá uma volta a cada 8,3 ms; a espera média só de rotação já é da ordem de 4 ms, antes de contar o seek. SSD e NVMe saem dessa escala. A diferença prática para o banco: o commit que espera o WalSync num disco lento empilha. No disco rápido, a mesma fila anda.

A AWS documenta o outro lado, o do volume de nuvem. Um volume gp3 entrega 3.000 IOPS e 125 MiB/s na linha de base, inclusos no preço do armazenamento, com latência de milissegundo de um dígito. IOPS extra vai até 80.000, vazão extra até 2.000 MiB/s, os dois cobrados à parte. Quem precisa de latência menor migra para io2 Block Express, desenhado para média abaixo de 500 microssegundos em I/O de 16 KiB.

Nenhuma dessas linhas é “nuvem é lenta”. IOPS é linha de fatura, não propriedade do disco que você comprou. A própria AWS registra que dirigir mais IOPS do que o volume tem aumenta a latência, e que aplicação transacional é sensível exatamente a isso. E mesmo o io2 continua sendo volume de rede: o fsync do commit atravessa o caminho até o storage. Disco local no servidor, NVMe no barramento da máquina, não atravessa.

Por que o VPS (e o volume de nuvem) esconde o teto

O VPS bem feito reserva CPU e RAM. Na oferta da Saiph isso é explícito: sem overselling, vCPU e memória contratadas ficam alocadas. O que a ficha técnica não reserva, nem aqui nem na maior parte do mercado, é o caminho de I/O do disco: o controlador, a fila do hypervisor, o teto de IOPS do volume.

Para aplicação web de tráfego moderado, isso quase não aparece. O post sobre servidor dedicado ou VPS já marca o extremo certo: a diferença real mostra na latência de disco previsível e na ausência de vizinhança, que é exatamente o perfil de banco transacional sob pico.

O volume de nuvem adiciona uma segunda camada: o teto é provisionado, cobrado e remoto. Você pode pagar os 80.000 IOPS do gp3 e cada commit ainda espera milissegundos de um dígito, porque essa é a latência do produto. A linha extra entra na fatura em dólar, com o mesmo mecanismo de câmbio que o artigo sobre quanto custa a nuvem em reais destrincha para compute e egress.

Isso não é argumento para tirar tudo da nuvem. Carga elástica, ambiente que nasce e morre, leitura que cabe em cache: VPS continua a escolha certa. O caso que quebra é o banco com plano certo, RAM certa, CPU ociosa, esperando o disco no pico.

Memória decide quanto o disco trabalha

Disco rápido com working set no disco continua lento. Disco razoável com working set na RAM parece instantâneo. Por isso “coloquei NVMe” sem olhar memória é meio diagnóstico.

Some o tamanho das tabelas e índices quentes (não o banco inteiro: o que a aplicação toca no pico). Compare com a RAM disponível para o banco (shared_buffers no PostgreSQL, innodb_buffer_pool_size no MySQL) mais o page cache que o sistema ainda tem folga para usar. Se o quente não cabe, cada miss é I/O. Nenhum RAID resolve isso.

Dois corolários: RAM demais não substitui disco previsível, porque WAL e checkpoint escrevem mesmo com 100% de hit em leitura. Disco rápido não substitui RAM: se o conjunto quente é 80 GB e a máquina tem 32 GB, o NVMe só torna o miss menos doloroso. Dimensionar servidor dedicado para banco é dimensionar os dois juntos.

WAL, checkpoint e RAID: o disco faz mais I/O do que a query

A query do usuário é só uma das bocas que comem disco. As outras, se ignoradas, sabotam o upgrade.

WAL. Cada commit precisa chegar a armazenamento durável. Separar WAL em disco próprio tira a escrita sequencial de log da fila das leituras aleatórias de tabela. Em dedicado isso é dois grupos de disco. Em volume único de VPS, as duas cargas brigam na mesma fila.

Checkpoint. O checkpointer despeja páginas sujas para o WAL poder ser reciclado. Intervalo curto demais: tempestade periódica. Intervalo longo demais: tempestade maior, e recuperação depois de um crash alonga. Não existe valor mágico publicável para todo banco. Existe medir pg_stat_checkpointer (PostgreSQL) ou o equivalente InnoDB e ajustar com o disco que você realmente tem.

RAID. Espelhamento (RAID 1 ou 10) duplica cada escrita. RAID 5 e 6 pagam mais caro: cada escrita lógica vira duas leituras (dado antigo e paridade antiga) e duas escritas. Para OLTP, RAID 10 continua o desenho que menos surpreende.

Backup na mesma controladora é o quarto sabotador. A janela de backup vira o horário em que o banco “inexplicavelmente” trava. Destino de backup é outro disco, outro storage, outro servidor.

O que muda num servidor dedicado para banco de dados

No servidor dedicado da Saiph o hardware é inteiro seu: processador Intel Xeon ou AMD EPYC físico, RAM ECC, discos HDD, SSD ou NVMe em RAID conforme a carga, KVM over IP, nos datacenters próprios de Belo Horizonte e Recife. Quem provisiona, monitora e atende é a mesma equipe que opera o datacenter. Servidores em estoque entram em produção em até 48h úteis, com SLA de 99,9% de uptime da infraestrutura em contrato e suporte 24x7 em português.

Para o banco, o que isso muda: o IOPS do disco é seu (sem vizinho no mesmo SSD, sem linha extra na fatura, sem hypervisor no meio do fsync); o layout é o da carga (WAL num grupo, dados noutro, backup fora; NVMe onde o commit importa, HDD só no que é frio); a latência é a do barramento, não a da rede de storage.

Se o hardware já é seu e o que falta é o ambiente, o caminho é colocation, não outra máquina alugada. O artigo sobre quando colocation vale cobre essa fronteira.

O dedicado não é a resposta para todo banco. Homologação, cache pequeno, leitura que cabe em 16 GB: VPS resolve e provisiona mais rápido. O caso que justifica a máquina inteira é o deste texto: query certa, CPU ociosa, disco na fila.

Perguntas frequentes

Como eu confirmo que o gargalo é disco, e não lock ou CPU?

No PostgreSQL, wait_event_type = 'IO' com state = 'active' é o sinal direto. Lock e LWLock são outra conversa (alguém segurando transação). CPU em 90%+ com iowait baixo também é outra conversa (falta de índice, sort enorme, função cara). Os três se separam em cinco minutos de pg_stat_activity mais iostat. Se o wait é IO e o await do disco sobe no mesmo instante em que a aplicação reclama, você não precisa de mais hipótese.

Colocar NVMe num VPS não resolve?

Resolve parte, se o hypervisor realmente entrega esse NVMe para a sua VM e se o teto de IOPS não é compartilhado. Na prática, o que a maioria dos planos chama de “NVMe” é um pedaço de um array, com fila comum. Você ganha latência melhor que HDD e continua sem garantia de que o pico das 11h é só seu. NVMe de verdade, para banco, é o disco na máquina, sem vizinho no mesmo dispositivo.

Meu banco é SQL Server ou Oracle. O diagnóstico muda?

O motor muda, o disco não. SQL Server mostra PAGEIOLATCH_* para leitura de página e WRITELOG para o log. Oracle mostra db file sequential read e log file sync. A pergunta é a mesma: a sessão está esperando I/O, ou está esperando CPU, lock ou a aplicação? Se for I/O, o resto deste texto se aplica.

Preciso de RAID 10, ou um NVMe só basta?

Um NVMe único é rápido e é um ponto único de falha. Disco de banco sem redundância transforma um SSD queimado em restore. RAID 1 ou 10 em NVMe (ou em SSD) entrega a latência e sobrevive à perda de um membro. RAID 5 em OLTP continua o atalho que reaparece como latência. Para produção que o comercial sente, o segundo disco ganha.


Se o seu banco já passou pelo EXPLAIN e continua esperando o disco, a conversa deixou de ser de query e passou a ser de máquina. Solicite uma cotação com o perfil da carga (tamanho do conjunto quente, transações por segundo no pico, se o WAL já está separado) e dimensionamos um servidor dedicado em Belo Horizonte ou Recife, ou o colocation se o hardware já é seu.

Vamos desenhar a sua infraestrutura?

Conte o que você precisa e nossa equipe técnica retorna com uma proposta sob medida.

  • Resposta em até 1 dia útil
  • Atendimento direto com a equipe técnica
  • WhatsApp, sem fila de robôs

* campos obrigatórios. Seus dados são usados apenas para o atendimento (LGPD).