Planejamento de Capacidade em Profundidade
O planejamento de capacidade para PostgreSQL é fundamentalmente sobre três recursos, CPU, memória e I/O de disco, mais um teto rígido que se comporta de maneira diferente dos três: o limite de conexão.
Esta página constrói o modelo mental que conecta esses recursos aos sintomas que as equipes realmente observam, para que uma decisão de dimensionamento comece a partir de evidências em vez de redimensionar a instância por reflexo.
Resumo
- O planejamento de capacidade mapeia sintomas observados (latência, saturação, erros) de volta a um de um pequeno número de gargalos de recursos subjacentes.
- Por que Importa: Dimensionar o recurso errado, como adicionar CPU para corrigir uma carga de trabalho limitada por I/O, desperdiça orçamento sem corrigir o problema real.
- Conceitos Chave: saturação, taxa de acerto de cache (
cache hit ratio), teto de conexão (connection ceiling), escalonamento vertical (vertical scaling), escalonamento horizontal (horizontal scaling), previsão de crescimento (growth forecasting). - Quando Usar: Dimensionamento inicial da instância, revisões trimestrais de capacidade e qualquer incidente onde a latência aumentou, mas a CPU parece normal.
- Limitações / Trade-offs: Cada estratégia de dimensionamento (instância maior, réplicas de leitura, particionamento, sharding) troca custo ou complexidade por margem, e nenhuma delas corrige um plano de consulta ruim.
- Tópicos Relacionados: pool de conexões (
connection pooling), otimização de desempenho de consultas (query performance tuning), monitoramento e alertas (monitoring and alerting), dimensionamento de plataforma gerenciada (managed platform sizing).
Fundamentos
A capacidade de CPU governa quanta execução de consulta, ordenação e trabalho de autovacuum o cluster pode realizar simultaneamente.
A capacidade de Memória governa a eficácia do cache através de shared_buffers e do cache de página do sistema operacional, determinando com que frequência uma leitura é atendida pela RAM em vez do disco.
A capacidade de I/O de Disco governa a rapidez com que a camada de armazenamento pode atender leituras que não estão no cache e absorver o fluxo contínuo de escritas WAL que cada transação gera.
O teto de conexão (connection ceiling), definido por max_connections, se comporta de maneira diferente dos outros três, pois é um corte rígido em vez de uma degradação gradual, e uma vez atingido, novas sessões são rejeitadas imediatamente em vez de apenas serem desaceleradas.
Um modelo mental útil é uma cozinha de restaurante: CPU é o número de cozinheiros que podem trabalhar ao mesmo tempo, memória é o espaço no balcão que evita viagens repetidas à geladeira, I/O de disco é a rapidez com que essa geladeira pode ser acessada, e o teto de conexão é o número fixo de comandas que a impressora da cozinha pode fisicamente comportar.
Adicionar cozinheiros não ajuda se a geladeira for o gargalo, e uma geladeira maior não ajuda se a impressora estiver travada, que é exatamente por que o planejamento de capacidade começa identificando qual recurso está realmente restrito.
O PostgreSQL expõe as evidências para esse diagnóstico diretamente através de pg_settings, pg_stat_activity e ferramentas de nível de host como iostat, então os dados necessários para distinguir uma carga de trabalho limitada por CPU de uma limitada por I/O já estão disponíveis em todos os clusters.
Decisões de dimensionamento feitas sem essas evidências tendem a se basear no hábito, redimensionando para uma classe de instância familiar em vez do que o perfil de recurso real da carga de trabalho exige.
Mecânicas e Interações
Os quatro recursos interagem através de uma cadeia que começa com uma consulta e termina com a conclusão rápida ou latência visível para o usuário.
Uma consulta primeiro compete por CPU para planejar e executar, depois por memória (work_mem) se precisar ordenar ou fazer hash, e finalmente por I/O de disco se os dados de que precisa não estiverem residentes em shared_buffers ou no cache do SO.
effective_cache_size não aloca memória por si só; ele informa ao planejador de consultas aproximadamente quanta cache está disponível em todo o sistema, o que molda a escolha do plano, como favorecer um index scan em vez de um sequential scan quando o planejador espera que as páginas relevantes já estejam em cache.
Sob carga de escrita sustentada, I/O de disco e CPU interagem através do autovacuum, pois uma tabela que gera tuplas mortas mais rápido do que o autovacuum pode recuperá-las causa tanto inchaço de índices (mais I/O por varredura) quanto mais CPU gasta avaliando linhas que eventualmente serão descartadas.
-- Um mecanismo concretizado: este sinal distingue
-- "consultas estão em execução" de "consultas estão em fila", o que
-- é a primeira bifurcação em qualquer diagnóstico de capacidade.
SELECT count(*) FILTER (WHERE state = 'active') AS active,
count(*) FILTER (WHERE wait_event_type = 'Lock') AS blocked,
count(*) AS total
FROM pg_stat_activity
WHERE backend_type = 'client backend';As conexões interagem com todos os três recursos indiretamente, mas significativamente, pois cada backend aberto consome memória mesmo quando ocioso, e uma tempestade de conexões de uma aplicação com pool insuficiente pode esgotar max_connections muito antes que a CPU ou o disco mostrem qualquer tensão real.
Um erro comum de raciocínio é dimensionar a CPU ou o tamanho da instância primeiro, quando o gargalo real é frequentemente um índice ausente ou uma contagem de conexão ilimitada, ambos que uma instância maior não corrigirá e apenas tornará mais caro continuar ignorando.
Considerações Avançadas e Aplicações
Em escala, o planejamento de capacidade muda de combate reativo a incêndios para uma disciplina de previsão que antecipa o esgotamento de recursos antes que se torne um incidente.
O crescimento do armazenamento é o recurso que a maioria das equipes subestima, pois o crescimento de tabelas e índices se compõe com cargas de trabalho de séries temporais ou logs de eventos de uma forma que um único snapshot pontual não revela, tornando a projeção baseada em tendências mais útil do que um alerta estático de "porcentagem livre".
A escolha entre escalonamento vertical, réplicas de leitura e estratégias horizontais como particionamento ou sharding depende de qual recurso está realmente restrito: uma carga de trabalho de escritor único limitada por CPU ou memória se beneficia do escalonamento vertical, uma carga de relatório com muitas leituras se beneficia de réplicas, e uma única tabela muito grande para ser desfragmentada ou indexada eficientemente se beneficia do particionamento, independentemente do tamanho da instância.
O sharding especificamente deve ser tratado como último recurso nesta hierarquia, pois introduz complexidade de consulta entre shards e sobrecarga operacional que o particionamento ou as réplicas de leitura geralmente evitam, enquanto resolvem a mesma pressão subjacente.
O pool de conexões interage com o planejamento de capacidade em um nível arquitetônico, pois um pooler como o PgBouncer muda o recurso real que está sendo dimensionado de "conexões por instância de aplicação" para "conexões por pool", o que é o que torna os tiers de aplicação escalados horizontalmente (muitos pods, muitas invocações serverless) compatíveis com um teto fixo de max_connections.
Revisões de capacidade realizadas em cadência trimestral, correlacionando crescimento de tabelas, picos de conexão e custo das principais consultas, detectam a lenta deriva em direção a um teto de recursos muito antes que se torne um alerta às 3 da manhã.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Escalonamento vertical (instância maior) | Simples, sem alterações na aplicação | O custo cresce mais rápido que linearmente no topo, tem um teto | Cargas de trabalho de escritor único limitadas por CPU ou memória |
| Réplicas de leitura | Descarrega tráfego de leitura, melhora a latência de leitura | Atraso de replicação (replication lag), não ajuda na taxa de transferência de escrita | Carga de relatórios ou análise com muitas leituras |
| Particionamento | Limita o custo de manutenção de vacuum e índice por partição | A complexidade de consulta e migração aumenta | Tabelas únicas muito grandes com uma chave natural (tempo, tenant) |
| Sharding | Distribui carga de leitura e escrita horizontalmente | Consultas entre shards, sobrecarga operacional significativa | Taxa de transferência de escrita que excede qualquer primário único, último recurso |
Equívocos Comuns
- "Alta latência sempre significa que a instância precisa de mais CPU." - Cargas de trabalho PostgreSQL são frequentemente limitadas por I/O ou bloqueios (
lock-bound), então a CPU pode parecer saudável enquanto as consultas ficam em fila atrás de esperas de disco ou transações bloqueantes. - "
max_connectionsdeve ser definido alto 'para crescimento'." - cada conexão aberta consome memória, esteja ociosa ou ativa, então um teto alto sem pooling arrisca esgotamento de memória, não margem. - "
shared_buffersmaior sempre significa melhor taxa de acerto de cache." - os retornos diminuem bem antes de 100% da RAM, e o cache de página do SO faz um trabalho significativo queshared_bufferssuperdimensionado pode ofuscar. - "Réplicas de leitura resolvem gargalos de escrita." - réplicas descarregam apenas o tráfego de leitura; um primário limitado por escrita precisa de uma estratégia diferente, como particionamento ou, eventualmente, sharding.
- "Sharding é a resposta padrão para ficar sem capacidade." - geralmente é a opção mais cara operacionalmente e deve ser reservada para taxa de transferência de escrita que escalonamento vertical e particionamento genuinamente não conseguem resolver.
- "Planejamento de capacidade é um exercício de dimensionamento único." - a carga de trabalho e o volume de dados mudam continuamente, então o dimensionamento decidido no lançamento rotineiramente se torna incorreto dentro de um ano sem uma cadência de revisão.
FAQs
Quais são os recursos principais envolvidos no planejamento de capacidade do PostgreSQL?
CPU para execução de consultas, memória para cache, I/O de disco para leituras e escritas WAL, e o teto de conexão como um limite rígido distinto.
Por que a latência pode aumentar mesmo quando a utilização da CPU parece baixa?
O PostgreSQL é frequentemente limitado por I/O de disco ou contenção de bloqueio, ambos os quais podem saturar independentemente da CPU.
O que `effective_cache_size` realmente controla?
Ele não aloca memória por si só; ele informa a estimativa do planejador de consultas de cache disponível, o que influencia a escolha do plano, como indexação versus varreduras sequenciais.
Por que o teto de conexão é tratado de forma diferente da CPU, memória e disco?
É um corte rígido em vez de uma degradação gradual, rejeitando novas sessões imediatamente quando max_connections é atingido, em vez de apenas desacelerá-las.
Como o `autovacuum` se conecta à capacidade de CPU e I/O de disco?
Uma tabela que acumula tuplas mortas mais rápido do que o autovacuum pode recuperá-las causa índices inchados que custam mais I/O por varredura e mais CPU avaliando linhas descartáveis.
Quando o escalonamento vertical faz sentido em vez de uma réplica de leitura?
O escalonamento vertical se encaixa em cargas de trabalho de escritor único limitadas por CPU ou memória, enquanto uma réplica de leitura se encaixa em tráfego de relatórios com muitas leituras que não afeta o gargalo de escrita.
Por que o sharding é considerado um último recurso em vez de um caminho de dimensionamento padrão?
Ele introduz complexidade de consulta entre shards e sobrecarga operacional que particionamento ou réplicas de leitura geralmente evitam, enquanto aborda a mesma pressão subjacente.
Como o pool de conexões muda o cenário de capacidade?
Ele muda o recurso que está sendo dimensionado de conexões por instância de aplicação para conexões por pool, permitindo que um tier de aplicação escalado horizontalmente permaneça sob um teto fixo de max_connections.
Por que o crescimento do armazenamento é comumente subestimado?
Um único snapshot pontual não revela o crescimento composto de cargas de trabalho de séries temporais ou logs de eventos, então a projeção baseada em tendências captura o que uma verificação estática de espaço livre perde.
O planejamento de capacidade é algo que se faz uma vez no lançamento?
Não, a carga de trabalho e o volume de dados mudam continuamente, então uma cadência de revisão trimestral é necessária para capturar a deriva antes que ela se torne um incidente.
Uma instância maior sempre corrige uma consulta lenta?
Raramente; um índice ausente ou um plano de consulta ruim geralmente dominam o tamanho bruto da instância, e dimensionar o hardware primeiro muitas vezes apenas torna a mesma ineficiência mais cara.
Que evidências devem preceder uma decisão de dimensionamento?
Eventos de espera do pg_stat_activity, taxa de acerto de cache, métricas de I/O de nível de host e saturação de conexão, para que a decisão vise o recurso que está realmente restrito.
Relacionados
- Noções Básicas de Capacidade - o ponto de partida em nível de receita para o modelo de recursos descrito aqui.
- Matemática de Conexões - as mecânicas de pooling referenciadas na discussão do teto de conexão desta página.
- Escalar para Cima vs Escalar para Fora - uma comparação mais aprofundada das estratégias de dimensionamento na tabela acima.
- Previsão de Crescimento de Armazenamento - a disciplina de previsão descrita em Considerações Avançadas.
- Sharding: Último Recurso - por que o sharding fica no final da hierarquia de dimensionamento.
- Pontos Chave de Monitoramento e Métricas - os sinais usados para diagnosticar qual recurso está restrito.
Versões da Stack: Esta página foi escrita para PostgreSQL 18.4 (major 18 estável, linha de manutenção 17) e PgBouncer 1.x.