Effective optimizaton requires monitoring key performance indicators such as throughput, latency, error rates, thread pool utilization, CPU load, and memory consumption. Load testing tools like JMeter or AB can simulate traffic, while monitoring can be performed using system commands or specialized agents.
System-level analysis often begins with identifying the process ID:
# Identify the Tomcat process
ps -ef | grep tomcat
# Inspect process status
cat /proc/[PID]/status
# Monitor real-time CPU and memory usage
top -p [PID]
For deeper insights, utilize Java diagnostic tools such as JConsole, VisualVM, Arthas, or PSI-Probe to analyze heap usage and thread states.
Core Configuration Optimization (server.xml)
The primary configuration file conf/server.xml contains the components critical to performance. While top-level containers like Server and Service rarely need tuning, the Connector and Executor elements are paramount.
1. Connector Protocol Selection
The protocol attribute dictates the I/O model. In older versions (Tomcat 7 and below), the default was often blocking I/O (BIO). Modern versions default to Non-blocking I/O (NIO) or NIO2, which offer significantly better scalability.
<!-- Explicitly defining NIO2 protocol for modern JDKs -->
<Connector port="8080" protocol="org.apache.coyote.http11.Http11Nio2Protocol"
connectionTimeout="20000"
redirectPort="8443" />
- BIO (Http11Protocol): One thread per connection. Resource-intensive.
- NIO (Http11NioProtocol): Uses poller threads to handle connections non-blocking.
- APR (Http11AprProtocol): Uses native libraries for high performance.
2. Thread Pool and Executor Configuration
To maximize request handling capacity, configure a shared thread pool executor. A general formula for calculating optimal thread count is:
Optimal Threads = ((Wait Time + CPU Time) / CPU Time) * CPU Cores
Defining a custom executor allows beter resource control:
<Executor name="appThreadPool"
namePrefix="http-worker-"
maxThreads="200"
minSpareThreads="25"
maxIdleTime="60000"/>
<Connector executor="appThreadPool"
port="8080"
protocol="HTTP/1.1"
acceptCount="100"
maxConnections="10000"
connectionTimeout="20000" />
- maxThreads: Maximum concurrent request processing threads.
- acceptCount: Queue size for pending connections once maxThreads is reached.
- maxConnections: Total connections the server will accept (NIO default is often 10000).
3. Host and Context Settings
In production environments, disable automatic deployment and class reloading to prevent background resource consumption and classloader leaks.
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
<Context path="" docBase="myapp" reloadable="false"/>
</Host>
- autoDeploy: Set to
falseto stop the server from polling for new applications. - reloadable: Set to
falseto disable monitoring ofWEB-INF/classesfor changes.
Streamlining Deployment (web.xml)
The global conf/web.xml and application-specific descriptors often contain unnecessary configurations. Removing unused servlets, filters, and MIME mappings reduces memory overhead and startup time.
- Remove the
JspServletif the application serves only static content or REST APIs. - Trim the
<welcome-file-list>to only include files that actually exist. - Disable DNS lookups in the
AccessLogValveby ensuringenableLookups="false"(default is usually false, but verifying helps).
Startup Speed Optimization
Slow startups are often caused by unnecessary deployment processes or entropy generation for session IDs.
- Remove Unused Webapps: Delete default applications (ROOT, docs, examples) to prevent automatic deployment scans.
- Entropy Source: On Linux systems, the JVM may block waiting for entropy. Use
/dev/urandomby adding the JVM flag:-Djava.security.egd=file:/dev/./urandom. - Parallel Startup: Use the
startStopThreadsattribute in theHostelement to parallelize application deployment. - Disable Unused Features: Remove WebSocket JARs if the feature is not required.
Troubleshooting Common Issues
High CPU Utilization
Excessive CPU usage is frequently caused by infinite loops, frequent Garbage Collection (GC), or excessive thread context switching.
- Identify high-load threads:
top -H -p [PID] - Convert the thread ID to hexadecimal.
- Dump the stack trace:
jstack [PID] - Analyze the stack trace for the offending thread to locate the bottleneck in the application code.
Connection Failures
- BindException (Address already in use): Indicates port conflict. Use
netstat -tulpnto identify the process holding the port. - SocketException (Too many open files): The system limit for file descriptors has been reached. Increase the limit via
ulimit -n 65535or modify system security limits configuration. - ConnectException (Connection refused): Verify if the Tomcat process is actually running and listening on the expected IP/Port.
Miscellaneous Enhancements
- Compression: Enable GZIP compression in the Connector for text-based responses to reduce bandwidth.
compression="on" minResponseSize="2048". - AJP Connector: If a front-end web server (like Nginx or httpd) is not used, comment out the AJP Connector to free up ports and memory.
- Database: Optimize connection pools and query performance to reduce "Wait Time" in the thread pool formula.