SCALABILITY & PERFORMANCE / SYSTEM CONCEPT BRIEF

Connection pooling

A connection pool keeps a set of open connections (to a database, cache, or HTTP service) ready for reuse, instead of opening and closing one per request.

IntermediatePhase 03 / Topic 11 of 13RequirementsTrade-offsFailure modes
01

Overview

A connection pool keeps a set of open connections (to a database, cache, or HTTP service) ready for reuse, instead of opening and closing one per request. Opening a database connection can cost tens of milliseconds (TCP, TLS, authentication, backend process setup), and databases can only handle a limited number of connections at once.

Pools make requests faster and protect the database. The key design question is sizing: too few connections and requests queue; too many and the database spends its time context switching. With many app instances, the total across all pools must stay within what the database can handle, which is why proxies like PgBouncer exist.

Taxi stand

Instead of calling a new taxi every time (slow), a stand keeps a few taxis waiting. Customers take one and return it. Too few taxis create a queue; too many clog the street.

02

When to use it

  • Any service talking to a relational database.
  • High-rate HTTP calls to the same downstream service (keep-alive agents).
  • Serverless functions that would otherwise open a connection per invocation.
  • Protecting databases from connection storms during scale-outs.
03

Where it shows up in interviews

Database protection

Recognize it when: hundreds of app instances hit one database.

  • Scale a web app on PostgreSQL
  • Design a serverless backend with a relational DB
Service-to-service efficiency

Recognize it when: high call volume to a dependency.

  • Design an API gateway
  • Design a payment service calling a bank API
04

Where it is used in real software

PgBouncer

A lightweight PostgreSQL proxy that multiplexes thousands of client connections onto a few dozen server connections.

HikariCP

The default Java connection pool in Spring Boot, known for speed and a recommended small pool size.

Amazon RDS Proxy

Pools database connections for Lambda functions, which would otherwise exhaust database connection limits.

05

Key terms

Pool size
Maximum open connections per instance.
Acquire timeout
How long a request waits for a free connection before failing.
Idle timeout
Close connections unused for a while.
Transaction pooling
PgBouncer mode that assigns a server connection only for a transaction's duration.
06

How it works, step by step

  1. 1
    Pool opens connections

    Up to a minimum at startup and a maximum under load.

  2. 2
    Request borrows a connection

    Waits up to the acquire timeout if all are busy.

  3. 3
    Run queries

    Keep transactions short so the connection returns quickly.

  4. 4
    Return the connection

    Always, even on errors (finally blocks).

  5. 5
    Validate and recycle

    Test stale connections and replace them periodically.

07

Sizing pools across a fleet

PostgreSQL max_connections = 500, keep 50 for admin and replication

Step 1 / 4
App instancesPool size eachTotal connectionsResult
1020200Fine
4020800Exceeds limit: connection errors
4010400Fits
40 via PgBouncer20 client each, 60 server total60 server connectionsFits with lots of headroom

NOWApp instances: 10 | Pool size each: 20 | Total connections: 200 | Result: Fine

Pool size per instance times instance count must stay below the database limit. Auto scaling app servers without a pooler can take down the database.

08

Implementation

import { Pool } from "pg"; const pool = new Pool({  connectionString: process.env.DATABASE_URL,  max: 10,                        // per instance; total = max x instances  idleTimeoutMillis: 30_000,  connectionTimeoutMillis: 2_000, // fail fast instead of queueing forever}); export async function transferFunds(from: string, to: string, cents: number) {  const client = await pool.connect();  try {    await client.query("BEGIN");    await client.query("UPDATE accounts SET balance = balance - $1 WHERE id = $2", [cents, from]);    await client.query("UPDATE accounts SET balance = balance + $1 WHERE id = $2", [cents, to]);    await client.query("COMMIT");  } catch (err) {    await client.query("ROLLBACK");    throw err;  } finally {    client.release(); // always return the connection  }}
09

Complexity and performance

New PostgreSQL connection~5-50 ms

TCP + TLS + auth + process fork.

Borrow from poolmicroseconds

When a connection is free.

Good starting pool size~2 x CPU cores of the DB / instances

Tune with load tests.

10

Trade-offs

Bigger vs smaller pools

Bigger pools reduce waiting at the app but overload the database; a small pool plus a short queue often gives better total throughput.

Session vs transaction pooling

Transaction pooling scales further but breaks session features (prepared statements, session variables) unless handled.

11

Variants and related techniques

HTTP keep-alive agents

Reuse TCP/TLS connections to downstream services.

Redis connection multiplexing

Clients like ioredis pipeline many commands over one connection.

12

Common mistakes

  • Forgetting to release connections.

    Fix: Use finally blocks or helpers; leaks exhaust the pool.

  • Long transactions holding connections.

    Fix: Never call slow external APIs inside a DB transaction.

  • Scaling app instances without checking DB limits.

    Fix: Use a pooler (PgBouncer, RDS Proxy) and cap total connections.

13

Interview questions

Why use connection pooling?

Creating connections is slow and databases support a limited number. Reusing a fixed set of connections cuts latency and protects the database from overload.

Your database hits max connections after auto scaling. What do you do?

Reduce per-instance pool sizes, add a connection pooler such as PgBouncer or RDS Proxy, and make sure connections are released and transactions are short.

14

Practice problems

ProblemDifficultyWhat it trains
Size pools for 30 instances and a 300-connection DBEasyMath.
Design DB access for 10,000 concurrent Lambda functionsMediumProxy pooling.