Skip to main content
Version: 7.2505.x.x LTS

Detailed description of parameters of connection pools, and how to set them up for efficiency

Parameter settings for efficiency and performance improvement

Balancing throughput and resource utilization: minPoolSize and maxPoolSize

minPoolSize is called database.connection.pool.size.min, maxPoolSize is called database.connection.pool.size.max in the nevisidm-prod.properties.

The optimal sizing of the connection pool, primarily governed by minPoolSize and maxPoolSize, is a critical determinant of application performance and resource consumption.

minPoolSize ensures that a baseline number of connections are always available, which can significantly reduce the latency for initial requests, particularly during bursty load patterns or application startup. However, setting this value too high means consuming valuable database resources even during periods of low activity.

maxPoolSize serves as a vital safeguard, preventing the application from overwhelming the database with an excessive number of concurrent connections. An inadequately low maxPoolSize can lead to PoolExhaustedException and application bottlenecks, as the system cannot acquire enough connections to meet demand. Again, an excessively high value for maxPoolSize risks causing "connection storms" and resource exhaustion (memory, CPU) on both the application and database servers, ultimately degrading performance. The objective is to set maxPoolSize to comfortably accommodate peak demand without oversubscribing the database.

The approach taken by Atomikos, allowing for dynamic growth within defined minPoolSize and maxPoolSize bounds, offers a degree of elasticity, enabling connections to scale on demand up to a configured maximum. This contrasts with a philosophy that advocates for strictly static connection pools to prevent "connection storms", as suggested in some database contexts.

Managing responsiveness: borrowConnectionTimeout

borrowConnectionTimeout is called database.connection.borrow.connection.timeout in the nevisidm-prod.properties.

This parameter directly dictates how long an application thread will block and wait for a connection to become available in the pool when it is currently empty or exhausted. A shorter timeout value leads to faster failure, typically by throwing a PoolExhaustedException, which prevents application threads from blocking indefinitely.

A longer timeout might provide sufficient time for the pool to grow (up to maxPoolSize) or for existing connections to be returned, potentially avoiding an immediate exception. However, this carries the inherent risk of application threads hanging for extended periods, which can lead to cascading timeouts throughout the system and a degraded user experience.

Optimizing connection lifecycle: maxIdleTime and maxLifetime

maxIdleTime is called database.connection.max.idle.time, maxLifetime is called database.connection.max.lifetime in the nevisidm-prod.properties.

These two parameters are crucial for managing the lifecycle of connections within the pool, contributing to both resource efficiency and long-term stability.

maxIdleTime enables the connection pool to dynamically shrink during periods of low activity. By closing "excess" connections (connections that have been opened above the minPoolSize limit and have remained idle for longer than maxIdleTime), the pool conserves database resources and memory. This is particularly beneficial for applications with fluctuating or unpredictable load patterns, as it prevents the unnecessary retention of resources.

maxLifetime is a best practice to prevent issues that can arise from very long-lived connections, such as database-side timeouts or network disruptions that render connections unusable. It contributes significantly to the long-term stability and overall health of the connection pool by ensuring a regular turnover of physical connections. Setting a non-zero maxLifetime ensures that connections are periodically refreshed.

Ensuring connection health: testQuery

testQuery is called database.connection.test.query in the nevisidm-prod.properties.

Configuring an appropriate testQuery, like select 1 from DUAL or a database-specific lightweight query, is a best practice to validate the liveness and usability of a connection before it is handed out from the pool to the application. This proactive check prevents the application from attempting operations on a stale or broken connection, thereby significantly improving overall reliability.

Best practices for Atomikos connection pool management

Effective management of Atomikos connection pools extends beyond initial configuration and involves continuous monitoring, iterative tuning, and adherence to robust development practices.

Strategies for optimal pool sizing

Achieving optimal pool sizing is an iterative process that requires a deep understanding of the application's workload and the database's capabilities.

Workload assessment: Before configuring, it is imperative to assess the application's workload. This includes understanding average and peak concurrent requests, the nature of transactions (e.g., read-heavy versus write-heavy), and the complexity of database queries.

Iterative tuning: It is advisable to start with sensible defaults or a conservative initial maxPoolSize (e.g., following guidelines such as approximately 10 processes per CPU core on the database server for static pools). Subsequently, parameters should be iteratively adjusted based on rigorous performance monitoring and testing in environments that closely mimic production.

Continuous monitoring: Implement robust monitoring of key connection pool metrics, such as connection wait time, pool utilization, and active connections. Equally crucial is monitoring database-side metrics, including CPU utilization, active sessions, lock contention, and specific wait events. High wait times for connections often signal that maxPoolSize is too low or that connection leaks are occurring. A healthy database CPU utilization, such as Oracle's recommended 90/10 ratio of %user to %system CPU utilization, should be targeted. Optimal pool settings are highly fluid, influenced by evolving application load profiles, changes in database performance, and underlying infrastructure modifications. Effective, real-time monitoring provides the crucial data necessary to identify when adjustments are required, enabling proactive tuning to maintain peak performance and stability. Without this continuous loop, even a perfectly configured pool can quickly become a bottleneck as system conditions change, leading to resource wastage or performance degradation.

Consider static vs. dynamic: While Atomikos supports dynamic sizing within minPoolSize and maxPoolSize bounds, for highly stable and predictable loads, a fixed poolSize (setting minPoolSize equal to maxPoolSize) can offer more predictable performance and help prevent the "connection storm" issues associated with unconstrained dynamic growth.

Effective connection validation and health checks

testQuery: It is a critical best practice to configure a lightweight testQuery to validate the liveness and usability of a connection before it is returned from the pool to the application. This prevents the application from encountering stale or broken connections, significantly improving application reliability.

maxLifetime: Set a non-zero maxLifetime to ensure that connections are periodically refreshed. This proactive measure helps mitigate issues that can arise from very long-lived connections, such as database-side timeouts, network disruptions, etc.

Monitoring key connection pool metrics

Comprehensive monitoring provides the necessary data for informed tuning decisions.

Pool size metrics: Regularly track availableSize() (connections ready for use) and totalSize() (all connections) of the pool. These metrics offer immediate insights into pool utilization and can help identify when the pool is approaching exhaustion.

Connection wait times: Monitor the time application threads spend waiting for a connection. Consistently high wait times are a strong indicator of a bottleneck, suggesting that maxPoolSize might be too low or that connection leaks are occurring.

Database-side metrics: Crucially, monitor the database itself. Key metrics include database CPU utilization, the number of active sessions, lock contention, and specific wait events (e.g., latches, enqueues). These provide a holistic view of database health and how it is impacted by the application's connection demands.

Atomikos logging: Enable and regularly review Atomikos' internal logging for detailed insights into pool operations, transaction lifecycle events, and potential issues.

Database placement and its impact on connection pooling

The physical and logical placement of the database relative to the application server significantly influences connection pool configuration and overall system throughput.

Physical placement: local vs. remote database latency

Increased latency: Accessing a database situated on a different physical server or through a managed cloud service introduces significant network latency compared to a database residing on the same server or accessible via a local port. This is because each database request involves network round trips to an external server.

Impact on connection holding time: Higher network latency means that each individual database operation takes a longer time. Consequently, connections are held for extended durations by the application. This effectively reduces the number of "available" connections in the pool at any given moment, increasing the likelihood of pool exhaustion even if the maxPoolSize is seemingly adequate for a low-latency environment. Even if a connection is technically "available" in the pool, if the round-trip time for a database query is high, that connection is effectively "busy" or "occupied" for a longer duration from the application's perspective. This means that for a given maxPoolSize, a high-latency environment will experience connection pool exhaustion or high connection wait times much sooner than a low-latency one, precisely because connections are held for extended periods. This fundamental impact necessitates a re-evaluation of maxPoolSize and borrowConnectionTimeout in such environments. This could lead to a smaller maxPoolSize to prevent overwhelming the database with slow requests, or a larger minPoolSize to pre-establish connections and mitigate the effect of initial latency.

Tuning implications: In high-latency environments, a larger minPoolSize might be considered to pre-establish more connections, thereby absorbing some of the initial connection overhead and ensuring a baseline of readily available connections. However, this must be carefully balanced against the increased resource consumption on both the application and database servers. Conversely, maxPoolSize might need to be more tightly constrained to prevent overwhelming the database with too many concurrent, slow-running requests, which can exacerbate connection storms.

Adjusting pool settings for high-latency environments

Specific parameter adjustments are often necessary when operating in high-latency environments.

borrowConnectionTimeout: In high-latency scenarios, the borrowConnectionTimeout may need to be adjusted upwards to account for the increased network round-trip times. A longer timeout can prevent premature PoolExhaustedExceptions, allowing more time for connections to be established or returned. However, this must be balanced against the desired user experience and application responsiveness.

testQuery: Frequent execution of testQuery can add significant overhead in high-latency environments due to the additional network round trips.

maxLifetime: This parameter becomes even more critical in high-latency environments. It ensures that connections are periodically refreshed, mitigating the risk of connections becoming stale or unusable due to prolonged network instability or infrequent use over long periods.