default_pool_size es uno de esos parámetros que, si lo pones “a ojo”, puede salir bien… hasta el día que sube la carga y te explota: Postgres saturado (si te pasas) o colas en PgBouncer (si te quedas corto).
La buena noticia: se puede dimensionar con un método simple y luego afinar con métricas.
1) Qué controla realmente default_pool_size
PgBouncer define default_pool_size como:
cuántas conexiones “server” permite por par usuario/base de datos (user/database pair), y puede sobrescribirse por DB. Postgres Professional
En transaction pooling (lo típico con Odoo), una conexión “server” se asigna solo durante la transacción y luego vuelve al pool. Postgres Professional+1
Traducción: default_pool_size es, en la práctica, tu límite de transacciones concurrentes hacia PostgreSQL por pool.
2) Antes de calcular: define cuántos “pools” tienes (esto cambia todo)
Como el pool es por (db, user), el número de pools depende de cómo conectas:
Odoo típico: 1 usuario DB (odoo) + 1 DB ⇒ 1 pool (lo más común).
Multi-tenant: 1 usuario DB + N bases ⇒ N pools (uno por base).
Varios usuarios DB: (raro en Odoo) ⇒ multiplicas pools (db × users).
3) Paso a paso para dimensionar (sin magia)
Paso A — Define tu “presupuesto” real de conexiones en PostgreSQL
No uses max_connections como “todo para PgBouncer”. Reserva margen para:
superuser / admin
migraciones, backups, mantenimiento
monitoreo
replicación (si aplica)
conexiones directas (si decides bypass para algo específico)
Ejemplo mental: deja 10–20% libre como colchón.
Paso B — Reparte el presupuesto entre pools
Fórmula base:
default_pool_size_inicial ≈ floor( presupuesto_pg / num_pools )
Ejemplo:
max_connections = 300
reservas 50 para “todo lo demás” → presupuesto_pg = 250
tienes 1 pool → default_pool_size ≈ 250 (pero ojo: no siempre conviene llegar tan alto)
Paso C — No le des a Postgres más concurrencia de la que puede digerir
Aunque “quepa” en max_connections, Postgres puede volverse lento si le das demasiadas consultas simultáneas (CPU, I/O, locks). Por eso, como regla operativa:
Empieza conservador (p.ej. 20–80 por pool) y sube con métricas.
A veces 40 conexiones bien usadas rinden más que 200 compitiendo a lo bruto.
default_pool_size es “cuántas” conexiones; no garantiza “más rendimiento”.
4) Método recomendado (el que funciona en producción)
4.1 Elige un default_pool_size inicial por perfil
Si es 1 pool (1 DB, 1 user):
Servidor pequeño / carga moderada: 20–40
Servidor medio: 40–80
Servidor grande (DB potente + queries optimizadas): 80–150
Si es multi-DB (N pools):
parte el presupuesto por N y cap por pool (no dejes que una DB “se coma” todo).
Recuerda: default_pool_size es por usuario/DB. Postgres Professional
4.2 Activa “burst control”: reserve_pool_size
PgBouncer permite un “extra” temporal con:
reserve_pool_size (conexiones adicionales)
reserve_pool_timeout (cuándo se habilitan si un cliente espera) Postgres Professional+1
Ejemplo típico para Odoo:
reserve_pool_size = 10 (o 10–20% del pool)
reserve_pool_timeout = 5
Esto absorbe picos cortos sin sobredimensionar el pool “normal”.
5) Usa límites globales para evitar sorpresas
Aunque default_pool_size es por (db,user), puedes imponer techos con:
max_db_connections (límite de conexiones server por base, sin importar user) Postgres Professional
max_user_connections (límite por user, sin importar DB) Postgres Professional
Esto es oro si tienes múltiples DBs o escenarios donde un pool puede crecer más de lo esperado.
6) La validación real (la única que vale)
Señal 1: ¿hay cola en PgBouncer?
Mira SHOW POOLS; y fíjate en:
cl_waiting (clientes esperando)
sv_active (server conns activas)
Si cl_waiting sube en picos y Postgres está cómodo → probablemente te falta pool.
Señal 2: ¿Postgres está “feliz” o saturado?
Si al subir default_pool_size ves:
CPU/IO al 100%
más lock waits
más latencia por query
…tu DB no gana con más concurrencia: necesitas optimizar queries/índices o bajar el pool.
7) Ejemplo “de libro” (Odoo típico)
Escenario
1 DB, 1 user (odoo)
Postgres max_connections = 300
Reservas 60 (admin, mantenimiento, etc.) → presupuesto = 240
Empiezas con algo prudente:
[pgbouncer] pool_mode = transaction default_pool_size = 80 reserve_pool_size = 20 reserve_pool_timeout = 5 max_db_connections = 120
Luego:
si cl_waiting aparece en horas pico y Postgres no sufre → subes a 100–120
si Postgres sufre → bajas y optimizas
8) Bonus: no olvides max_client_conn (y FDs)
max_client_conn es cuántos clientes (Odoo workers + conexiones) acepta PgBouncer, y la propia doc advierte que esto impacta file descriptors y hasta da fórmulas del máximo teórico. Postgres Professional
No es parte directa del cálculo de default_pool_size, pero si lo dejas bajo, vas a ver rechazos aunque el pool esté bien.
Cierre: la regla de oro
default_pool_size no se “adivina”: se elige conservador, se observa (colas vs saturación) y se ajusta.