en
· 4 min de leitura

Postgres basta, até o dia em que não basta, e como saber que dia é esse

A maioria dos times sai do Postgres cedo demais ou tarde demais. Os sinais que dizem qual dos dois são mensuráveis.

infradata

Minha recomendação padrão para quase qualquer produto é uma única instância de Postgres, bem indexada, com uma read replica quando as queries de relatório começarem a doer. Ele aguenta mais do que as pessoas acreditam. Já vi Postgres carregar marketplaces, clínicas, plataformas de logística e dashboards de analytics que numa arquitetura mais na moda seriam três serviços e um stream processor. A escolha entediante está certa muito mais vezes do que é celebrada.

Mas 'Postgres basta' não é religião. Existe um dia em que ele deixa de bastar para uma carga específica, e a habilidade está em reconhecer esse dia pelos números, e não pela ansiedade.

Sinais que não são o dia

Query lenta não é o dia. Query lenta é índice faltando, estatística faltando, ORM gerando padrão N+1 ou tabela que nunca passou por um vacuum decente. A solução é ler o plano da query, que leva uma tarde, não migrar para outro banco, que leva um trimestre.

Tabela grande não é o dia. Postgres lida com tabelas de centenas de milhões de linhas sem reclamar se as queries chegam nelas por índice e as escritas não brigam pela mesma página. Particionar por tempo ou por tenant estende isso ainda mais e continua sendo Postgres.

Crescimento de tráfego não é o dia. Uma instância bem ajustada em hardware modesto serve milhares de transações por segundo. Se você está vendo problema com algumas centenas, a causa é quase sempre gestão de conexões, falta de pooler na frente de um deploy serverless ou contenção de lock numa linha quente, e não o engine.

Sinais que são o dia

O primeiro sinal real é throughput de escrita num único caminho quente ultrapassando o que um primário consegue absorver, depois de pooling de conexão, depois de batching, depois de remover índices desnecessários naquela tabela. Postgres tem um primário. Se a taxa sustentada de escrita numa tabela está chegando ao que o disco e o WAL de uma máquina sustentam, e você já escalou o hardware, essa carga precisa ser dividida ou movida.

O segundo é um padrão de acesso contra o qual o modelo relacional luta. Séries temporais inseridas em alta taxa e consultadas só pela janela recente. Documentos profundamente aninhados que são sempre lidos e escritos inteiros. Travessia de grafo com profundidade variável. Busca full-text com ranking e facetas em escala. Postgres faz cada uma dessas, e existe extensão para a maioria, mas quando uma delas vira a carga dominante, um store especializado vai ser mais barato de operar e mais fácil de raciocinar.

O terceiro é operacional: a instância está grande o suficiente para que um restore demore mais do que o negócio pode ficar fora, ou um upgrade de versão maior exige uma janela de manutenção que ninguém consegue aprovar. Nesse ponto a pergunta não é 'qual banco', mas 'como dividimos o estado para que nenhuma parte seja tão grande'.

Como saber o dia com antecedência

  • Acompanhe transações por segundo e bytes de WAL por segundo no primário, e observe a tendência, não o valor.
  • Acompanhe a proporção entre tempo esperando lock e tempo executando.
  • Acompanhe as cinco queries com maior tempo total por semana, e repare quando a mesma continua ganhando depois de otimizada.
  • Acompanhe quanto demora um restore completo, do último ensaio, contra o tempo de recuperação que o negócio espera.
  • Acompanhe a contagem de conexões contra o limite, especialmente em deploy serverless em que cada instância abre as próprias.

Quando um desses cruzar uma linha que você definiu antes, você tem uma decisão para tomar com dados. Quando nenhum cruzou, a resposta para 'devemos sair do Postgres' é não, e a próxima tarefa é um índice.

O que mover realmente significa

O dia raramente significa substituir o Postgres. Significa tirar uma carga de dentro dele. A tabela de eventos vai para um store de séries temporais ou um log. O índice de busca vai para um motor de busca, alimentado por change data capture. O cache de sessão vai para um key-value store. O dado transacional central, a parte que precisa estar correta, fica exatamente onde estava.

Times que entendem isso movem uma coisa de cada vez, mantêm o núcleo entediante e nunca precisam da grande migração. Times que não entendem ou saem cedo demais, para uma complexidade que não conseguem operar, ou tarde demais, numa crise que ninguém queria. Os números acima são o jeito de evitar os dois.