Matemáticas de Conexiones
El max_connections de PostgreSQL es un límite estricto. El número de instancias de aplicación × tamaño del pool debe mantenerse por debajo de él, con margen para administración, replicación y autovacuum. Usa PgBouncer (o el pooler del proveedor) para que cientos de hilos de aplicación se multiplexen en decenas de backends reales.
Receta
presupuesto_seguro_backend = max_connections - reservado
reservado ≈ 10 (superusuario) + ranuras_replicacion + monitoreo + margen_admin (15-30)
conexiones_servidor_app = instancias_app × pool_max_por_instancia
conexiones_servidor_pgbouncer = tamaño_pool (hacia Postgres)
Regla: tamaño_pool_pgbouncer ≤ presupuesto_seguro_backend × 0.8
Regla: suma(server_conn de todos los pools) ≤ presupuesto_seguro_backend
SHOW max_connections;
SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';Cuándo recurrir a esto:
- Errores de producción "too many clients already" (demasiados clientes ya)
- HPA de Kubernetes aumentando el número de pods
- Dimensionamiento de un nuevo grupo de parámetros de instancia RDS
Ejemplo de Trabajo
40 pods de API, cada uno con un pool máximo de 20, modo de transacción de PgBouncer, max_connections=200 de RDS.
Lado de la aplicación (potencial): 40 × 20 = 800 conexiones de cliente a PgBouncer (OK)
PgBouncer default_pool_size = 40 conexiones de servidor a Postgres
Reservado: 20 admin/replicación/monitor
Usado: 40 + 20 = 60 ≤ 200 × 0.8 = 160 ✓
# Extracto de pgbouncer.ini
[databases]
orders = host=primary.internal port=5432 dbname=orders
[pgbouncer]
pool_mode = transaction
default_pool_size = 40
max_client_conn = 1000
reserve_pool_size = 5-- Verificar uso en vivo
SELECT state, count(*) FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY 1;
SELECT setting::int FROM pg_settings WHERE name = 'max_connections';Lo que esto demuestra:
- La aplicación puede abrir 800 conexiones lógicas mientras que Postgres ve ~40 backends activos
- Reserva margen para sesiones que no son de la aplicación
max_client_connen PgBouncer es independiente demax_connectionsde Postgres
Inmersión Profunda
Sin Pooler (antipatrón a escala)
50 pods × 20 conexiones = 1000 > max_connections 200 → fallo
Impacto de los Modos de Pool
| Modo | Backends de servidor | Advertencia |
|---|---|---|
| Session | Hasta el número de clientes | Poco ahorro |
| Transaction | Multiplexado por transacción | Sin persistencia de GUC de sesión |
| Statement | Raro | Rompe muchos ORM |
Pools por Rol
# Pools separados para api vs migrator (migrator evita el pooler directamente)
orders_api = host=primary dbname=orders pool_size=35La CI del migrator se conecta directamente con pool_size=1 de sesión para DDL.
Trampas Comunes
- Pool predeterminado del ORM = num_cpus × 5 por pod - explota con HPA. Solución: limitar el pool (a menudo 5-20 por pod).
- PgBouncer pool_size = max_connections - sin margen administrativo. Solución: máximo 60-70% del presupuesto.
- Múltiples servicios compartiendo un único pool DSN - se requieren matemáticas agregadas. Solución: graficar la contribución de cada servicio al pool.
- RDS max_connections escala con la RAM pero no linealmente con los pods de la aplicación - siempre usar pool. Solución: grupo de parámetros + sidecar de PgBouncer.
- Las conexiones inactivas todavía consumen memoria - ~5-10 MB por backend. Solución: pooling de transacciones, menor tiempo de espera inactivo.
- Funciones sin servidor × alta concurrencia - se requiere pooler Neon/Supabase. Solución: URL del pooler, no directa.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| PgBouncer | Flotas OLTP estándar | Necesidad de tablas temporales con ámbito de sesión en todas partes |
| RDS Proxy | AWS sin operar un pooler | No AWS |
| Supavisor / Neon pooler | Serverless alojado | Autoalojado a menos que adopten su proxy |
| pgpool-II | Despliegues heredados | Greenfield (preferir PgBouncer) |
Preguntas Frecuentes
¿Pool ideal por pod?
5-20 para API típica; prueba de carga; más pequeño si las consultas son rápidas y HPA es amplio.
¿Fórmula max_connections RDS?
Documentación del proveedor ESTILO LEAST({DBInstanceClassMemory/9531392}, 5000) - verificar la documentación de AWS para la clase.
¿Sentencias preparadas con pool de transacciones?
Usar la configuración del ORM para deshabilitar la preparación del lado del servidor o usar un pool de sesión para ese servicio.
¿Monitorear espera del pool?
PgBouncer SHOW POOLS cl_waiting; alertar cuando > 0 de forma sostenida.
¿Conexiones de réplica de lectura?
Pool separado por endpoint; las réplicas tienen su propio max_connections.
¿Ranuras de trabajador de replicación lógica?
Contar en el presupuesto reservado; las ranuras usan conexiones walsender.
¿Tormenta de conexiones al desplegar?
Secuenciar el despliegue de pods; calentamiento del pool; evitar la estampida al reiniciar la base de datos.
¿Máximo de pg_stat_activity?
Muestra backends de servidor; comparar con las métricas de conn de servidor de PgBouncer para una imagen completa.
¿Cuándo aumentar max_connections?
Después de optimizar el pooler y aún así agotar los backends - preferir escalar CPU/RAM con él.
¿Dónde documentar las matemáticas?
Tabla de runbook del servicio: pods, pool, tamaño del pooler, max_connections, fecha de actualización.
Relacionado
- Modos de PgBouncer - semántica del pool
- Fundamentos de Capacidad - contexto de RAM y CPU
- Proxies de Conexión - enrutamiento HA
- Mejores Prácticas de PostgreSQL Gestionado - pooling en la nube
- Mejores Prácticas de Planificación de Capacidad - revisión trimestral
Versiones de Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, y PostGIS 3.5+.