CodePark/ questions / Connections & pooling
START PRACTICINGPRACTICE
Backend question · Databases & SQL › Connections & pooling

A Node API moved to serverless functions and PostgreSQL started rejecting connections with too many clients already during traffic spikes. Why, and how do you fix it?

Each function instance has its own memory and its own connection pool. Under load, the platform starts many instances in parallel, and each one opens one or more connections. For example, a spike to 300 instances with a pool of 5 each wants 1,500 connections. That is far above max_connections, the database's limit on open connections. Frozen or idle instances can also keep connections open without using them.

Fixes:

  • Make the pool in each instance very small, often max: 1.
  • Create the pool outside the handler function. Then warm invocations (calls that reuse an already running instance) reuse the same pool.
  • Most important: put a pooler between the functions and the database. Examples are PgBouncer in transaction mode or a managed pooler from your cloud provider. A pooler lets thousands of client connections share a small number of real database connections.
  • Limit function concurrency. This also caps the total number of connections.

Remember the limits of transaction mode. Session state does not survive between transactions. Prepared statements may not work either. PgBouncer supports them in transaction mode only from version 1.21, when max_prepared_statements is set.

  • Every instance has its own pool, and the platform starts more instances under load.
  • The total number of connections goes above max_connections.
  • Use a tiny pool per instance, created outside the handler.
  • Put an external pooler, PgBouncer or a managed one, in front of the database.
  • Remember the transaction-mode limits, and cap function concurrency.