Interview Prep Zoneby CuriouserLabs

Question 3 of 5 · architect level

Size a HikariCP pool and the timeout chain. Why is 'increase the pool' usually the wrong fix?

🎤 Say this first

A connection does work only while a transaction actively uses it — throughput = poolSize / avgHoldTime. Small pools genuinely outperform big ones (less DB contention/context switching): start near cores×2 on the DB side of the math, but the real driver is holdTime — the fix for exhaustion is almost always 'stop holding connections during slow work' (remote calls inside transactions, OSIV) not 'more connections'. And do the fleet math: 30 pods × 30 connections = 900 backends — the DB's limit is the shared budget. Then design the timeout chain: connectionTimeout < request timeout, holds bounded, leak detection on.

The full picture

A reasoned configuration
spring.datasource.hikari:
  maximum-pool-size: 15          # from math, not vibes: see below
  minimum-idle: 15               # fixed pool: no resize thrash under burst
  connection-timeout: 2000       # fail fast; don't queue callers into timeout stacking
  max-lifetime: 1800000          # < DB/LB idle kill (30m) — avoids mid-query drops
  keepalive-time: 300000
  leak-detection-threshold: 10000  # logs stacks holding >10s — finds the OSIV/remote-call bugs

# The math: target 500 req/s hitting DB, avg TX hold 20ms
#   connections needed ≈ 500 * 0.02 = 10 (+ headroom) => 15
# Fleet: 20 pods * 15 = 300 ≤ DB max_connections budget (with reserve) ✅
  • Exhaustion triage order: leak detection stacks → who holds long? (remote call in TX? OSIV? missing close on manual usage?) → fix holds → only then revisit size. Doubling the pool with 5s holds just moves the queue into the DB.
  • Timeout chain coherence: client timeout > server request timeout > (connectionTimeout + query timeouts). Inverted chains create work that outlives its requester — the retry-storm amplifier.
  • Virtual threads sharpen this: VTs remove the thread ceiling, so 10k concurrent requests all reach for the pool — the pool becomes the explicit concurrency limiter; consider a semaphore in front of scarce resources to keep queues visible and bounded.
  • Observe: hikaricp.connections.pending (callers waiting) is the leading indicator; alert on sustained pending, not on usage %.

🔄 Likely follow-up questions

  • Derive pool needs from Little's Law for a given SLO.
  • read-only replicas: separate pools/datasources — routing strategies?
  • What does REQUIRES_NEW do to pool math under load? (two holds per thread)