Java Virtual Machine

Java Virtual Machine
Dr.NaveenBansal Profile Pic
Published Date:25-10-2017
Your Website URL(Optional)
C H A P T E R 8 ■ ■ ■ Tuning Your Java Virtual Machine: Finding Your Ideal JVM Settings Through Metrics Log Analysis by Mike Brunt The Java Virtual Machine underlying the ColdFusion server is probably one of the least understood things about ColdFusion. Yet this mysterious "black box" is key to keeping ColdFusion operating efficiently. In the ColdFusion world, Mike Brunt is one of the best-known experts on taming this beast, and he presents many insights in this article. Tuning the Java Virtual Machine (JVM) can deliver dramatic benefits. For instance, a client recently called with severe stability issues: ColdFusion froze regularly and needed multiple restarts daily. We initially found that both thread and heap memory utilization reached 100% regularly. After we spent five days on-site tuning the JVM, overall heap memory utilization did not go beyond 30% and threads cycled well—a totally different world When I help clients with problems like this, I use a two-step process. First, I analyze the client's metrics logs, which measure memory and thread usage over time. Second, I use these logs to help me pinpoint, implement, and test the JVM settings that are ideal for the client's particular server. In this particular case, the client had not done anything more than accept the default JVM settings. This organization also ran an older version of ColdFusion, which meant it could not run the latest JVM. Often, simple changes, such as fine-tuning the JVM settings and upgrading to a newer JVM, will do wonders to restore a server's efficiency—even before analyzing and correcting issues in the client's codebase. In this article, I will detail how to go about tuning the JVM to improve performance and stability. How the JVM Fits into ColdFusion ColdFusion moved squarely into the standards-based Java Platform, Enterprise Edition (Java EE) world with version 6.1. The greatest benefit of that move was the ability to run multiple instances of 103 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS ColdFusion—effectively multiple ColdFusion servers—on the same physical machine. This common practice in the Java EE world was not possible in ColdFusion before version 6.1. The JVM enables the claim "write once, run anywhere" for Java (and ColdFusion) applications to come very close to reality. In essence, it abstracts the host operating system, such as Windows, Macintosh OS X, or Unix. In the Java application server world, which includes ColdFusion 6.1, 7, 8, and 9 as standards-based Java EE application servers, three layers sit within the host operating system. As shown in Figure 8-1, ColdFusion sits at the center of it all. And in a ColdFusion Enterprise installation, we might well see multiple Java application server COLDFUSION instances in that central position, each totally encapsulated. Figure 8-1. The JVM with ColdFusion ■ Note The Sun JVM is the default that comes with ColdFusion 6.1, 7, 8, and 9, with JRun as the default Java servlet container. The principles I will show here for tuning the JVM apply to any of the standards-based Java EE JVMs, although the location and names of the basic configuration files may differ. Enabling Metrics Logging The root needs of the JVM revolve around memory use and threads. In my experience, the perfectly tuned JVM recycles threads quickly (in milliseconds) and rarely uses more than 50% of the total heap memory available. To that end, the first thing I do with a client is see how the memory and threads are behaving, by enabling metrics logging within the JVM, which provides me with a running log of the threads and memory state on the client’s server. In fact, I have found this so safe and useful, I often recommend setting up metrics logging and leaving it running permanently. 104 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS Editing the jrun.xml File You enable metrics logging by editing the jrun.xml file for the ColdFusion server or instance. If you are on a Standard installation, you'll find this file here: drive-volume\coldfusionRoot\runtime\servers\cfusion\SERVER-INF where drive-volume is the name of the drive where ColdFusion is installed, and coldfusionRoot is the directory on that drive that holds ColdFusion. On a standard Windows installation, this would be C:\ColdFusion9. On an Enterprise installation, jrun.xml will be here: drive-volume\JRun4\servers\instancename\SERVER-INF Save a copy of the original jrun.xml file in case you need to roll back to it. Then open the original file in a text editor and locate the first set of metrics-logging entries, which will look like Listing 8-1. Listing 8-1. Default jrun.xml To enable metrics: uncomment this service and in LoggerService set metricsEnabled to true service class="jrunx.metrics.MetricsService" name="MetricsService" attribute name="bindToJNDI"true/attribute /service Uncomment the lower block of code so it now looks like Listing 8-2. Listing 8-2. Uncommented metrics section in jrun.xml To enable metrics: uncomment this service and in LoggerService set metricsEnabled to true myemailaddress 10/25/2008 "enabled metrics logging" service class="jrunx.metrics.MetricsService" name="MetricsService" attribute name="bindToJNDI"true/attribute /service Next, enable the metrics, once again in the jrun.xml file. Locate the block of settings shown in Listing 8-3. Listing 8-3. metricsEnabled attribute in jrun.xml You may also need to uncomment MetricsService if you want metrics enabled attribute name="metricsEnabled"false/attribute attribute name="metricsLogFrequency"60/attribute 105 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS attribute name="metricsFormat"Web threads (busy/total): jrpp.busyTh/jrpp.totalTh Sessions: sessions Total Memory=totalMemory Free=freeMemory/attribute Finally, make the changes shown in Listing 8-4 for the ColdFusion Enterprise edition, or make the changes shown in Listing 8-5 for the Standard edition. Listing 8-4. metricsEnabled attribute set to true in jrun.xml (Enterprise edition) You may also need to uncomment MetricsService if you want metrics enabled attribute name="metricsEnabled"true/attribute attribute name="metricsLogFrequency"60/attribute attribute name="metricsFormat"Web threads (busy/total/delayed): jrpp.busyTh/jrpp.totalTh/jrpp.delayTh Sessions: sessions Total Memory=totalMemory Free=freeMemory/attribute Listing 8-5. metricsEnabled attribute set to true in jrun.xml (Standard edition) You may also need to uncomment MetricsService if you want metrics enabled attribute name="metricsEnabled"true/attribute attribute name="metricsLogFrequency"60/attribute attribute name="metricsFormat"Web threads (busy/total/delayed): busyTh/totalTh/delayTh Sessions: sessions Total Memory=totalMemory Free=freeMemory/attribute In Listings 8-4 and 8-5, we are changing the metricsEnabled flag to true and adding a metric to show delayed threads. This important step helps to determine the number of threads an application needs under x amount of load. The difference between the Standard and Enterprise editions is that the Standard edition does not use the jrpp. prefix in the thread variable declaration (compare the last line of both listings). Splitting Up the JRun Logs Now we will improve organization and human-readability of the JRun logs by splitting different information into separate logs. In the jrun.xml file, make the bolded addition to the logging settings shown in Listing 8-6. Listing 8-6. Separate groups of information in jrun.xml attribute name="filename" jrun.rootdir/logs/ Next, restart the server to get the changes to take effect. Then look for the extra logs that are now being created, as shown in Figure 8-2. 106 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS Figure 8-2. New logs after server restart Here, we have three ColdFusion instances, and we can see that both cfusion and go2rialab2 have only two log files, while go2rialab1 has more, created as a result of our enhanced settings. Now that we've split the logs, it's time to look at the data. Examining the Metrics Logging Output Listing 8-7 shows an example of metrics-logging output from a server under load. Listing 8-7. Metrics before making changes 10/29 16:42:32 metrics Web threads (busy/total/delayed): 9/98/57 Sessions: 1 Total Memory=122848 Free=20640 10/29 16:43:32 metrics Web threads (busy/total/delayed): 9/112/75 Sessions: 1 Total Memory=122848 Free=19567 10/29 16:44:32 metrics Web threads (busy/total/delayed): 9/142/101 Sessions: 1 Total Memory=122976 Free=1847510/29 16:45:32 metrics Web threads (busy/total/delayed): 9/156/109 Sessions: 1 Total Memory=123104 Free=21705 10/29 16:46:32 metrics Web threads (busy/total/delayed): 9/157/84 Sessions: 1 Total Memory=123104 Free=43526 10/29 16:47:32 metrics Web threads (busy/total/delayed): 9/158/104 Sessions: 1 Total Memory=123348 Free=69981 10/29 16:48:32 metrics Web threads (busy/total/delayed): 9/173/119 Sessions: 1 Total Memory=144552 Free=57853 10/29 16:49:32 metrics Web threads (busy/total/delayed): 9/195/143 Sessions: 1 Total Memory=154480 Free=43064 10/29 16:50:32 metrics Web threads (busy/total/delayed): 9/216/162 Sessions: 1 Total Memory=154544 Free=37209 10/29 16:51:32 metrics Web threads (busy/total/delayed): 9/226/170 Sessions: 1 Total Memory=154608 Free=74059 10/29 16:52:32 metrics Web threads (busy/total/delayed): 9/226/150 Sessions: 1 Total Memory=154608 Free=9180 107 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS The logging collects these metrics at 60-second intervals. From this portion of the log, we can deduce that the default heap total memory size is too small. Let's examine the first metrics line: 10/29 16:42:32 metrics Web threads (busy/total/delayed): 9/98/57 Sessions: 1 Total Memory=122848 Free=20640 10/29 16:42:32 represents the date and time the metric was collected. In the Web threads (busy/total/delayed): 9/98/57 portion, the first number shows the amount of free memory (9 MB), which is uncomfortably low. The second number represents the total number of threads. The third number represents delayed or queued threads. (Threads are roughly equivalent to requests.) This number shows that in its current state of long-running requests, the application needs a higher concurrent request number than its current value of 8. At this point, we can start to pinpoint the desired start and maximum heap memory size in the JVM. Finding the Proper Start and Maximum Heap Memory Size Armed with the information from the metrics-logging output, I would change the start and maximum heap memory size. To do this, change the jvm.config file. On a Standard ColdFusion installation, you'll find the file here: drive-volume\coldfusionRoot\runtime\bin\ On an Enterprise installation, look in this directory: drive-volume\JRun4\bin\ The default values from a ColdFusion 9 Enterprise installation look like this: Arguments to VM java.args=-server -Xmx512m -XX:MaxPermSize=192m -XX:+UseParNewGC -Dcoldfusion.rootDir=application.home/ At present, we have no start value for the heap, and the maximum size -Xmx512m does not really help us. We will double the value of the maximum heap size and set the start value at the same level, as follows: Arguments to VM java.args=-server -Xms1024m -Xmx1024m -XX:MaxPermSize=192m -XX:+UseParNewGC -Dcoldfusion.rootDir=application.home/ Over many years of tuning the JVM up to Sun Java 1.6, I have found it beneficial to set the start (Xms) and maximum (Xmx) to the same number. The school of thought on this is that there is more effort expended by the JVM in gradually taking more memory than if we simply start it at the maximum in the first place. After making this change, we have much more free memory available at all times during the test. Requests are still queued, but not as many; response times improve; and errors diminish. 108 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS From the number of queued requests and the good amount of memory still available, we can see that we should increase the number of threads using ColdFusion Administrator. In this case, let's change the "Maximum number of running JRun threads" setting from 8 to 25, as shown in Figure 8-3. Figure 8-3. Setting the maximum number of running JRun threads in ColdFusion Administrator For this change to take effect, you must restart the server instance. The New Metrics After our changes to the memory and maximum thread settings, the metrics look like Listing 8-8. Listing 8-8. Metrics after making changes 10/29 21:27:02 metrics Web threads (busy/total/delayed): 22/86/0 Sessions: 0 Total Memory=1028928 Free=826205 10/29 21:28:02 metrics Web threads (busy/total/delayed): 17/85/0 Sessions: 0 Total Memory=1028928 Free=854949 10/29 21:29:02 metrics Web threads (busy/total/delayed): 13/85/0 Sessions: 0 Total Memory=1028928 Free=824296 10/29 21:30:02 metrics Web threads (busy/total/delayed): 14/85/0 Sessions: 0 Total Memory=1028928 Free=860022 10/29 21:31:02 metrics Web threads (busy/total/delayed): 21/85/0 Sessions: 0 Total Memory=1028928 Free=866417 10/29 21:32:02 metrics Web threads (busy/total/delayed): 24/85/0 Sessions: 0 Total Memory=1028928 Free=875053 10/29 21:33:02 metrics Web threads (busy/total/delayed): 24/85/0 Sessions: 0 Total Memory=1028928 Free=912602 109 CHAPTER 8 ■ TUNING YOUR JAVA VIRTUAL MACHINE: FINDING YOUR IDEAL JVM SETTINGS THROUGH METRICS LOG ANALYSIS 10/29 21:34:02 metrics Web threads (busy/total/delayed): 26/85/0 Sessions: 0 Total Memory=1028928 Free=868403 10/29 21:35:02 metrics Web threads (busy/total/delayed): 26/85/0 Sessions: 0 Total Memory=1028928 Free=921888 The requests still run too long, but not as long as before, since now we do not get any queued threads. At this point, we would move on to check both code and any database query issues. Summary In this article, I have shown what I do to enable enhanced metrics logging and how I use the logging information to find a server's optimal JVM settings. These are actual results from a live production server. I hope to produce more articles in the future covering garbage-collection logging and the use of SeeFusion, both critical components of the work that I do, day in and day out. 110 C H A P T E R 9 ■ ■ ■ The Shoemaker and the Asynchronous Process Elves by Doug Boude This article was based on an experiment—a bit of impromptu testing by the author on the viability of using ColdFusion’s asynchronous processing, a feature introduced in ColdFusion MX 7. The effectiveness of the experiment and the power he discovered in asynchronous processing inspired and excited Doug and prompted this article. It was the last session at the two-day cf.Objective() conference where speakers had been exploring en masse new ways of approaching application development using ColdFusion. I had found the sessions inspiring and enlightening and had no reason to believe that the one called “Asynchronous Logging” would be any different. Indeed, as Michael Dinowitz began to artistically weave what would later serve as a catalyst for his audience's understanding, an analogy began to form in my mind. To further my understanding, I likened “Asynchronous Logging” to an old story that was told to me as a child—“The Shoemaker and the Elves.” Taking the liberty of modernizing and modifying the tale a bit to better apply to the subject at hand, I saw it like this: The shoemaker worked steadily, night and day, working his way down a very long list of customer shoe orders, yet the list grew ever longer. Given enough time and processing power the shoemaker would eventually complete his list of orders, but at what cost in time to the customers waiting patiently for their new shoes to arrive? How long would they wait before finding another site to make their shoes? Then late one night help arrived. A company of process elves begged the shoemaker to let them help. There they stood, tools in hand, looking up at the obviously worn out shoemaker, ready to start work as soon as he gave the word. The elves didn’t wait long, as the shoemaker immediately began doling out shoe orders to be filled. Under his direction, each elf began to pound away toward the completion of his individual piece of work. By the time the shoemaker had delegated all of his shoe orders, the sound of the hammers was deafening. And in a very brief time, every single order had been “automagically” filled. It was nothing short of a miracle for the shoemaker, who vowed never again to settle for serial processing when parallel processing was an option. He ran every other shoemaker in town out of business and, of course, lived happily ever after. Armed with this inspiration, I arrived back at my office on Monday ready to see just how much faster it is to make shoes with the help of elves. When I shared my epiphany with my coworkers, it 111 CHAPTER 9 ■ THE SHOEMAKER AND THE ASYNCHRONOUS PROCESS ELVES spawned some debate over whether or not the work would actually occur in less time or just appear to be completed in less time, because once a process is handed off to an elf, it is completely out of sight, leaving no clue as to how long it actually took. So I came up with an experiment to settle that debate. The Experiment I inserted the contents of a text file into a database table using two different methods: First, I inserted one record at a time, essentially having the shoemaker do all of the work himself. Then I gave the shoemaker the sole job of handing off one record to each elf for insertion. After the insertions were complete, for each method I subtracted the time when the first insert occurred (noted by a datetime field in the target table) from the time when the last insert occurred to see which method required the least amount of time to complete. My incoming file consisted of 256 records, each with three varchar fields. Two additional fields were also inserted: a datetime stamp set within the insert statement and an integer indicating which method had performed the insertion (synchronous or asynchronous). Listing 9-1 shows the code I used to read in the data. Listing 9-1. Code to Read in Data (asynctest.cfm) - Read in our data file - cffile ACTION="read" FILE="expandpath(".")/testfile.txt" VARIABLE="incoming" - Treating the file like a list, use the following (line feed/carriage return) characters as delimiters - cfset mydelim = chr(10) & chr(13) - Grab number of lines in file and display for informational purposes - cfset filelen = listlen(incoming, mydelim) cfoutput lines: filelen /cfoutput - Put the data file into an array - cfset thisdata = ListToArray(incoming, mydelim) The template I used, asynctest.cfm shown in Listing 9-2, contained both the synchronous processing and the asynchronous process handoff, segregated within a cfswitch that I manipulated via a URL expression. Listing 9-2. cfswitch Statement (asynctest.cfm) - Data put into array. Start the test (testtype value of 1 indicates synchronous processing, 2 indicates asynchronous). - cfswitch expression="url.test" cfcase value="batch" - Perform insertions the old-fashioned way - - First purge existing records - cfquery name="qryDelete" datasource="dsn" delete from TestTable where testtype = 1 112 CHAPTER 9 ■ THE SHOEMAKER AND THE ASYNCHRONOUS PROCESS ELVES /cfquery - Loop over the data array and perform an insert for each item - cfloop from="1" to="arraylen(thisdata)" index="j" cfquery name="qryInsertRec" datasource="dsn" insert into TestTable (txt_groupid, txt_code, txt_description, inserttime, testtype) VALUES ( cfqueryparam value="listfirst(thisdataj)" CFSQLTYPE="CF_SQL_VARCHAR", cfqueryparam value="listgetat(thisdataj,2)" CFSQLTYPE="CF_SQL_VARCHAR", cfqueryparam value="listlast(thisdataj)" CFSQLTYPE="CF_SQL_VARCHAR", cfqueryparam value="now()" CFSQLTYPE="CF_SQL_TIMESTAMP", cfqueryparam value="1" CFSQLTYPE="CF_SQL_TINYINT") /cfquery /cfloop - Retrieve the max and min times so we can calculate total insertion time - cfquery name="qryGetMaxMin" datasource="dsn" select max(inserttime) as maxtime, min(inserttime) as mintime from TestTable where testtype=1 /cfquery cfoutputtotal time for linear insertions: datediff("s", qryGetMaxMin.mintime, qryGetMaxMin.maxtime) seconds/cfoutput /cfcase cfcase value="async"- Perform inserts via gateways - - Purge existing data - cfquery name="qryDelete" datasource="dsn" delete from TestTable where testtype = 2 /cfquery - Loop over data array and call the gateway for each item, passing in the data - - Set up the structure we'll be handing over to the gateway - cfloop from="1" to="arraylen(thisdata)" index="j" cfscript stData = structnew(); stData.dsn = dsn; stData.theData=thisdataj; sendGatewayMessage(gateway, stData); /cfscript - To give the gateways time to complete their work, call this page with a separate request where test=checkAsyncTime to see the total insertion time for the gateways - /cfloop /cfcase cfcase value="checkAsyncTime" - Go back and see how long it took to perform all inserts 113 CHAPTER 9 ■ THE SHOEMAKER AND THE ASYNCHRONOUS PROCESS ELVES via gateway - cfquery name="qryGetMaxMin" datasource="dsn" select max(inserttime) as maxtime, min(inserttime) as mintime from TestTable where testtype=2 /cfquery cfoutput total time for asynchronous insertions: datediff("s", qryGetMaxMin.mintime, qryGetMaxMin.maxtime) seconds /cfoutput /cfcase /cfswitch The actual elf itself (asynchronous process code) lived in a CFC, shown in Listing 9-3, that had been associated with a ColdFusion gateway set up within the ColdFusion Administrator. Both methods were given the responsibility for splitting the incoming record into individual field values before performing their insertions, so that work was also part of their total insertion time. The back-end database was Sybase, which was accessed via ODBC instead of a native Sybase ColdFusion driver. Listing 9-3. Asynchronous Process Code (aTest.cfc) cfcomponent cffunction access="public" name="onIncomingMessage" output="false" cfargument name="CFEvent" type="struct" required="yes" cftry cfquery name="qryInsertRec" datasource="CFEvent.Data.dsn" dbtype="ODBC" insert into TestTable (txt_groupid, txt_code, txt_description, inserttime, testtype) values ( cfqueryparam value="listfirst(CFEvent.Data.theData)" cfsqltype="cf_sql_varchar", cfqueryparam value="listgetat(CFEvent.Data.theData,2)" cfsqltype="cf_sql_varchar", cfqueryparam value="listlast(CFEvent.Data.theData)" cfsqltype="cf_sql_varchar", cfqueryparam value="now()" cfsqltype= "cf_sql_timestamp", cfqueryparam value="2" cfsqltype="cf_sql_tinyint") /cfquery cfcatch cfmail to="" from="gateway test" subject="Candygram for Mongo" cfcatch.errorbrcfcatch.messagebrcfcatch.detail /cfmail /cfcatch /cftry /cffunction /cfcomponent I ran each method three times and found that the results favored the asynchronous method much more than I had expected. What took on average 20.7 seconds using the standard synchronous methodology took only 1.7 seconds when handing each insert to the gateway. That’s 12 times faster 114 CHAPTER 9 ■ THE SHOEMAKER AND THE ASYNCHRONOUS PROCESS ELVES When run under ColdFusion 8 and ColdFusion 9 beta, the same test performed a little better during standard insertion (13 seconds on average), but yielded the same results as MX 7 when performing the work asynchronously. Needless to say, I'm now a fan of using the elves whenever and wherever I can find a creative place to do so. To see the experiment in action, download my files from and save them to the same directory. Execute the tests at http://yourserver/asynctest.cfm?test= Here test can be "batch" (linear processing), "async" (gateway processing), or "checkAsyncTime" (to retrieve the time results for the last asynchronous processing test). Before Employing Those Elves There’s always a competing shoemaker in town, so you are probably thinking of at least two places in your application where an elf or two would be just the ticket. But before you start delegating functionality to ColdFusion gateways, take a few moments to consider the prerequisites. The most important prerequisite for using asynchronous gateways is that your ColdFusion server must be MX 7 Enterprise or ColdFusion 8 (Enterprise or Standard)—MX 7 Standard, as well as previous versions of ColdFusion, does not have built-in support for gateways. And before deciding how much work to delegate to a gateway, consider how beefy your server is. While we can sometimes mistake our servers for the latest Cray prototypes, they do have their limits, and we can all too quickly discover those limits if we aren’t careful. For some insight to help balance your zeal, read Sean Corfield's blog post “Asynchronous Development—How Much Parallelism?” listed in the resource section at the end of this article. ■ Note ColdFusion 8 Standard allows gateways, but limits them to a single thread. The Moral of the Story Although every speaker at the cf.Objective() conference had different topics, styles, and approaches, I was able to glean the same message from all of them: be creative in my coding, think outside the box, make the time to experiment with ColdFusion, and let my creativity manifest itself in what I produce. Their examples taught me that I should always strive for elegance and efficiency in my code. It was inspiring, to say the least. I leave you with a bone to chew on: How would you recreate or simulate asynchronous processing using a version of ColdFusion that does not support that feature? Let that question be fodder for your creativity and experimentation next time you have a few minutes to “play. ” 115 CHAPTER 9 ■ THE SHOEMAKER AND THE ASYNCHRONOUS PROCESS ELVES Further Reading on Asynchronous Gateways • Matthew Woodward, “The Asynchronous CFML Gateway”: http://coldfusion. • Adobe LiveDocs on Asynchronous Gateways: coldfusion/7/htmldocs/wwhelp/wwhimpl/common/html/wwhelp.htm?context= ColdFusion_Documentation&file=00000622.htm • Sean Corfield, “Asynchronous Development—How Much Parallelism?”: • Sean Corfield, “Asynchronous Development—Things to Consider”: • Ben Forta, “Understanding Asynchronous Processing”: blog/index.cfm?mode=entry&entry=A61BC2EE-3048-80A9-EF50D0AA3896B282 • Raymond Camden, “Using ColdFusion’s Asynchronous Gateway”: Asynchronous-Gateway • Raymond Camden, “Using ColdFusion’s Asynchronous Gateway – 2”: Asynchronous-Gateway2 • Raymond Camden, “Using ColdFusion’s Asynchronous Gateway – 3”: Asynchronous-Gateway3 116 C H A P T E R 10 ■ ■ ■ Asynchronous Gateways Step-by-Step by Michael Dinowitz Asynchronous gateways were one of the key additions to ColdFusion MX 7. Originally, gateways were limited to the Enterprise version, but in ColdFusion 8 and 9 this limitation has been removed. (ColdFusion 8 and 9 Professional allow gateways but limit the number of threads in use.) In this short article, a companion piece to Chapter 9, Doug Boude’s “The Shoemaker and the Asynchronous Process Elves,” Michael Dinowitz takes us, step-by-step, through setting up a gateway. Despite its awe-inspiring power, setting up an asynchronous gateway in ColdFusion is actually very simple. All you need is a CFC that will be called by the asynchronous gateway, a place to put that CFC (and where you place it is more important than you may think), and access to the ColdFusion administrator in order to register the CFC. It is best to put all asynchronous gateways in a directory separate from the rest of your application. There is a really good reason for this, and it has to do with context. A normal ColdFusion page runs in one context with access to the sitewide error handler. A gateway runs in a different context, and if an error is ever thrown from the gateway CFC it will not be caught by the sitewide error handler. The solution to this is to place an Application.cfc in the same directory as the gateway. Using an onError method, we can now capture error events and do something about them, such as emailing an administrator. In addition, we can use the Application.cfc to create application and server variables for use by the gateway. Application variables set inside an onApplicationStart() method will run once. Variables set inside a gateway CFC will run every single time the gateway is run. In other words, there is no caching of the gateway CFC. It’s possible to use the gateway CFC as a “stub” to call a cached CFC, but the technique is outside of the scope of this article. Our asynchronous gateway will look like Listing 10-1. Listing 10-1. Sample Asynchronous Gateway CFC CFCOMPONENT output="false" CFFUNCTION name="SiteLog" returntype="void" output="false" CFARGUMENT name="CFEvent" required="yes" ... lots of logging code ... /CFFUNCTION 117 CHAPTER 10 ■ ASYNCHRONOUS GATEWAYS STEP-BY-STEP CFFUNCTION name="listbanners" returntype="void" output="false" CFARGUMENT name="CFEvent" required="yes" ... lots of logging code ... /CFFUNCTION /CFCOMPONENT When we create an asynchronous gateway in the administrator, we will map its unique name to the specific CFC. In Listing 10-1 we have two different methods (SiteLog and listbanners), which means that two different asynchronous gateways can use this same CFC. The only thing that will be passed into any gateway method is a structure called CFEvent. This structure contains all of the data that the gateway method will use. While this is required, we really do not have to check its data type. If it’s not a structure, an error will be thrown before we even get to the method. Not checking the data type saves us memory and processing, and in cases like this, where we have total control over what’s going into the CFC, it’s warranted. Now that we have created our asynchronous CFC and the methods it contains, we have to register it in the ColdFusion Administrator. Open up the Event Gateways tab (see Figure 10-1) and select Gateway Instances. All we need here is the name of the gateway, which does not need to be the name of the method being called. We select “CFML - Asynchronous Events via CFML” as the gateway type (there are others) and then put in the full server path to our CFC. Figure 10-1. Setting up Your Gateway in the ColdFusion Administrator We don’t need a configuration file, so we can skip over that. We do need to decide if the gateway should start automatically or be turned on by hand. Once you have done all this, click submit. You now have an asynchronous gateway. Having a gateway set up is only half the battle. To use it, you must call it. Listing 10-2 contains some sample code that will call an asynchronous gateway to log user information. 118 CHAPTER 10 ■ ASYNCHRONOUS GATEWAYS STEP-BY-STEP Listing 10-2. Calling the LogPage Gateway CFFUNCTION name="LogPage" returntype="void" output="false" CFSCRIPT var sLogData=StructNew(); sLogData.Query_String=CGI.Query_String; sLogData.Path_Info=cgi.Path_Info; sLogData.Script_Name=cgi.Script_Name; sLogData.REQUEST_METHOD=CGI.REQUEST_METHOD; sLogData.HTTP_REFERER=cgi.HTTP_REFERER; sLogData.REMOTE_ADDR=cgi.REMOTE_ADDR; sLogData.http_user_agent=cgi.http_user_agent; sLogData.method="SiteLog"; SendGatewayMessage('Asynch Logger', sLogData); /CFSCRIPT /CFFUNCTION The function in Listing 10-2 creates a structure containing some visitor information that we want to log. The structure also includes the method that we want to run in the gateway CFC, “SiteLog”. Finally, in the last line of the cfscript section, we send the structure to the asynchronous gateway using the SendGatewayMessage, and we’re done. The gateway gets the data and uses it, the page that calls the gateway doesn’t have any of the overhead of logging, and everything is smooth. The whole purpose of an asynchronous gateway is about performance and savings. Rather than doing 1,000 operations sequentially in a single template, you have an asynchronous gateway do them individually and get them done quicker. Rather than have a complex and resource-intensive logging operation take place as part of a user’s session, you throw the information you want to log “somewhere else” to be worked with. The only limit is knowledge and imagination. 119 C H A P T E R 11 ■ ■ ■ You Might Have a Performance Bottleneck If… by Adrian J. Moreno Many a flame war has started over the argued performance of a web application based solely on the language with which it was programmed. You may hear "X scales better than Y," or "No real programmer uses Z." More often than not, poor performance in a web application can be traced to data management. The application could be performing tasks better suited to the database, or the database could be poorly designed. Taking a cue from Jeff Foxworthy’s “You might be a redneck if…” jokes, this article will introduce terms and concepts related to data normalization and application optimization in order to help you pinpoint poor database structures, data-storage processes, and data-retrieval techniques. If You Can't Tell a Manager from an Employee, You Might Have a Performance Bottleneck Most developers know that the primary key (denoted as PK) of a database table is a unique value that identifies each row. For the example in this article, Listing 11-1 creates a table named USERS with columns named USER_ID, FIRST_NAME, and LAST_NAME. The USER_ID column holds the table's primary key, which is an auto-incrementing numeric value, also called an identity, that increases as new records are added. ■ Note The SQL contained in this article pertains to Microsoft SQL Server. Consult your documentation for syntax specific to your database. 121 CHAPTER 11 ■ YOU MIGHT HAVE A PERFORMANCE BOTTLENECK IF... Listing 11-1. Creating the USERS table CREATE TABLE USERS( USER_ID int IDENTITY(1,1) NOT NULL, FIRST_NAME varchar(50) NOT NULL, LAST_NAME varchar(50) NOT NULL, CONSTRAINT PK_USERS_USER_ID PRIMARY KEY CLUSTERED ( USER_ID ASC ) ) Figure 11-1 shows the USERS table, including a yellow key icon next to the USER_ID column. That key icon is a common way of denoting the primary key of a table. Figure 11-1. The USERS table created by Listing 11-1 In this article’s example, your application’s requirements include restricted sections, such as user management and order processing. In order to allow certain people into restricted sections, the application code could be written to recognize one user from another, as shown in Listing 11-2. Listing 11-2. User access in the application code cfif (session.first_name eq "John") and (session.last_name) eq "Doe") - run restricted functionality - /cfif This creates a performance bottleneck in the application, because it’s possible for there to be more than one “John Doe” in the system. In addition, you would need to manually add a CHECK condition for each new user allowed into a restricted section. If you can tell a manager from an employee, you eliminate this bottleneck. You need to classify each user as a specific type. A beginning developer might create a list of user types and add a column to the USERS table that stores the first character of each user type, as in Listing 11-3. Figure 11-2 shows the altered USERS table. 122

Advise: Why You Wasting Money in Costly SEO Tools, Use World's Best Free SEO Tool Ubersuggest.