slaltats/Tomcat

Tomcat Performace Tunning

단순대왕 2012. 9. 18. 17:58

I've been working with Apache Tomcat for years and always seem to stumble upon new information related to the proper setup and configuration for a production environment. I've decided to put the instructions and tips I've collected together in one place.

So here are some helpful hints for running Tomcat in a production environment:

1. If you're running on a 1.5+ JVM...

Add the following to your JAVA_OPTS in catalina.sh (or catalina.bat for Windows): -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/j2ee/heapdumps Then use a tool such asYourKit to analyze the heapdump file.

2. When using Jasper 2 in a production Tomcat server you should consider...

Straight from the Tomcat documentation on Jasper 2...

When using Jasper 2 in a production Tomcat server you should consider making the following changes from the default configuration. development: To disable on access checks for JSP pages compilation set this to falsegenStringAsCharArray: To generate slightly more efficient char arrays, set this to true.modificationTestInterval: If development has to be set to true for any reason (such as dynamic generation of JSPs), setting this to a high value will improve performance a lot. trimSpaces: To remove useless bytes from the response, set this to true.

3. Use Tomcat's clustering/session replication capability.

Use Tomcat's clustering/session replication capability to minimize application user impact during maintenance periods.

4. Implement custom error pages

To hide raw exception messages from the users. To do this, simply add something like the following to your web.xml:

<error-page>
   <error-code>404</error-code>
   <location>/error/404.html</location>
</error-page>

5. Use a logging toolkit.

Eliminate System.out and System.err statements from application code and use a logging toolkit such as Log4J for application logging.

6. Leverage Tomcat's shared library directory.

If you're loading several applications with several of the same library dependencies, consider moving them from the applications' WEB-INF/lib directory to Tomcat's shared library{catalina.home}/shared/lib. This will reduce the memory used by each application and result in smaller WAR files.

Update (comments from the user@tomcat.apache.org mailing list): The following should be considered when using the shared library directory: 1. The shared classloader is searched in last resort when looking for classes, according to http://tomcat.apache.org/tomcat-5.5-doc/class-loader-howto.html. 2. Because the classes are shared, they share configuration and singletons and if they store objects statically they will prevent your application from unloading.

This is turning out to be a more controversial suggestion...

Starting with Servlet Spec 2.3 (I think) there has been an emphasis on putting everything a web app needs to run into its war file.

Shared classloaders are evil, but not as evil as the invoker servlet. With a shared loader you can easily get Singleton assumptions being wrong, class cast exceptions, versioning woes, and other issues. Saving a little perm memory just doesn't justify it.

7. Tweak memory parameters.

Most of the time you will want to make a change to the default settings. The best advice here is to create a development environment that matches your production environment and load test the application. While you do this you can also use a profiler to identify bottlenecks, etc.

8. Remove unnecessary applications.

9. Secure the Manager application.

By default there are no users with the manager role. To make use of the manager webapp you need to add a new role and user into the CATALINA_HOME/conf/tomcat-users.xml file.

10. Use a valve to filter by IP or hostname to only allow a subset of machines to connect.

This can be configured at the Engine, Host, or Context level in the conf/server.xml by adding something like the following:

<!-- allow only LAN IPs to connect to the manager webapp -->
<!-- contrary to the current Tomcat 5.5 documation the value for 'allow' is not a regular expression -->
<!-- future versions may have to be specified as 192.168.1.* -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="192.168.1.*"></Valve>

11. Strip down server.xml.

By removing comments to make it easier to read and remove connectors that you don't need. An easy way to do this is the following: Rename CATALINA_HOME/conf/server.xml toCATALINA_HOME/conf/server-original.xml and rename CATALINA_HOME/conf/server-minimal.xml to CATALINA_HOME/conf/server.xml. The minimal configuration provides the same basic configuration, but without the nested comments is much easier to maintain and understand. Do not delete the original file as the comments make it useful for reference if you ever need to make changes. Unless you are using Tomcat with the Apache server, comment out this line in CATALINA_HOME/conf/server.xml:

<Connector port="8009" enableLookups="false" redirectPort="8443" protocol="AJP/1.3"></Connector>

12. Split your Tomcat installation for added flexibility when it comes time to upgrade Tomcat.

See the "Advanced Configuration - Multiple Tomcat Instances" section in the RUNNING.txt file of the Tomcat distribution.

14. Do NOT run Tomcat as root.

Look to my previous post, "3 Ways to Run a Servlet Container on Port 80 as Non-Root", for tips.

15. Precompile JSPs.

Precompile JSPs (at build time).

16. Secure directory listings.

In CATALINA_HOME/conf/web.xml:

<servlet>
   <servlet-name>default</servlet-name>
   <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
   <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
   </init-param>
   <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>  <!-- make sure this is false -->
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>

17. If you have multi-core CPUs or more than one CPUs on your server...

It might be beneficial to increase the thread pool beyond the default 250. On the other hand, if you have a slow server, decreasing the thread pool will decrease the overhead on the server.

18. Monitor application applications via Tomcat MBeans.

This article provides some great insight on how to do this.

Consider JDK 1.5 or even better JDK 1.6

To take advantage of performance improvements.

Update (comments from users@tomcat.apache.org mailing list):

Note that you can gain even more performance if you recompile your "string concatenation hungry" (d="aaaa"+b+"ccc") support libraries for JDK 5+ on a multi-CPU system. This is because JDK 5 uses the non-synchronized StringBuilder instead of the JDK 4- synchronized StringBuffer. And synchronization over multiple CPUs takes a few more cycles than on single CPU machines.

19. Use the -server JVM option.

This enables the server JVM, which JIT compiles bytecode much earlier, and with stronger optimizations. Startup and first calls will be slower due to JIT compilation taking more time, but subsequent ones will be faster.

20. Use GZIP compression.

Look for the service connector you wish to configure for compression and add two attributes, compression and compressableMimeType. For example:

<Connector>
   port="80"
   maxHttpHeaderSize="8192"
   URIEncoding="UTF-8"
   maxThreads="150"
   minSpareThreads="25"
   maxSpareThreads="75"
   enableLookups="false"
   redirectPort="8443"
   acceptCount="100"
   connectionTimeout="20000"
   disableUploadTimeout="true"
   compression="on"
   compressableMimeType="text/html,text/xml,text/plain,application/xml">
</Connector>

For more information, read the Tomcat HTTP Connector documentation.

The default Tomcat configuration provides good protection for most requirements, but does not prevent a malicious application from compromising the security of other applications running in the same instance. To prevent this sort of attack, Tomcat can be run with a Security Manager enabled which strictly controls access to server resources. Tomcat documentation has a good section on enabling the Security Manager.

Who's Using Tomcat in Production

Curious about what other organizations run Tomcat in a production environment? The Tomcat wiki has a list.

Update: If you're running with Java 6 JVM, I found this great resource which gives a complete list of -XX options. This is helpful if you're doing performance tweaking for your environment or debugging an issue with your system.



Introduction
Think about this situation, you had developed an application which contains excellent layout, latest features and all the other things which relishes the application. But if it lacks in performance means, No matter what surely the application will be rejected by the customers. Customers always expect their application should have a better performance. If you used Tomcat server for your production, then this article gives you some aspects to improve the performance of the Tomcat Server. Thanks for the resources provided in this ITWorld article. After pondering the net I had understand that the latest release of Tomcat gives the better performance and stability when compared to Old version. So always use the latest version of Tomcat. Now in this article, the following steps are used to improve the performance of the tomcat server,

  1. Increase JVM heap memory
  2. Resolve JRE memory leaks
  3. Thread pool setting
  4. Compression
  5. Database performance tuning
  6. Tomcat Native Library
  7. Other options

Step 1 – Increase JVM heap memory
If you had used tomcat, definitely you would have heard about “Permgen Space” error. Simply said “OutOfMemoryError”. Mostly this error will occur in the production environment. The reason for this error is tomcat has very small memory for the running process, this error can be resolved by doing some changes in the Tomcat configuration file named “catalina.bat(In windows)/catalina.sh(In Linux)”. The changes to be made is to increase the JVM heap memory. That is , the JVM does not invoke the garbage collector often, so the server can focus more in serving web requests and the requests are completed faster. The file(catalina.sh) to be changed is located at “\tomcat server folder\bin\catalina.sh” and the configuration to be made in this file is given below,

1JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8
2-server -Xms1024m -Xmx1024m
3-XX:NewSize=512m -XX:MaxNewSize=512m -XX:PermSize=512m
4-XX:MaxPermSize=512m -XX:+DisableExplicitGC"

-Xms – Specifies the initial heap memory
-Xmx – Specifies the maximum heap memory
The changes will gets activated, Once you restart the Tomcat Server. Next we shall see how to handle the memory leak,

Step 2 – Resolve JRE memory leaks
Another main reason for the performance lack is memory leak, as I said before always use the latest tomcat server to get better performance and scalability. Now the phrase becomes true. This error can be resolved if we use the latest tomcat server version 6.0.26 and above. Since it contains a listener to handle the JRE and permgen memory leak. The listener used here is,

1<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />

You can find the above listener class configuration in the server.xml file which resides in “tomcat project folder/conf/server.xml”. Next we shall see how to tune the connector attribute “maxThreads”.

Step 3 – Thread pool setting
Thread pool specifies the number of web request load that comes in, So this part should be handled carefully in order to get the better performance. This can be accomplished by tuning the connector attribute“maxThreads”. The value of the maxThreads should be based on the volume of the traffic. If the value is low, then there will not be enough threads to handle all of the requests, so it undergoes in to the wait state and comes back only when an another request thread gets freed. If we set maxThreads value too high means then the Tomcat startup time will take longer. So its up to us, Put a right value in the maxThreads.

1<Connector port="8080" address="localhost"
2maxThreads="250" maxHttpHeaderSize="8192"
3emptySessionPath="true" protocol="HTTP/1.1"
4enableLookups="false" redirectPort="8181" acceptCount="100"
5connectionTimeout="20000" disableUploadTimeout="true" />

In the preceding configuration, maxThreads value is given as “250″. This specifies the maximum number ofsimultaneous requests that can be handled by the server. If not specified, the default value of this attribute “200″. Any further simultaneous requests will receive “connection refused” errors until the another request gets freed. The error looks like the below,

1org.apache.tomcat.util.threads.ThreadPool logFull SEVERE: All threads (250) are
2currently busy, waiting. Increase maxThreads (250) or check the servlet status

If  the application results in the above error, Always investigate whether the above error caused by a single request that takes too long. The reason is, Sometimes if the database connection is not released means, it will not allow to process additional request.

Note: If the number of request exceeds “750″ means, Instead of setting the value “750″ in the maxThreads attribute, Its better to go for the “Tomcat Clustering” with multiple tomcat instances. That is, In the case of “1000″ request,  set “maxThreads=500″ for the two instances of tomcat,  Instead of a single Tomcat with maxThreads=1000.

According to my perspection, the exact value can be determined only by testing the application in various environment. Next we shall see how to compress the mime types.

Step 4 – Compression
Tomcat has an option to compress the mime-types by doing some configuration in the server.xml file. This compression should be done in the connector like the below,

1<Connector port="8080" protocol="HTTP/1.1"
2connectionTimeout="20000"
3redirectPort="8181" compression="500"
4compressableMimeType="text/html,text/xml,text/plain,application/octet-stream" />

In the preceding configuration, the files will be compressed when the number of bytes is >= 500. If the files not to be compressed by the size means, Set the attribute compression=”on”. Otherwise the default the setting in Tomcat is “off”. Next we shall see, How to tune the database.

Step 5- Database performance tuning
Tomcats performance gets lacked while waiting for the database queries to get executed. Nowadays most of the application uses Relational databases, which may contains “NamedQueries”.  If so, by default the tomcat will load the named queries initially, this may increase the performance. Another important thing is, always ensure that all the database connections are closed properly. Also setting the correct value in the database connection pool is very essential. I mean the values in maxIdle, maxActive, and maxWait attributes of the Resource element. Since the configuration depends on the application requirements, I cannot specify the right values in this article. You can find the correct values by invoking the performance testing for the database.

Step 6 – Tomcat Native Library
Tomcat native library, “Apache Portable Runtime(APR)” provides superior scalability, performance and better integration with the native server technologies and gives optimal performance in the production environment. The installation steps is explained in the article Tomcat Native Library – (APR) Installation.

Step 7 – Other options
Some of the other options are,

  • Enable the web browser cache, so that the static content which resides in the webapps folder loads faster, By doing this the performance is greatly increased.
  • Tomcat server should be automatically restarted, whenever the machine starts.
  • Normally HTTPS request is slow when compared to the HTTP request. But what ever if you want some good security for the application means, we should prefer HTTPS instead of HTTP.

Thats all folks. In this article I have given some stuffs to improve the Tomcat server performance. If you find this article is useful to you or if you have any other options to improve the performance, dont forget to leave your valuable comments. Have a joyous code day.