Skip to content

Zoom-in: Connection Pool

Karify98·
Cover Image for Zoom-in: Connection Pool

Your application slows down or crashes under heavy load. The logs show a "Too many connections" error, even though your database queries are indexed and optimized.

graph TD
    App(["💻 App Service"]) -->|"Query 1 (Create new connection)"| DB[("🗄️ Database")]
    App -->|"Query 2 (Create new connection)"| DB
    App -->|"Query N (Create new connection)"| DB
    style App fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd
    style DB fill:#1a3a2a,stroke:#22c55e,color:#86efac

Let's zoom in on this problem.


Layer 1 — The Setup Cost: 3-way Handshake and Authentication

Opening and closing a connection for every query introduces significant overhead on both the network and the database.

sequenceDiagram
    participant A as App Service
    participant D as Database

    A->>D: 1. TCP Syn (3-Way Handshake)
    D-->>A: 2. TCP Syn-Ack
    A->>D: 3. TCP Ack
    A->>D: 4. TLS Handshake (Encryption)
    D-->>A: 5. Handshake Complete (Keys Exchanged)
    A->>D: 6. Send credentials (Authentication)
    D-->>A: 7. Session Created

To establish a new connection, the client must perform a TCP 3-way handshake, a TLS negotiation for encryption, and send credentials to authenticate the session. This process takes anywhere from 10ms to over 100ms depending on geographical distance. This network round-trip inflates application latency before the query runs.

Remaining problem: repeatedly opening and closing connections wastes database CPU, network bandwidth, and memory on overhead rather than actual work.

Layer 2 — Connection Pool: Reusing Persistent Connections

Instead of opening and closing connections per query, a Connection Pool keeps a set of database connections open in an idle state.

sequenceDiagram
    participant App as 💻 App Code
    participant PM as 📦 Pool Manager
    participant DB as 🗄️ Database

    App->>PM: 1. Request connection (Checkout)
    PM-->>App: 2. Return connection #3 (Ready)
    App->>DB: 3. SELECT * FROM users (Query executes)
    DB-->>App: 4. Query results
    App->>PM: 5. Return connection (Checkin)
    Note over PM: Connection #3 becomes Idle again

When the application needs to run a query, it borrows (checkouts) an idle connection from the pool. The query is sent immediately without a handshake. After retrieving the results, the application returns (checkins) the connection to the pool for other requests to use.

Remaining problem: what happens when a sudden spike in traffic exceeds the number of available connections in the pool?

Layer 3 — Throttling & Queueing: The Backpressure Safety Valve

When all connections in the pool are busy (active), the Pool Manager places new requests into a queue rather than opening more database connections.

graph TD
    R["📥 Incoming Request"] --> PM{"📦 Pool Manager"}
    PM -->|"Connection available"| Alloc["Allocate connection"]
    PM -->|"No connections available"| Q["⏳ Waiting Queue"]
    Q -->|"Timeout reached"| Fail["❌ Reject with Timeout Error"]
    Q -->|"Connection returned"| Alloc
    style R fill:#1e293b,stroke:#475569,color:#cbd5e1
    style PM fill:#3b2a1a,stroke:#f59e0b,color:#fcd34d
    style Q fill:#1e3a5f,stroke:#3b82f6,color:#93c5fd

If a request waits longer than the configured limit (connection timeout) without a connection freeing up, the pool rejects it. This queuing mechanism acts as backpressure, protecting the database from running out of memory and CPU under intense traffic.


Full picture

sequenceDiagram
    participant C as Client Request
    participant App as App Code
    participant PM as Pool Manager (Max: 10)
    participant DB as Database

    C->>App: 1. HTTP Request
    App->>PM: 2. Checkout connection
    alt Connection is Idle
        PM-->>App: Return connection #5
        App->>DB: SELECT...
        DB-->>App: Results
        App->>PM: Return connection #5
        App-->>C: 200 OK
    else All connections busy (All 10 active)
        PM-->>PM: Place request in Queue
        alt Connection freed before Timeout
            Note over PM: Connection #1 returned
            PM-->>App: Return connection #1
            App->>DB: SELECT...
            DB-->>App: Results
            App->>PM: Return connection #1
            App-->>C: 200 OK
        else Timeout reached
            PM-->>App: Connection Timeout Error
            App-->>C: 500 Internal Server Error
        end
    end

Takeaway

A Connection Pool is not just a tool to optimize performance and reduce latency by skipping connection handshakes. It is a critical architecture guardrail that manages finite resources. Setting the pool size too large can crash your database, while setting it too small can choke your application queues.


This post was assisted by Amy 🌸 - AI Assistant. Content has been reviewed by the author.

Related Posts