Un ingeniero revisa métricas de Postgres y PgBouncer en una sala de operaciones con pantallas de monitoreo y gráficas de conexiones activas.

PgBouncer a 4x: lecciones reales para Postgres

PgBouncer a 4x throughput muestra cómo exprimir más rendimiento en Postgres sin rehacer la arquitectura. Te explicamos qué cambió, qué midieron y qué lecciones sirven a equipos en Latinoamérica que ya están al límite de conexiones.

Si tu base de datos ya está cerca del límite de conexiones, sabes que el problema no siempre es “más CPU” o “más RAM”. Muchas veces el cuello de botella está en cómo se abren, reutilizan y liberan las conexiones. Ahí es donde PgBouncer deja de ser un componente secundario y pasa a ser parte del plan de capacidad.

El caso que compartió ClickHouse sobre su despliegue de Managed Postgres va justo por ese camino: no cambiaron toda la arquitectura para ganar aire, sino que ajustaron la capa de pooling y lograron multiplicar el throughput por cuatro. La lección útil para ti no es solo el número, sino el enfoque: antes de pensar en reescribir servicios o partir la base en mil piezas, revisa si estás pagando demasiado costo por conexión.

Qué problema resuelve PgBouncer cuando Postgres ya va justo

Postgres maneja cada conexión como un proceso o backend separado. Eso funciona bien hasta que el número de sesiones concurrentes empieza a crecer y el costo de mantenerlas vivas se vuelve caro. Si tu aplicación abre muchas conexiones cortas, o si tienes muchos pods, workers o lambdas golpeando la base, el servidor termina gastando tiempo en administración de sesiones en lugar de trabajo útil.

PgBouncer entra como pooler. En vez de que cada cliente hable directo con Postgres de forma permanente, PgBouncer mantiene un conjunto más pequeño de conexiones hacia la base y las reutiliza para múltiples clientes. Eso reduce el churn de conexiones, baja la presión sobre el backend y te permite atender más tráfico con el mismo servidor.

La idea no es mágica ni nueva, pero sí muy práctica. Si tienes un stack con API, jobs en background, migraciones, cron y herramientas internas, es fácil llegar a cientos o miles de conexiones aparentes aunque el tráfico real no sea tan alto. En ese escenario, un pool bien configurado puede darte más margen que un upgrade de instancia caro y apresurado.

Cuándo empieza a doler de verdad

Hay señales bastante claras. Por ejemplo: picos de conexión que coinciden con despliegues, timeouts intermitentes al abrir sesiones nuevas, latencia rara en endpoints que solo hacen queries simples, o saturación del parámetro max_connections aunque el uso de CPU no esté al 100%.

También pasa mucho en equipos que escalan horizontalmente sin revisar el impacto en la base. Si cada réplica de tu API levanta 20 conexiones y pasas de 5 a 20 réplicas, ya cambiaste el perfil de carga sin tocar una sola query. El problema no es solo el volumen, sino la multiplicación silenciosa.

PgBouncer ayuda justamente ahí: a desacoplar el número de clientes del número de conexiones reales a Postgres. Pero para que funcione bien, tienes que entender qué modo usar, cómo medir el efecto y qué trade-offs aceptas.

Qué hizo ClickHouse y por qué importa

En su publicación, ClickHouse explica que logró escalar PgBouncer a 4x throughput en su entorno de Managed Postgres. No se trató de una optimización cosmética. El objetivo fue sostener más tráfico con menos fricción en la capa de conexión, algo que cualquier equipo que opera Postgres bajo presión puede reconocer de inmediato.

La parte interesante es que el caso no gira alrededor de una migración total ni de un rediseño de aplicación. El foco está en la infraestructura alrededor de la base: cómo se enrutan las conexiones, cómo se amortiza el costo de abrir sesiones y cómo se evita que el pool se convierta en otro cuello de botella.

Eso importa porque muchas veces la respuesta institucional a un problema de conexiones es demasiado grande. Se habla de particionar, de mover cargas a otro motor, de meter una capa de caché, o de reescribir el acceso a datos. A veces toca hacerlo, sí. Pero en otros casos el salto de rendimiento viene de algo más pequeño: configurar mejor el pool y observar el sistema con más rigor.

Qué significa 4x throughput en la práctica

Throughput no es lo mismo que latencia. Puedes tener una consulta que responde rápido en aislamiento y aun así no sostener carga concurrente. Cuando un sistema dice que multiplicó su throughput por cuatro, lo que te está diciendo es que pudo procesar muchas más operaciones por unidad de tiempo bajo una condición comparable.

En términos prácticos, eso suele traducirse en una o varias de estas mejoras:

  1. Más consultas atendidas por segundo sin aumentar proporcionalmente el tamaño de la instancia.
  2. Menos tiempo perdido en crear y destruir conexiones.
  3. Menor presión sobre el backend de Postgres en picos de tráfico.
  4. Más estabilidad cuando varios clientes compiten por recursos al mismo tiempo.

No significa que tu base de datos ahora sea cuatro veces más rápida en todo. Lo que sí significa es que la capa de conexión estaba frenando el sistema más de lo que parecía.

Lo que puedes copiar sin copiar toda la arquitectura

No necesitas ser ClickHouse para aprender del enfoque. Si hoy operas Postgres para una app SaaS, una plataforma de e-commerce o un backend de analítica, puedes aplicar el mismo criterio: identificar si el límite está en la base o en la forma de conectarte a ella.

La lección más útil es esta: antes de tocar el modelo de datos, mide la distribución de conexiones, el tiempo de espera para obtener una sesión y la tasa de reutilización. Si esos números están mal, PgBouncer puede darte un salto importante sin mover todo lo demás.

Cómo pensar la configuración sin adivinar

PgBouncer tiene varios modos y cada uno sirve para cosas distintas. El más conocido es transaction pooling, que reutiliza la conexión del backend entre transacciones. Eso suele dar muy buen rendimiento cuando tu aplicación hace queries cortas y no depende de mantener estado de sesión entre una consulta y otra.

Pero ese modo no es universal. Si tu app usa prepared statements de forma intensiva, session variables, advisory locks o features que dependen de mantener la sesión viva, debes revisar con cuidado qué se rompe al pasar por el pooler. No es un problema de PgBouncer en sí, sino de compatibilidad entre tu patrón de uso y el modo elegido.

La documentación oficial de PgBouncer es la referencia que debes tener abierta mientras haces pruebas: https://www.pgbouncer.org/features.html. Para Postgres, también conviene revisar la guía oficial sobre conexiones y parámetros relacionados: https://www.postgresql.org/docs/current/runtime-config-connection.html.

Tres decisiones que no deberías tomar a ciegas

Antes de mover tráfico real, revisa estos puntos:

  • Modo de pooling: transaction, session o statement. En la práctica, transaction suele ser el punto de partida para apps web, pero no siempre.
  • Tamaño del pool: si lo haces demasiado pequeño, introduces espera artificial. Si lo haces demasiado grande, pierdes parte del beneficio.
  • Timeouts y límites: connection timeout, idle timeout y límites por usuario o base pueden cambiar mucho el comportamiento bajo carga.

Un error común es copiar una configuración de internet y asumir que funcionará igual. Tu patrón de tráfico, tu ORM y tu número de réplicas importan más que la receta genérica.

Señales de que vas por buen camino

Cuando el ajuste está bien hecho, deberías ver algunos cambios medibles. Por ejemplo, menos conexiones activas en Postgres para la misma carga, menor variación en la latencia de endpoints que consultan la base y menos rechazos por saturación de conexiones.

También deberías observar que el pooler no se convierte en el nuevo cuello de botella. Si PgBouncer empieza a acumular esperas largas, quizá el tamaño del pool es demasiado chico o tu aplicación está sosteniendo sesiones de forma innecesaria.

La clave es medir antes y después con la misma ventana de carga. Sin eso, cualquier mejora se vuelve una impresión subjetiva.

Qué métricas sí mirar para saber si mejoraste

Si quieres sacar conclusiones útiles, no te quedes solo con el promedio de latencia. En problemas de conexiones, los promedios esconden bastante. Lo que te conviene mirar es la cola, los percentiles y el comportamiento en picos.

Una forma simple de ordenar la observación es esta tabla:

MétricaQué te diceSeñal sanaSeñal de alerta
Conexiones activas en PostgresCuánta presión real recibe el backendEstable y por debajo del límite cómodoCerca de max_connections en picos
Espera para obtener conexiónSi el pool está chico o saturadoBaja y estableCrece durante tráfico normal
Latencia p95 de endpointsImpacto percibido por usuariosPoco ruido entre picosSaltos bruscos con carga moderada
Rechazos por timeoutSi el sistema deja caer trabajoCasi ceroAparecen en horas punta
Uso de CPU en PostgresSi el motor está trabajando o solo administrandoAlineado con trabajo realAlto sin aumento de throughput

Si tienes observabilidad suficiente, añade métricas de PgBouncer como clients waiting, active server connections y pool utilization. Esas tres te dicen si el pool está absorbiendo bien la presión o si solo estás moviendo el problema de lugar.

Un flujo de prueba razonable

Una secuencia práctica para validar cambios sería esta:

  1. Mide el estado actual durante una ventana de tráfico real de al menos 30 minutos.
  2. Define una carga comparable con tu herramienta de pruebas o con tráfico controlado.
  3. Activa PgBouncer en un entorno de staging o en una fracción pequeña del tráfico.
  4. Compara conexiones, p95 y errores antes y después.
  5. Ajusta pool size, timeouts y modo de pooling con cambios pequeños, no con saltos grandes.

Si haces pruebas con una carga artificial, procura que se parezca a tu patrón real. Un benchmark con muchas consultas idénticas no siempre representa un sistema con múltiples endpoints, jobs y escrituras concurrentes.

Cuándo PgBouncer te ayuda y cuándo no alcanza

PgBouncer es muy útil cuando el dolor principal está en la conexión, no en la consulta. Si tus queries son lentas por falta de índices, joins pesados o diseño deficiente, el pool no va a arreglar eso. Solo va a hacer que llegues al problema con menos fricción en el camino.

También hay límites claros. Si tu aplicación depende de features de sesión o si tu patrón de trabajo necesita mantener estado entre llamadas, el modo de pooling puede complicarte. En esos casos, quizá necesites separar rutas críticas, usar PgBouncer solo para ciertos servicios o ajustar el código para reducir dependencia de sesión.

Otra situación típica es confundir escalado de conexiones con escalado de escritura. Si el backend ya está saturado por I/O, locks o contención en tablas calientes, el pool ayuda menos. Por eso el caso de ClickHouse es interesante: muestra una mejora grande en la capa correcta, no una promesa de curarlo todo.

Errores frecuentes que ves en equipos reales

Estos son algunos patrones que suelen aparecer cuando un equipo intenta meter PgBouncer tarde y con prisa:

  • Ponerlo delante de todo sin separar cargas de lectura y escritura.
  • Mantener max_connections demasiado alto y usar PgBouncer solo como parche.
  • No revisar prepared statements y terminar con errores raros en producción.
  • Medir solo throughput y olvidar la latencia p95 o p99.
  • Cambiar demasiadas variables al mismo tiempo y no saber qué funcionó.

Si te reconoces en uno de esos puntos, no estás solo. La mayoría de los problemas de pool no vienen del software, sino de la falta de límites claros entre aplicación, pooler y base.

Cuándo vale la pena parar y rediseñar

Hay casos en los que PgBouncer te compra tiempo, pero no te da el salto que necesitas. Si tu crecimiento viene acompañado de más escrituras, más consistencia fuerte o más aislamiento entre tenants, puede que el problema sea estructural.

Aun así, incluso ahí, el pool puede servir como paso intermedio. Te deja estabilizar el sistema mientras decides si separas servicios, introduces colas o cambias la forma en que tus clientes consumen datos.

Tabla resumen

Pregunta cortaRespuesta corta
¿Qué problema ataca PgBouncer?El costo de manejar demasiadas conexiones a Postgres.
¿Qué logró el caso de ClickHouse?Escalar PgBouncer a 4x throughput en su entorno gestionado.
¿Qué modo suele usarse primero?Transaction pooling, si tu app lo soporta.
¿Qué métrica importa más que el promedio?El p95 y la cola para obtener conexión.
¿PgBouncer arregla queries lentas?No, solo reduce el costo de conexión.
¿Sirve para equipos al límite de conexiones?Sí, especialmente si el cuello está en la capa de sesión.

La mejor forma de leer este caso es como una señal de prioridades. Antes de reescribir tu backend o cambiar de base de datos, revisa si estás usando Postgres de una forma más cara de lo necesario. A veces el margen que te falta no está en el motor, sino en cómo llegas a él.

Si tu equipo ya vive al borde de max_connections, PgBouncer no es un parche menor. Puede ser la diferencia entre seguir escalando con cambios acotados o entrar en una migración mucho más larga de lo que querías.

Preguntas frecuentes

¿PgBouncer sirve para cualquier aplicación con Postgres?
No siempre. Funciona muy bien cuando tienes muchas conexiones cortas y queries relativamente simples, pero puede chocar con aplicaciones que dependen de estado de sesión, prepared statements o locks que viven más de una transacción. Lo correcto es probarlo con tu patrón real de uso antes de mover todo el tráfico.
¿Transaction pooling es la mejor opción por defecto?
Suele ser el punto de partida más común para aplicaciones web, porque maximiza la reutilización de conexiones. Aun así, no es universal: si tu aplicación necesita mantener sesión viva entre consultas, puede que necesites session pooling o una estrategia mixta.
¿Cómo sé si mi problema es de conexiones y no de queries?
Mira si el sistema se cae, se pone lento o rechaza tráfico cuando sube la cantidad de conexiones, aunque el uso de CPU no esté al máximo. Si además ves tiempos de espera para abrir sesión o llegas cerca de `max_connections`, el problema está muy probablemente en la capa de conexión.
¿PgBouncer reemplaza la necesidad de optimizar índices o queries?
No. PgBouncer solo reduce el costo de administrar conexiones, pero no acelera una consulta mal diseñada. Si tus consultas son lentas por falta de índices, joins caros o contención, igual tendrás que corregir la base del problema.
¿Qué métricas debo mirar después de activarlo?
Mira conexiones activas en Postgres, clientes esperando en el pool, latencia p95 y errores por timeout. Si puedes, suma CPU, I/O y uso del pool por usuario o por base para entender dónde se concentra la presión.
¿Puedo poner PgBouncer delante de toda mi infraestructura sin más?
No conviene hacerlo a ciegas. Primero valida compatibilidad con tus aplicaciones, define qué servicios pasan por el pool y prueba con una parte del tráfico. Un despliegue gradual te evita errores difíciles de diagnosticar en producción.
¿Este enfoque sirve para equipos en Latinoamérica con presupuestos ajustados?
Sí, porque muchas veces te permite ganar capacidad sin subir de inmediato a una instancia más grande o rediseñar todo el stack. Si operas con márgenes apretados, exprimir mejor Postgres puede darte semanas o meses de aire para planear el siguiente paso con calma.

Azirgo

¿Listo para construir tu Producto Digital?

Sitios web, apps móviles, software a medida y soluciones blockchain. Cuéntanos qué tienes en mente y armamos un plan claro contigo.

  • Cotización clara en 48 horas
  • Equipo en Ecuador, atención en español
  • Desde un MVP hasta un producto en producción