Connection Pooling
Dimensionar e configurar pools de conexões de banco de dados para que serviços assíncronos não esgotem as max_connections do PostgreSQL ou fiquem lentos sob carga.
Receita
Cartão de referência rápida - pronto para copiar e colar.
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(20)
.min_connections(5)
.acquire_timeout(std::time::Duration::from_secs(5))
.connect(&database_url)
.await?;Quando usar isso: Todo processo de servidor que se comunica com PostgreSQL, MySQL ou Redis deve reutilizar um pool - nunca abrir por requisição.
Exemplo de Trabalho
use sqlx::postgres::PgPoolOptions;
#[derive(Clone)]
struct AppState { pool: sqlx::PgPool }
async fn sizing_hint(workers: u32, db_max: u32, services: u32) -> u32 {
// regra de ouro: pool_max * service_replicas * workers <= db_max * 0.8
let per_instance = (db_max as f32 * 0.8 / services as f32).floor() as u32;
per_instance.min(20).max(2)
}
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let max = sizing_hint(4, 100, 3).await;
let pool = PgPoolOptions::new()
.max_connections(max)
.connect(&std::env::var("DATABASE_URL")?)
.await?;
let _state = AppState { pool };
Ok(())
}O que isso demonstra:
max_connectionslimita sessões concorrentes de DB por processo.min_connectionsmantém conexões ativas para latência.acquire_timeoutfalha rapidamente quando o pool está sobrecarregado.- O dimensionamento leva em conta a contagem de réplicas e o limite do DB.
Mergulho Profundo
Como Funciona
- O pool mantém conexões ociosas e as empresta para tarefas.
- Quando o pool está vazio, as tarefas esperam até
acquire_timeout. - O pool do sqlx é integrado;
deadpool-postgresebb8são alternativas para outros drivers.
Fórmula de Dimensionamento
instâncias × pool_max ≤ database_max_connections × 0.7–0.8
Deixe espaço para conexões administrativas, migrações e réplicas.
Notas de Rust
// deadpool-postgres (alternativa)
let cfg = deadpool_postgres::Config::from_url(&url)?;
let pool = cfg.create_pool(None, tokio_postgres::NoTls)?;Armadilhas
- Pool por handler - Criar um novo pool a cada requisição esgota o DB. Correção: Um pool em
AppStatena inicialização. - max_connections muito alto - 100 tarefas Tokio × 50 pool = desastre. Correção: Matemática a partir da contagem de instâncias e do limite do DB.
- Transações longas e ociosas - Mantêm a conexão durante chamadas lentas de API externa. Correção: Transações curtas; liberar antes do I/O.
- Sem acquire timeout - Requisições ficam penduradas para sempre quando o pool está sobrecarregado. Correção: Definir timeout de 3-10s; retornar 503.
- Incompatibilidade com PgBouncer - O modo de pooling de transação quebra instruções preparadas. Correção: Usar modo de sessão ou desativar o cache de instruções.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Pool integrado do sqlx | Pilha sqlx | Precisa de recursos do ecossistema deadpool |
| PgBouncer | Muitos serviços pequenos | Monólito único com poucas conexões |
| Conexão única | Scripts CLI de uso único | Servidores HTTP |
FAQs
Pool por worker?
Um pool por processo - tarefas Tokio o compartilham, não um por thread.
Pooling do Redis?
deadpool-redis ou conexões multiplexadas por orientação do crate redis.
Verificação de saúde?
SELECT 1 através do pool para o endpoint /ready.
Métricas do pool?
Acompanhe o tempo de aquisição, contagem de ociosos e timeouts com tracing ou Prometheus.
Encerramento?
pool.close().await durante o encerramento gracioso.
Divisão de leitura/escrita?
Dois pools apontando para URLs primária e de réplica.
Tempo de vida da conexão?
max_lifetime recicla conexões antigas - defina para failovers de DB na nuvem.
Cache de instruções?
sqlx armazena em cache instruções preparadas por conexão - observe a memória em pools enormes.
Teste de carga do pool?
Aumente gradualmente até que os timeouts de aquisição apareçam - esse é o seu teto real.
Rust Serverless?
Pools muito pequenos ou um pooler externo (PgBouncer) são necessários - os cold starts importam.
Relacionado
- Noções Básicas de Banco de Dados - Primeiro pool
- sqlx - API PgPoolOptions
- Transações e Isolamento - Tempo de retenção da conexão
- Melhores Práticas de Banco de Dados - Regras do pool
- Melhores Práticas de Backends Web - Dimensionamento de serviços
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.