Difference between revisions of "ColdFusion Performance"

From Hostek.com Wiki
Jump to: navigation, search
(Tune Your Queries)
m (added note about increasing G1 Heap Size if there are too many humongous allocations)
 
(20 intermediate revisions by 2 users not shown)
Line 3: Line 3:
 
==JVM Settings==
 
==JVM Settings==
 
===Sizing the Heap===
 
===Sizing the Heap===
A good set of 64-bit JVM arguments to start with (for controlling memory and garbage collection) are below:<pre style="white-space: pre-wrap">java.args=-server -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -XX:+UseCompressedOops -Xms1024m -Xmx1024m -XX:NewSize=64m -XX:MaxNewSize=64m -XX:SurvivorRatio=4 -XX:MaxPermSize=512m -XX:PermSize=512m -XX:+UseParNewGC -Djava.awt.headless=true</pre>
+
====Memory Allocation====
 +
Trying to find the right size for your server's ColdFusion memory heap is an iterative process. However, the following memory allocation arguments will give you a good start: <pre style="white-space: pre-wrap">java.args=-server -XX:+UseCompressedOops -XX:+DisableExplicitGC -Xms1024m -Xmx2048m -XX:NewSize=256m -XX:MaxNewSize=512m -XX:SurvivorRatio=8 -XX:PermSize=128m -XX:MaxPermSize=512m</pre>
  
Those settings specify a maximum ColdFusion heap of 1 GB (1024 MB), an Eden space of 64 MB, and a non-heap Perm space of 512 MB. If your application needs a bit more memory, you can adjust the "-Xmx" and "-Xms" values as needed. A good rule of thumb though is to set them to the same value as each other to help improve ColdFusion perform better. More info on tuning the JVM can be found in this article, but the recommended JVM settings above are great for most ColdFusion applications: [http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html Java Garbage Collection Tuning]
+
''Note: The above arguments only control memory allocation. You should still retain any garbage collector and class-related arguments.''
  
===Garbage Collection Performance===
+
The settings shown above specify a maximum ColdFusion heap of 2 GB ''(2048 MB)'', an Eden/New space ''(where Java creates new objects)'' that starts at 256 MB and can grow to 512 MB, and a non-heap Perm space with a maximum of 512 MB. If your application needs a bit more memory, you can adjust the "-Xmx" and "-Xms" values as needed. Setting the maximum heap argument ''(-Xmx)'' to a value higher than the minimum heap argument ''(-Xms)'' will allow ColdFusion to utilize more RAM during times of peak activity. This will increase startup time slightly, but it gives the server more stability when your sites are busy.
Because a lot of the JVM's processing time can be spent in garbage collection of memory, it can be helpful to enable Garbage Collection Logging to your server. In order to do so, just add the following arguments to your ColdFusion server's ''jvm.config'' file: <pre style="white-space: pre-wrap">-verbose:gc -Xloggc:gc-1.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps</pre>
+
 
 +
====Choosing a Garbage Collector====
 +
After specifying good memory settings for your ColdFusion server, you'll want to ensure it uses an appropriate garbage collector for the work being done on your sites.
 +
=====Mostly Concurrent Collector=====
 +
If the sites on your server are primarily lightweight request/response applications where response times are critical, then the ''mostly'' concurrent garbage collector is a great choice for your server. This collector does its best to collect dead objects from memory while applications on the server are still processing data. This adds a small bit of overhead for transactional applications, but it helps such applications maintain their response-time SLAs. To enable this garbage collector, add the following JVM arguments after your memory allocation settings: <pre style="white-space: pre-wrap">-XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled -XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68 -XX:+UseParNewGC</pre>
 +
 
 +
''Note:'' The main downside of this collector is that it can consume too much CPU when memory-intensive applications run on the server. Servers running such applications would want to use the ''throughput collector'' mentioned below.
 +
=====Throughput/Parallel Collector=====
 +
If the applications on your server are memory intensive and allocate a lot of objects, then the throughput/parallel garbage collector would be a great choice for your server. Any application performing image manipulation or creating a lot of objects would be a great candidate for the throughput collector. To enable this garbage collector, add the following JVM arguments after your memory allocation settings: <pre style="white-space: pre-wrap">-XX:+UseParallelOldGC -XX:YoungGenerationSizeIncrement=50 -XX:TenuredGenerationSizeIncrement=25 -XX:AdaptiveSizeDecrementScaleFactor=10 -XX:MaxGCPauseMillis=10000 -XX:GCTimeRatio=19</pre>
 +
 
 +
The first thing to note about this collector is the ''-XX:+UseParallelOldGC'' name. This doesn't mean you're using old garbage collection techniques; rather it mean that both the ''old'' (or ''tenured'') and the ''new'' (or ''eden'') sections of memory are collected in parallel. This allows Java to perform collections much faster than normal. One thing to keep in mind is that with this collector when the heap fills up Java will pause all application processing for a short period of time to clean up memory. The above settings act to minimize the time of such pauses so your end users typically won't notice any slowness.
 +
 
 +
=====Garbage First Garbage Collector=====
 +
If you are running the latest Java 8 JVM on your servers, you can take advantage of G1GC. G1GC was introduced before Java 8; however unless you have a support contract with Oracle for Java 7, Oracle only recommends using it with Java 8. This garbage collector works best on larger heaps (3GB+). The goal off this collector is to reduce GC pauses by doing more collections and marking objects concurrently with the running application. To enable this garbage collector, add the following JVM arguments after your memory allocation settings: <pre style="white-space: pre-wrap">-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2</pre> You will want to to make ParallelGCThreads to the number of cores you have and make ConcGCThreads half of ParallelGCThreads. You may also need to adjust the G1 Heap Size manually if you notice too many "humongous" allocations.
 +
 
 +
You will notice more CPU being used by this collector, but you should notice better performance with less latency between requests. This collector uses ~2048 regions of memory instead of 4 regions of memory. Oracle's documentation explains this is great detail at http://www.oracle.com/technetwork/articles/java/g1gc-1984535.html
 +
 
 +
====References====
 +
*Tuning ColdFusion 10 for performance and stability: [http://cfwhisperer.com/post.cfm/coldfusion-10-enhanced-performance-settings ColdFusion 10 Enhanced Performance Settings]
 +
*Optimizing Garbage Collection Pause Times: [http://wouterzelle.wordpress.com/2008/07/28/advanced-java-memory-tuning/ Advanced Java Memory Tuning]
 +
*Oracle Java Garbage Collection Tuning Guidelines: [http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html Java Garbage Collection Tuning]
 +
 
 +
===Garbage Collection Performance Logging===
 +
Because a lot of the JVM's processing time can be spent in garbage collection of memory, it can be helpful to enable Garbage Collection Logging to your server. In order to do so, just add the following arguments to your ColdFusion server's ''jvm.config'' file: <pre style="white-space: pre-wrap">-Xloggc:gc-1.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps</pre>
  
 
If you wish to change the name of the log file, just change 'gc-1.log' to the filename you wish. By default, this file will be created in the same folder as your ''jvm.config'' file.
 
If you wish to change the name of the log file, just change 'gc-1.log' to the filename you wish. By default, this file will be created in the same folder as your ''jvm.config'' file.
 +
<br><br>''If Using Railo'': When using Railo it's more reliable to specify a full path to the GC log file like this:
 +
    -Xloggc:C:\railo\gc-1.log
 
<br />
 
<br />
 
<br />
 
<br />
Line 17: Line 43:
 
==Tuning the Database Tier==
 
==Tuning the Database Tier==
 
===Add Indexes===
 
===Add Indexes===
Make sure all database fields are indexed properly, adding indexes for any columns used in a WHERE clause.  
+
Make sure all database fields are indexed properly. At the minimum your tables should have a primary (unique) key and indexes for any columns used in a WHERE clause.  
 +
 
 +
For your reference, this video from Percona describes how to make the most of table indexes: [https://www.youtube.com/watch?v=zeRqU0SlJa4 MySQL Indexing Best Practices]
 +
 
 
===Tune Your Queries===
 
===Tune Your Queries===
 
Be sure to remove any 'SELECT *' statements in the code. Instead, explicitly name each column used in a query. Also, make use of query advisors such as the following:
 
Be sure to remove any 'SELECT *' statements in the code. Instead, explicitly name each column used in a query. Also, make use of query advisors such as the following:
#'''MySQL - Percona Query Advisor''': https://tools.percona.com/query-advisor
+
*'''MySQL - Percona Query Advisor''': https://tools.percona.com/query-advisor
#'''MS SQL Server - Database Engine Tuning Advisor''': http://www.mssqltips.com/sqlservertutorial/286/database-engine-tuning-advisor/
+
*'''MS SQL Server - Database Engine Tuning Advisor''': http://www.mssqltips.com/sqlservertutorial/286/database-engine-tuning-advisor/
  
 
===Cache Queries (cfquery / cfstoredproc) Where Possible===
 
===Cache Queries (cfquery / cfstoredproc) Where Possible===
Does your application have queries that could be cached? If so, enable caching on those queries as shown here: [http://www.coldfusionmuse.com/index.cfm/2010/9/19/safe.caching Good Developers Practice Safe Query Caching]
+
Does your application have queries that are ran often and the data rarely changes? If so, enable caching on those queries as shown here: [http://www.coldfusionmuse.com/index.cfm/2010/9/19/safe.caching Good Developers Practice Safe Query Caching]
  
 
The main takeaway is that your application should use the '''cachedwithin''' attribute on as many cfquery and cfstoredproc tags as possible. Query caching helps reduce the load on the database server and  improves page response time noticeably.
 
The main takeaway is that your application should use the '''cachedwithin''' attribute on as many cfquery and cfstoredproc tags as possible. Query caching helps reduce the load on the database server and  improves page response time noticeably.
  
To enable this attribute on your queries, just add the '''cachedwithin''' attribute to your cfquery or cfstoredproc tags. This example will cache a query for 1 hour 15 minutes:<pre><cfquery name="myquery" datasource="mydsn" cachedwithin="#createTimespan(0,1,15,0)#"></pre>
+
To enable this attribute on your queries, just add the '''cachedwithin''' attribute to your cfquery or cfstoredproc tags. This example will cache a query for 15 minutes:<pre><cfquery name="myquery" datasource="mydsn" cachedwithin="#createTimespan(0,0,15,0)#"></pre>
 +
''Note'': It is not recommended to cache queries for very long periods of time, so try to keep the timespan to an hour or less.
  
 
==Preventing Known Memory 'Leaks'==
 
==Preventing Known Memory 'Leaks'==
Line 44: Line 74:
 
During non-peak hours for your site, try enabling the ColdFusion debug output and adding your IP to the remote debug IP list. Then load the most frequently accessed pages and grab the debug output. Once you have this, focus on improving the slowest sections of code first.  
 
During non-peak hours for your site, try enabling the ColdFusion debug output and adding your IP to the remote debug IP list. Then load the most frequently accessed pages and grab the debug output. Once you have this, focus on improving the slowest sections of code first.  
  
Additionally, if you have '''Seefusion''' on your VPS, it will hightlight the server's slowest scripts. You can also obtain stack traces of running scripts to find the root cause of any slowness.
+
Additionally, if you have '''Seefusion''' on your VPS, it will hightlight the server's slowest scripts. You can also obtain stack traces of running scripts to find the root cause of any slowness. <br />
 +
'''More info''': [[ColdFusion_Tips_%26_Tricks#Using_SeeFusion_to_Monitor_ColdFusion_Performance_on_a_VPS.2FDedicated_Server|Using SeeFusion to Monitor ColdFusion Performance on a VPS/Dedicated_Server]]
 
<br />
 
<br />
 
<br />
 
<br />

Latest revision as of 17:57, 17 December 2015

When analyzing ColdFusion's performance, There are several things to keep in mind including JVM (memory) settings, slowness on the database tier, and memory leaks that can be easily avoided.

JVM Settings

Sizing the Heap

Memory Allocation

Trying to find the right size for your server's ColdFusion memory heap is an iterative process. However, the following memory allocation arguments will give you a good start:
java.args=-server -XX:+UseCompressedOops -XX:+DisableExplicitGC -Xms1024m -Xmx2048m -XX:NewSize=256m -XX:MaxNewSize=512m -XX:SurvivorRatio=8 -XX:PermSize=128m -XX:MaxPermSize=512m

Note: The above arguments only control memory allocation. You should still retain any garbage collector and class-related arguments.

The settings shown above specify a maximum ColdFusion heap of 2 GB (2048 MB), an Eden/New space (where Java creates new objects) that starts at 256 MB and can grow to 512 MB, and a non-heap Perm space with a maximum of 512 MB. If your application needs a bit more memory, you can adjust the "-Xmx" and "-Xms" values as needed. Setting the maximum heap argument (-Xmx) to a value higher than the minimum heap argument (-Xms) will allow ColdFusion to utilize more RAM during times of peak activity. This will increase startup time slightly, but it gives the server more stability when your sites are busy.

Choosing a Garbage Collector

After specifying good memory settings for your ColdFusion server, you'll want to ensure it uses an appropriate garbage collector for the work being done on your sites.

Mostly Concurrent Collector
If the sites on your server are primarily lightweight request/response applications where response times are critical, then the mostly concurrent garbage collector is a great choice for your server. This collector does its best to collect dead objects from memory while applications on the server are still processing data. This adds a small bit of overhead for transactional applications, but it helps such applications maintain their response-time SLAs. To enable this garbage collector, add the following JVM arguments after your memory allocation settings:
-XX:+UseConcMarkSweepGC -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled -XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68 -XX:+UseParNewGC

Note: The main downside of this collector is that it can consume too much CPU when memory-intensive applications run on the server. Servers running such applications would want to use the throughput collector mentioned below.

Throughput/Parallel Collector
If the applications on your server are memory intensive and allocate a lot of objects, then the throughput/parallel garbage collector would be a great choice for your server. Any application performing image manipulation or creating a lot of objects would be a great candidate for the throughput collector. To enable this garbage collector, add the following JVM arguments after your memory allocation settings:
-XX:+UseParallelOldGC -XX:YoungGenerationSizeIncrement=50 -XX:TenuredGenerationSizeIncrement=25 -XX:AdaptiveSizeDecrementScaleFactor=10 -XX:MaxGCPauseMillis=10000 -XX:GCTimeRatio=19

The first thing to note about this collector is the -XX:+UseParallelOldGC name. This doesn't mean you're using old garbage collection techniques; rather it mean that both the old (or tenured) and the new (or eden) sections of memory are collected in parallel. This allows Java to perform collections much faster than normal. One thing to keep in mind is that with this collector when the heap fills up Java will pause all application processing for a short period of time to clean up memory. The above settings act to minimize the time of such pauses so your end users typically won't notice any slowness.

Garbage First Garbage Collector
If you are running the latest Java 8 JVM on your servers, you can take advantage of G1GC. G1GC was introduced before Java 8; however unless you have a support contract with Oracle for Java 7, Oracle only recommends using it with Java 8. This garbage collector works best on larger heaps (3GB+). The goal off this collector is to reduce GC pauses by doing more collections and marking objects concurrently with the running application. To enable this garbage collector, add the following JVM arguments after your memory allocation settings:
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+ParallelRefProcEnabled -XX:+AggressiveOpts -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2
You will want to to make ParallelGCThreads to the number of cores you have and make ConcGCThreads half of ParallelGCThreads. You may also need to adjust the G1 Heap Size manually if you notice too many "humongous" allocations.

You will notice more CPU being used by this collector, but you should notice better performance with less latency between requests. This collector uses ~2048 regions of memory instead of 4 regions of memory. Oracle's documentation explains this is great detail at http://www.oracle.com/technetwork/articles/java/g1gc-1984535.html

References

Garbage Collection Performance Logging

Because a lot of the JVM's processing time can be spent in garbage collection of memory, it can be helpful to enable Garbage Collection Logging to your server. In order to do so, just add the following arguments to your ColdFusion server's jvm.config file:
-Xloggc:gc-1.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

If you wish to change the name of the log file, just change 'gc-1.log' to the filename you wish. By default, this file will be created in the same folder as your jvm.config file.

If Using Railo: When using Railo it's more reliable to specify a full path to the GC log file like this:

   -Xloggc:C:\railo\gc-1.log



NOTE: This section primarily applies to VPS/Dedicated customers only. Our administrators make sure the Heap is properly sized on our shared ColdFusion servers.

Tuning the Database Tier

Add Indexes

Make sure all database fields are indexed properly. At the minimum your tables should have a primary (unique) key and indexes for any columns used in a WHERE clause.

For your reference, this video from Percona describes how to make the most of table indexes: MySQL Indexing Best Practices

Tune Your Queries

Be sure to remove any 'SELECT *' statements in the code. Instead, explicitly name each column used in a query. Also, make use of query advisors such as the following:

Cache Queries (cfquery / cfstoredproc) Where Possible

Does your application have queries that are ran often and the data rarely changes? If so, enable caching on those queries as shown here: Good Developers Practice Safe Query Caching

The main takeaway is that your application should use the cachedwithin attribute on as many cfquery and cfstoredproc tags as possible. Query caching helps reduce the load on the database server and improves page response time noticeably.

To enable this attribute on your queries, just add the cachedwithin attribute to your cfquery or cfstoredproc tags. This example will cache a query for 15 minutes:
<cfquery name="myquery" datasource="mydsn" cachedwithin="#createTimespan(0,0,15,0)#">

Note: It is not recommended to cache queries for very long periods of time, so try to keep the timespan to an hour or less.

Preventing Known Memory 'Leaks'

Specify CFFunction Output Attribute

For any <cffunction> and <cfcomponent> tags, make sure that you have output="false" specified. If for some reason you do need output from the function, be sure to explicitly add the output="true" attribute. There is a bug in CF that leaks memory when the output function is left of function and component declarations.

Use Var Scope for Variables within CFFunction

Make sure all functions have their variables in the "var" scope, including queries. The varscoper utility here will check your code for any missing var statements in your code: http://varscoper.riaforge.org/ We highly recommend using this on a regular basis for all your sites.

Handle Bots and Spiders Properly

Because bots and spiders can create a lot of useless sessions when indexing sites, we recommend setting a custom session timeout as shown here: Lower Session Timeouts for Bots and Spiders

Debugging Individual Scripts

During non-peak hours for your site, try enabling the ColdFusion debug output and adding your IP to the remote debug IP list. Then load the most frequently accessed pages and grab the debug output. Once you have this, focus on improving the slowest sections of code first.

Additionally, if you have Seefusion on your VPS, it will hightlight the server's slowest scripts. You can also obtain stack traces of running scripts to find the root cause of any slowness.
More info: Using SeeFusion to Monitor ColdFusion Performance on a VPS/Dedicated_Server

NOTE: This section primarily applies to VPS/Dedicated customers only. We do not allow debugging on our shared ColdFusion servers, as it negatively impacts server performance. Also, Seefusion is not available to our shared hosting customers.