Este artigo compara a arquitetura dos três poolers: linguagem, modos de pooling, modelo de locatário único ou multilocatário, funções além do pooling puro. Tembo e PkgPulse publicaram comparações numéricas dessas três ferramentas, mas nós mesmos não reproduzimos nenhuma de suas medições. Nossa posição editorial sobre benchmarks, detalhada em nossa metodologia de benchmark , é nunca republicar um número que não tenhamos verificado. Em vez disso, o que você encontrará aqui: a arquitetura real de cada ferramenta e como o Aurabase realmente roteia seu tráfego Postgres, verificado seção por seção no código-fonte.
- PgBouncer (C) continua sendo o pooler mais comprovado e melhor integrado ao Kubernetes: CloudNativePG depende diretamente dele para seu recurso
Pooler. - Supavisor (projeto Elixir, Supabase) tem como alvo um problema diferente: atender milhares de bancos de dados do mesmo serviço, em vez de um pooler por banco de dados.
- PgCat (Rust) adiciona fragmentação de aplicativos, balanceamento de carga entre réplicas e failover automático para pooling bruto.
- O repositório Aurabase mostra o PgBouncer usado em dois níveis: uma implantação compartilhada para a frota compartilhada e um recurso
Poolergerenciado pelo CloudNativePG por locatário dedicado. Ambos operam em modo de transação. - O PostgREST e o pool de administração
aura-dbpermanecem voluntariamente em conexão direta com o Postgres, sem passar pelo pooler: o pool de transações interromperia o recarregamento do esquema e os bloqueios de sessão.
Três poolers, três filosofias
O PgBouncer minimiza, os pools do Supavisor em escala multilocatário, o PgCat adiciona funções de rede ao pool bruto. Nenhum dos três substitui diretamente os outros dois, embora sejam frequentemente comparados termo por termo nas mesmas páginas.
| Idioma | C | Elixir (FEIXE) | Ferrugem |
|---|---|---|---|
| Modos de agrupamento | Sessão, transação, declaração | Sessão, transação | Sessão, transação, declaração |
| Modelo de locação | Um cluster de destino por instância, projetado para ser de locatário único | Multilocatário nativo: um serviço para muitos bancos de dados | Um cluster de destino, fragmentado por chave de partição |
| Além do pool | Sem funções adicionais, deliberadamente mínimas | API Admin HTTP, registro dinâmico de locatário | Fragmentação, balanceamento de carga e failover entre réplicas |
| Integração nativa do Kubernetes | Sim: pool de recursos CloudNativePG | Não documentado nativamente até o momento | Não documentado nativamente até o momento |
| Origem | O padrão histórico de pooling do Postgres | Construído pela Supabase para sua própria nuvem multilocatária | Nascido na Instacart, mantido hoje pelo PostgresML |
Colunas, em ordem: PgBouncer, Supavisor, PgCat. Características da arquitetura de acordo com os registros oficiais de cada projeto, a serem confirmados na versão que você está implantando, o ecossistema evoluindo rapidamente neste ponto.
O padrão histórico, leve e integrado ao Kubernetes
O PgBouncer faz apenas uma coisa: agrupar conexões Postgres, sem quaisquer funções adicionais. Este escopo deliberadamente estreito explica em grande parte sua longevidade e sua adoção como um elemento básico na maioria das pilhas do Postgres em produção.
Três modos de pooling estão disponíveis. O modo de sessão abre uma conexão de servidor por conexão de cliente, o mais permissivo. O modo transação reutiliza uma conexão de servidor entre vários clientes, liberada a cada final de uma transação. O modo de instrução vai ainda mais longe e raramente é usado na produção. É o modo de transação que traz o ganho real de pooling, mas impõe regras rígidas. Qualquer estado de sessão (variáveis SET, bloqueios de aconselhamento, LISTEN/NOTIFY) não sobrevive além de uma transação. Detalhamos essas regras e suas armadilhas em nosso artigo dedicado sobre o modo de pool de transações do PgBouncer.
Historicamente de processo único, uma instância PgBouncer usa um único núcleo de CPU por padrão. A execução de várias instâncias na mesma porta (via SO_REUSEPORT) é uma evolução mais recente do projeto, não um recurso de design inicial. No lado da autenticação, o PgBouncer suporta um auth_queryconfigurável, uma função SQL executada em cada conexão para resolver dinamicamente a senha de uma função. Este mecanismo evita depender de um arquivo estático listando previamente cada usuário. É exatamente esse mecanismo que o Aurabase utiliza para suas funções por projeto (seção 05).
PgBouncer é o pooler que CloudNativePG implanta nativamente por trás de seu recurso Pooler. Em um cluster Postgres gerenciado pelo operador CloudNativePG, ativar um pooler gerenciado equivale, na prática, a ativar o PgBouncer sem configurá-lo manualmente.
Pooler multilocatário nativo da nuvem da Supabase
Supavisor aborda um problema que o PgBouncer nunca foi projetado para resolver nesta escala. Isto envolve servir um grande número de bases de dados de inquilinos distintas a partir de um único serviço, em vez de uma instância de pooler por base de dados. Escrito em Elixir e executado na máquina virtual Erlang (BEAM), o projeto é desenvolvido e mantido pela Supabase, em código aberto, em seu próprio repositório GitHub.
O modelo nativo multilocatário é a verdadeira diferença estrutural. Onde uma frota PgBouncer clássica requer um processo (ou um conjunto de conexões dedicadas) por base alvo, o Supavisor funciona de forma diferente. Ele registra locatários dinamicamente por meio de uma interface de administração HTTP e roteia cada conexão de entrada para o banco de dados correto sem reiniciar o serviço. A Supabase migrou seus próprios projetos de nuvem do PgBouncer para o Supavisor exatamente por esse motivo. Um cluster de pooling clássico, um por banco de dados, não pode ser dimensionado para uma nuvem multilocatário que hospeda centenas de milhares de projetos.
Esta escolha arquitetônica tem uma desvantagem documentada. A paridade de recursos com o PgBouncer em casos avançados levou algum tempo para se estabilizar após o lançamento do projeto. Dois exemplos: certos comportamentos de LISTEN/NOTIFYe o gerenciamento preciso de instruções preparadas em modo de transação. Verifique sua versão antes da migração se seu aplicativo depender desses comportamentos específicos.
O estranho Rust: fragmentação nativa e balanceamento de carga
O PgCat está explicitamente posicionado como uma alternativa ao PgBouncer, escrito em Rust. Ele adiciona funções de rede ao pooling clássico que nem o PgBouncer nem o Supavisor incorporam nativamente. Três em particular: fragmentação de aplicativos por chave de partição, balanceamento de carga entre réplicas de leitura e failover automático de uma réplica com falha. O projeto nasceu na Instacart antes de ser assumido e mantido hoje pelo PostgresML.
Concretamente, o PgCat pode desempenhar o papel que duas camadas distintas normalmente ocupariam: um pooler de conexões e um proxy de aplicação para roteamento entre várias instâncias do Postgres. Uma equipe que já fragmenta seus dados manualmente pode simplificar seu código com o PgCat. O mesmo vale para uma lógica de distribuição de leituras entre réplicas desenvolvida internamente: uma camada de rede dedicada a substitui diretamente.
O compromisso oposto também existe: o PgCat é um projeto mais jovem, com um ecossistema de documentação e feedback de produção muito menor do que o PgBouncer. Adotar as suas funções de fragmentação e failover também significa concordar em depender da maturidade deste componente específico, e não apenas da sua capacidade de agrupamento.
O que o código Aurabase mostra: PgBouncer em todos os lugares, exceto onde o pool de transações quebra tudo
O repositório Aurabase implanta o PgBouncer em duas camadas separadas, ambas em modo de transação. Para a frota compartilhada, o gráfico Helm define uma implantação PgBouncer dedicada na frente do plano de dados compartilhado (deploy/helm/aurabase/templates/infra/pgbouncer.yaml, imagem edoburu/pgbouncer). Para um locatário em uma instância dedicada, o provisionador gera um recurso Pooler gerenciado nativamente por CloudNativePG (deploy/cnpg/tenant-pooler.yaml, renderizado por k8s_tenant.rs). Nenhum deles usa Supavisor ou PgCat. O código não documenta uma comparação explícita que precedeu esta escolha. Por outro lado, mostra uma integração profunda e já operacional com o ecossistema CloudNativePG, consistente com o facto de o PgBouncer ser o bloco de pooling nativo.
No entanto, nem tudo passa pelo pooler, e esta é uma escolha deliberada documentada no próprio código. O PostgREST permanece conectado ao vivo ao Postgres, nunca via PgBouncer. O comentário do gráfico Helm é explícito sobre o motivo: o pool de transações interromperia o recarregamento do esquema, que depende de um LISTEN no canal pgrst. Este mecanismo é incompatível com conexões de servidor recicladas entre clientes. O conjunto de administraçãoaura-db (esquema, DDL, bloqueios de aconselhamento de sessão) também permanece em conexão direta, pelo mesmo motivo básico. SET search_path sem escopo de transação e bloqueios de sessão não sobrevivem a um pooler de modo de transação.
A autenticação segue o padrão auth_query descrito na seção 02: AUTH_QUERY: SELECT * FROM pgbouncer.user_lookup($1), sem um arquivo userlist.txt estático. Isso é o que permite que funções criadas dinamicamente por projeto (project_<uuid>_authenticator) sejam autenticadas via PgBouncer sem reimplantar o pooler para cada novo projeto.
O comentário de verificação de integridade do PgBouncer nos manifestos locais do Kubernetes documenta um bug real, já corrigido. Uma execução pg_isready no PgBouncer valida apenas o handshake do proxy, nunca a conexão real com o back-end do Postgres que ele retransmite. O PgBouncer responde “aceitando conexões” mesmo quando o backend está parado, enfileirando as solicitações. Resultado observado durante um teste destrutivo: o serviço permaneceu healthy por 5 ciclos consecutivos enquanto o Postgres estava inacessível. A correção substitui a verificação por uma solicitação psql verdadeira de ponta a ponta por meio do pooler, até o back-end. Resultado após correção, no mesmo teste reproduzido: unhealthy detectado em 7 ciclos, aproximadamente 35 segundos.
Um último detalhe, menor, mas revelador: o gráfico do Helm fixa edoburu/pgbouncer:v1.24.1-p1 por padrão, enquanto o banco k3d local usa v1.25.2-p0. Não é uma escolha arquitetônica, apenas uma pequena falta de sincronização de versão entre dois ambientes, o tipo de detalhe que uma revisão de código captura mais rápido do que uma postagem de blog. Nós documentamos como é, em vez de enfeitá-lo. Para obter detalhes sobre o particionamento de esquema que esse pooler atende, consulte nosso artigo sobreisolamento RLS multilocatário.
Como escolher entre os três
Escolha PgBouncer se…
- Cluster Postgres gerenciado por CloudNativePG ou Kubernetes em geral
- Você quer o pooler mais comprovado e bem documentado
- Uma base de destino por instância do pooler combina com você
Escolha Supavisor se…
- Centenas ou milhares de bases por trás do mesmo serviço
- Necessidade de registrar locatários dinamicamente por meio de uma API, sem reimplantação
- Já está no ecossistema Supabase ou deseja depender dele
Escolha PgCat se…
- Compartilhamento de aplicativos já implementado ou planejado no nível do pooler
- Balanceamento de carga e réplica de failover sem camada de aplicação separada
- Confortável com um projeto mais jovem, menos documentado que o PgBouncer
Qualquer que seja o pooler escolhido, ele não substitui o dimensionamento do próprio Postgres. O tamanho do pool e o servidor max_connections devem ser considerados juntos, não um após o outro. Um pool generoso na frente de um max_connections muito baixo simplesmente muda a saturação de um nível para outro. Nosso guia sobre ajuste max_connections detalha a fórmula de dimensionamento a ser aplicada antes de definir o tamanho do seu pool.
O que nos perguntam com mais frequência
Não existe um pooler universal, apenas um bom ajuste para o seu arrendamento
PgBouncer, Supavisor e PgCat resolvem três variações do mesmo problema, não três versões da mesma ferramenta. PgBouncer continua sendo a escolha mais segura quando sua plataforma já depende de Kubernetes e CloudNativePG, ou quando você simplesmente deseja o pooler mais documentado. O Supavisor torna-se relevante além de um determinado número de bases atendendo a um mesmo serviço. Vale a pena desviar do PgCat se você perder a fragmentação e o failover de réplica no nível da rede, desde que aceite a maturidade de um projeto mais jovem.
O código Aurabase mostra uma escolha consistente, não neutra: PgBouncer em modo de transação, em dois níveis, frota compartilhada e pooler CNPG por locatário dedicado. Restam duas exceções documentadas, para PostgREST e para administração de esquema. Se você quiser ver este projeto em ação e não no papel, nossa página Desempenho documenta a metodologia de medição associada.