Challenge

Size six services

25 minintermediate115 yrs

Edge cases. You have to reason, and two valid fixes differ.

What this teaches

  • The sizing question is unanswerable without hold time
  • Two of the six should not be sized at all until something else is fixed
  • Total connections across instances is the number the database sees
  • A batch job and a request handler should not share a pool

Starter

Starter.javaOpen in playground
import java.util.*;

/**
 * Challenge: six services, one database. Size each pool.
 *
 * Two of them cannot be sized sensibly until something else changes, and
 * saying so is the correct answer rather than a dodge.
 */
public class Starter {

    // ── 1 ─────────────────────────────────────────────────────────────────
    // Product search. 2,000 req/s. One indexed query, p99 4 ms. 6 instances.

    // ── 2 ─────────────────────────────────────────────────────────────────
    // Checkout. 50 req/s. One transaction that also calls a payment gateway
    // with a p99 of 900 ms, inside the transaction. 4 instances.

    // ── 3 ─────────────────────────────────────────────────────────────────
    // Nightly reconciliation. One instance, runs for 40 minutes, streams
    // 2 million rows through a single connection.

    // ── 4 ─────────────────────────────────────────────────────────────────
    // Notification worker. 500 messages/s. Two queries per message, 3 ms
    // each. Autoscales between 2 and 20 instances.

    // ── 5 ─────────────────────────────────────────────────────────────────
    // Admin dashboard. 1 req/s. Aggregate queries with a p99 of 6 seconds.
    // 1 instance. Shares its pool with an hourly export job.

    // ── 6 ─────────────────────────────────────────────────────────────────
    // Public API on Java 21 with virtual threads. 3,000 req/s, one query at
    // 5 ms. 8 instances. No thread pool bounding anything.

    // The database: PostgreSQL, 8 cores, SSD, max_connections = 100.

    public static void main(String[] args) {

        // TODO 1: for each service, compute connections = rate x hold time.
        // Show the arithmetic. Note where hold time is not the query time.

        // TODO 2: two of the six produce a number the database cannot give.
        // Name them and say what has to change before sizing means anything.

        // TODO 3: service 3 needs one connection and holds it for 40 minutes.
        // Is that a problem? Say what it does to max_lifetime and to the
        // database's ability to clean up old row versions.

        // TODO 4: service 4 autoscales. Give the per-instance pool and then
        // the total at minimum and maximum scale. Which one breaks?

        // TODO 5: service 5 shares a pool between a 6-second dashboard query
        // and an export job. Say what the export does to the dashboard, then
        // split them and give both sizes.

        // TODO 6: service 6 has virtual threads and no thread pool. Say what
        // used to limit database concurrency, what limits it now, and what
        // that means for the acquisition timeout specifically.

        // TODO 7: add up every connection across all six at full scale, plus
        // monitoring and replication. Compare with max_connections = 100.
        // If you are over, say what you would do — there are three options
        // and they are not equally good.

        // TODO 8: give an acquisition timeout for each service. They should
        // not all be the same number, and the reason is about what the caller
        // does when refused.
    }
}

Run it locally:

cd exercises/java/db-performance/connection-pool-sizing/02-challenge
javac Starter.java -d /tmp/out && java -cp /tmp/out Starter

Hints

  1. Hint 1

    For each service, write connections = rate x hold time before anything else. Two of them produce an absurd number — that is the answer.

  2. Hint 2

    One service's hold time is dominated by something that is not a query. Sizing it is the wrong task.

  3. Hint 3

    One is fine per instance and not fine in aggregate. Multiply.

  4. Hint 4

    One shares a pool between two workloads with very different hold times. Say what the slow one does to the fast one.

Done when

  • A pool size, or a refusal to size, for each of the six with the arithmetic shown
  • The two hold-time problems identified as hold-time problems
  • A total connection count across all instances and tools, compared against max_connections
  • The shared-pool case split, with a reason
  • For each, the acquisition timeout you would set and why

← Back to How do you size a database connection pool?