Overview
This write up is intended to give java developers that are
developing ColdFusion applications some beneficial information:
things that are not documented.
Scenario
The company builds enterprise class web application software
for fortune 500 companies. It had purchased a CF 7 based product,
had and existing proprietary J2EE based product, and needed to
integrate the two while meeting a host of new requirements. These
requirements were based on delivering a better user experience,
faster / cheaper integration, increased flexibility /
configuration, useablily, decreasing maintenance costs, the ability
to deploy in either install or ASP models. An initiative was
started to create a new framework that integrated the best of each
technologies. Tactically, this meant that we were to build a hybrid
CF and java application: one that used building blocks (decoupled /
cohesive components) that would allow applications to be rapidly
assembled, configured and deployed. This made sense on several
levels, the team was composed of Java and CF developers, the CF
rapid application development was very productive, there is great
functionality delivered in the CF platform and initial performance
tests showed no cause for alarm
The agreed upon design, based on requirements, and analysis
by both the CF and Java staff has us using CF in the presentation
layer, using a CF based MVC, use of CF based web services. The MVC
was deployed using CFC inheritance for model objects and views made
use of CF custom tags. The internals of the application, used a
rules engine, some proprietary java, ORM, and other J2EE
technology. The initial performance of the system was reasonable.
We pushed on with product implementation.
Then it was time to load test the application, and tune it.
Under load the response times were orders of magnitude slower,
sometimes the pages even timed out.
Armed with our profiler, oracle execution plans and we
charged ahead addressing issue after issue. Note that we took
meticulous care in tweaking the active thread pool and ensuring
that our CF setup was tuned for our application. None of the
observations here are a condemnation of the language; rather they
are aspects that, when considered together, not conducive for
building integrated java and CF frameworks that use a structured /
OO programming practices. Further detail can be provided on
request.
CFC inheritance should be avoided - resolution of variable
scope is expensive even if properly declared.
Since CF creates a class per method under the covers call
stacks become very large, especially if used in a loop. This is
nominally exacerbated by CF calls necessary to set up for the
method call (String.toUpper()).
Nesting of loops and if statements should be kept to a
minimum - the conditional for each lookup of logical operator like
LT, GT are synchronized. Under load this results in thread waits.
Jrun has as single thread pool - both http and web service
requests use the same pool. Under load this leads to thread
deadlock. There are work arounds, but they are painful.
Recursion should be avoided - we had a few recursive routines
and these had to be rewritten.
Custom Tags - should be used sparingly - each custom tag
makes a synchronized call to the license server - (This may be
fixed in CF 8)
Summary
In the end we got the performance to reasonable numbers, but
we ended up moving some code to java (Custom Tags) and getting rid
of 'good programming' practices (Inheritance, loops, etc), mandated
proper variable scoping for those things left over. We prototyped a
sans cold fusion implementation and had an order of magnitude
improvement in performance and number of requests served per
second.
The lesson? Use Coldfusion in its sweet spot: make a query,
iterate over the results and format for display. Extensive use of
structure programming techniques or OO CFCs should be avoided: they
will work but under load - but are better as a prototype. Building
frameworks in CF? Think twice, no three times, and, if you must, be
minimalist.
Text