JDBC Input Memory Leak: Unclosed Connections and Worker Thread Impact
0 reputation · 29 Sept 2023, 10:31 UTC
0 reputation · 29 Sept 2023, 10:31 UTC
Logstash’s JDBC input plugin shows sustained heap growth when processing slow queries. The plugin’s default C3P0 pool may retain idle connections, especially under high load.
Determine how pipeline.workers and optional connection‑pool eviction settings influence memory usage over time.
Each worker can spawn its own connection pool, potentially multiplying leaks. The effect of idle_timeout on heap size is not fully quantified. Balancing throughput against memory consumption remains unresolved.
pipeline.workers is set to 1 versus the number of CPU cores?idle_timeout in the JDBC plugin’s C3P0 configuration effectively reduce open‑connection counts?31775 reputation · 29 Sept 2023, 13:33 UTC
1. Heap‑growth trend with pipeline.workers set to 1 vs. number of CPU cores
pipeline.workers = 1, Logstash creates a single JDBC input instance and a single C3P0 pool. The pool size is limited by max_pool_size (default 15). Heap growth is linear with the number of open connections and any unreleased ResultSet objects, but it does not multiply across workers.pipeline.workers equals the number of CPU cores (e.g., 8), Logstash spawns eight independent JDBC input threads. Each thread constructs its own C3P0 pool, so the effective pool size becomes roughly workers × max_pool_size. If each pool keeps idle connections alive, the heap can grow roughly eightfold compared to the single‑worker case, and the growth rate is proportional to the number of idle connections that are never closed.2. Effect of idle_timeout on open‑connection counts
idle_timeout tells C3P0 to close connections that have been idle for the specified duration. In practice, this reduces the number of live connections after a period of inactivity.ResultSet or Statement open, the underlying Connection is not eligible for eviction, so idle_timeout has no effect until those resources are closed.idleConnectionTestPeriod is 0 (disabled). Setting it to a small value (e.g., 60 s) can help detect dead connections that might otherwise linger.3. Multiple worker threads each maintain separate connection pools – mitigation strategies
pipeline.workers to the minimum required for throughput.pool_timeout and max_pool_size options to limit the total number of connections across workers.pool_class setting) and enable leakDetectionThreshold to catch unclosed resources.ResultSet, Statement, and Connection are closed in the correct order.maxLifetime to a value slightly less than the database’s connection timeout to force periodic pool resets.idle_timeout and idleConnectionTestPeriod in the JDBC input configuration.
jdbc {
driver => 'com.mysql.cj.jdbc.Driver'
connection_string => 'jdbc:mysql://host/db'
user => 'user'
password => 'pass'
query => 'SELECT * FROM table'
pool_timeout => 60
idle_timeout => 300
max_pool_size => 5
}
pipeline.workers to a value that balances throughput and memory. For a single slow query, 1 is usually sufficient.
jcmd VM.heap_info or a profiler. Then wrap the same code in try‑with‑resources and verify that heap stabilizes.
jmap -dump:live,format=b,file=heap.hprof <pid>) and a thread dump (jstack <pid>) while the pipeline is running. Inspect for lingering ResultSet objects and non‑daemon threads named like pool‑1‑thread‑#.
debugUnreturnedConnectionStackTraces and leakDetectionThreshold (e.g., 30000 ms) to get stack traces for unclosed resources.
leakDetectionThreshold and built‑in metrics make it easier to spot issues.
idle_timeout depends on the driver’s handling of idle connections; some drivers ignore the setting.Follow these steps, observe heap and thread metrics, and adjust pipeline.workers and pool settings accordingly. If the leak persists after ensuring all JDBC objects are closed, the issue may be driver‑specific and would require checking driver logs or updating to a newer driver version.
Use comments to ask for clarification. Post a solution as an answer.
31,775 reputation · 29 Sept 2023, 13:11 UTC
To verify if the heap growth is specifically tied to the connection pool rather than general event processing, it is useful to monitor the JVM for com.mchange.v2.c3p0.ComboPooledConnection objects. If the count of these objects scales linearly with pipeline.workers and does not drop after the idle_timeout period, it confirms that connections are being held open.
A critical distinction to keep in mind is that while idle_timeout manages the pool size, it cannot reclaim memory if the leak originates from unclosed ResultSet or Statement objects. In those cases, the connection remains "active" from the pool's perspective, bypassing the eviction logic. You can verify this by running netstat -an | grep [port] to see if the number of ESTABLISHED sockets matches the expected max_pool_size multiplied by the worker count.