Journey of Diagnosing and Fixing "Too Many Connections" Error in a Java Project Using VisualVM and JMX

As a Java developer, I recently faced a "Too many connections" error in a project where JDBC connections were not being closed properly. This caused the application to run out of available connections and prevented new connections from being created, resulting in errors and degraded performance.

At first, I tried the classic approach of restarting the application and database server multiple times, but the problem persisted.

To diagnose and fix the issue, I used VisualVM to monitor the application's performance and identify the root cause of the problem. Here's how I did it:

First, ensure that the Java application is running with the necessary JMX flags enabled. You can do this by adding the following flags to your Java command line options:

-Dcom.sun.management.jmxremote.port=<port_number>
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

Replace <port_number> with the port number that you want to use for JMX connections.

Next, configure your ECS task to allow inbound traffic on the JMX port. To do this, you can add a rule to your task's security group that allows incoming traffic on the JMX port.

Now that your application is ready to accept JMX connections, you can launch VisualVM and connect to it. In VisualVM, click the "Add JMX Connection" button and enter the hostname or IP address of your ECS instance, followed by the JMX port number that you configured earlier.

If your ECS instance is running behind a load balancer or other network device, you may need to configure port forwarding or other network settings to allow VisualVM to connect to it.

After these changes were applied, I used the jmxterm command-line tool to test the JMX connection to the ECS instance:

jmxterm -l <ECS_instance_public_IP>:<port_number>

This command allowed me to verify that the JMX connection was working properly and that I could access the management and monitoring information exposed by the application.

Connection established

Once you have successfully connected to the application, you can use VisualVM to monitor its performance, analyze heap dumps, and capture thread dumps.

First, I launched VisualVM and connected it to the running Java application.

Then, I clicked on the "Profiler" tab and selected the sampling profiling mode, which is a good option for general performance analysis.

Next, I clicked on the "CPU" button to start the profiler and let it run while I performed various operations in the application.

After a few minutes of profiling, I stopped the profiler and analyzed the flame graph to identify any methods that were consuming a disproportionate amount of CPU time.

I noticed that a particular method related to JDBC connection creation and management was taking a lot of CPU time, indicating that there may be an issue with connection handling.

To investigate further, I captured a heap dump using VisualVM and analyzed it using the Heap Dump Browser.

In the Heap Dump Browser, I searched for instances of JDBC connection objects and found that there were a large number of open connections that were not being closed properly.

Armed with this information, I went back to the code and made sure that all JDBC connections were being closed properly using the close() method.

After making the necessary code changes and deploying the new version of the application, I ran it again and monitored it using VisualVM.

This time, I was pleased to see that the number of open connections remained within the expected range, and the "Too many connections" error did not occur.

Overall, VisualVM proved to be an invaluable tool for diagnosing and fixing the "Too many connections" error in this project. By using the profiler and heap dump analysis, I was able to identify the root cause of the problem and make the necessary changes to the code to prevent it from happening again.