ArchitectureA supervised JVM-class runtime — OLTP on seven engines, OLAP on three. AI-native, MCP-native, observable as plain SQL.Read the architecture
Está viendo la edición Perú. Está viendo la edición Colombia. You're viewing the Pakistan edition. Cambiar a la edición global →Cambiar a la edición global →Switch to the global edition →

JDBC Pool V2 benchmarks — 1K, 2K, 3K concurrent pools per JVM, sub-microsecond acquisition

JDBC Pool V2 benchmarked against the platform's classic pool. Thread-local hit serves 70–90 % of acquisitions in 20–50 ns ; shared-pool acquisition runs 135–580 ns ; a single JVM sustains 1,000–3,000 concurrent per-(database × user) pools without saturating contention.

The new in-house JDBC pool was benchmarked against the platform's classic pool (the previous in-house design that ran in production through 2025) and the leading external pools cited in the public literature — HikariCP and Commons DBCP. The benchmark targets the workload shape the platform's request path actually produces — thousands of short-lived per-(database × user) pools per JVM — rather than the single-pool throughput pattern that JMH micro-benchmarks for shared pools typically use.

Why benchmarking matters here

Pool benchmarks published by external pool vendors typically measure one pool with N threads contending for it. That measurement is interesting but does not represent the platform's load shape. A medium-sized customer running 1,200 concurrent users against three databases produces ~3,600 simultaneous pools, most carrying 1–3 connections each. The bottleneck is not contention on one large pool ; it is the overhead of running thousands of small ones. The pool that wins the single-pool benchmark loses the thousand-pool benchmark every time.

The three benchmark scenarios

  • 1K pools, mixed read-heavy workload. 1,000 concurrent (database × user) pools, 80 % thread-affine acquisitions (the same thread returns to its previous connection), 20 % random. Median acquire latency p50 / p95 / p99.
  • 2K pools, burst-allocation workload. 2,000 concurrent pools with periodic 10× burst spikes simulating end-of-month batch jobs. Measures the cost of acquiring under contention while the scavenger reclaims idle objects.
  • 3K pools, sustained-saturation workload. 3,000 concurrent pools held at 80 % capacity for one hour. Measures memory growth, GC pressure and per-pool overhead in steady state.

What the numbers show

  • Tier-1 thread-local hit : 20–50 ns. Pool V2's per-thread cache serves 70–90 % of acquisitions without touching the shared queue at all. The previous in-house pool had no thread-local tier — every acquisition synchronised on a coarse-grained lock.
  • Tier-2 shared-queue hit : 135–580 ns. Lock-free ConcurrentLinkedQueue backed by compare-and-swap operations. Latency is independent of pool depth because the poll is O(1) amortised.
  • Tier-3 new-connection creation : ~10 ms. Pool growth happens on the platform's VirtualThreadExecutor (JEP 444 virtual threads, available since the JDK 21 upgrade and adopted platform-wide on 2025-11-06) so the acquiring request does not block on TCP setup, TLS handshake and authentication serially. Connection establishment is the natural floor — no pool can beat the database's own three-way handshake latency.
  • Per-pool steady-state memory : ~24 KB. At 3,000 pools, the aggregate pool overhead stays under 80 MB before the connections themselves. Generic external pools assume tens of pools per process and budget memory accordingly ; running 3,000 of them produces gigabyte-class heap pressure.
  • Scavenger lock-hold time : ≤ 50 ms. The scavenger batches validation work and releases the per-pool lock between iterations, so the p999 acquire latency does not spike during cleanup. The previous design held the lock for the entire scavenge cycle, producing 100–5,000 ms latency spikes that operators attributed to "the database" until JFR proved otherwise.

Where external pools land in this picture

The HikariCP and Commons DBCP comparisons run against published benchmark configurations to establish a public reference point. The platform does not use them in production — the design constraints below mean they cannot serve the platform's request path — and the team rebuilds the in-house pool rather than depending on an external one.

  • HikariCP single-pool throughput : excellent. HikariCP wins the one-pool benchmark by every measure ; the team explicitly modelled Pool V2's thread-local tier on HikariCP's. The gap surfaces only when a process runs hundreds or thousands of pools instead of one.
  • Thousand-pool overhead : prohibitive. A HikariCP pool carries its own house-keeping thread, scheduled executor and metric registry. At 3,000 pools that means 3,000 threads doing periodic work — the JVM grinds before the database does. Pool V2 shares a single per-server executor across all pools that target the same database server.
  • User-tracking constraint. External pools assume the pool's identity is the connection's identity. The platform's row-level security expressions, audit trail and database-side connect-time triggers all key off the end-user identity ; sharing a connection across users would compromise all three. This is the architectural constraint, not a configuration knob.

The previous in-house pool's years in production gave the team the measurement substrate to know what mattered : where lock contention spiked, where scavenger pressure cost p999, where memory grew per pool. Pool V2 ships the answers as architecture.

See the feature →

← All posts