YOUR FEEDBACK
andy.mulholland wrote: intriguing !!! We have full scale 'Mashup Factories' in Chicago USA and Utrec...


2008 East
DIAMOND SPONSOR:
Data Direct
Frontiers in Data Access: The Coming Wave in Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
Intel
Virtualization – Path to Predictive Enterprise
Green Hills
IT Security in a Hostile World
JBoss / freedom oss
Practical SOA Approach
GOLD SPONSORS:
Software AG
The Art & Science of SOA: How Governance Enables Adoption
PlateSpin
Effective Planning for Virtual Infrastructure Growth
Fujitsu
Automated Business Process Discovery & Virtualization Service
Ceedo
Workspace Virtualization
Click For 2007 West
Event Webcasts

2008 East
PLATINUM SPONSORS:
Appcelerator
Think Fast: Accelerate AJAX Development with Appcelerator
GOLD SPONSORS:
DreamFace Interactive
The Ultimate Framework for Creating Personalized Web 2.0 Mashups
ICEsoft
AJAX and Social Computing for the Enterprise
Kaazing
Enterprise Comet: Real–Time, Real–Time, or Real–Time Web 2.0?
Nexaweb
Now Playing: Desktop Apps in the Browser!
Sun
jMaki as an AJAX Mashup Framework
POWER PANELS:
The Business Value
of RIAs
What Lies Beyond AJAX?
KEYNOTES:
Douglas Crockford
Can We Fix the Web?
Anthony Franco
2008: The Year of the RIA
Click For 2007 Event Webcasts
SYS-CON.TV
TOP THREE LINKS YOU MUST CLICK ON


Extreme Performance Tuning
Extreme Performance Tuning

The performance of J2EE-based applications sometimes doesn't live up to users' expectations. Usually it's impossible to quantify exactly where the bottlenecks are. Many developers spend time searching for articles on the Internet only to find the same old tips about using the synchronized keyword and string concatenation without ever finding information that's useful. This article will help you find the holy grail of Java performance.

In my previous article (JDJ, Vol. 6, issue 9) we focused on tips that are common to most applications. The tips presented here focus on common problems found within applications that utilize JSP, EJB, JNDI, and JDBC. Future articles will cover some powerful techniques to help your applications perform better.

Session Invalidation
Many application servers typically have a default timeout value of 30 minutes for cleaning up dead sessions. When an application server can't hold any more sessions in memory, it may cause the operating system to page out portions of memory. The application server may also swap unused sessions to disk based on the most recently used algorithm or even throw OutofMemoryExceptions. In a high-volume system, serializing sessions can be expensive. Calling HttpSession.invalidate() is the recommended way to clean up a session when you no longer need to use it. This method is usually called as part of an application's logout page.

Sessions and JSP
The J2EE specification requires all JSP objects that can be referenced in JSP source and tags be usable without explicit declaration. For Web pages that don't require session tracking, you can save resources by turning off automatic session creation using the following page directive:

<%@ page session="false"%>
Servlet and Memory Usage
Many application developers are guilty of storing way too much information in the users session. Sometimes these objects don't get garbage collected in a timely manner. The typical performance symptom may be periodic slowdowns that are reflected in the user experience but aren't traceable to any particular component. If you're monitoring the JVM's heap size, this may be reflected as significant peaks and drops in memory usage instead of a normal pattern.

There are a couple of ways to even out memory usage in this scenario. The first recommendation is to have all beans that are scoped as session implement the HttpSessionBindingListener interface. This allows you to explicitly release resources that are used within the bean by implementing the method valueUnbound().

The other approach is to simply expire sessions more quickly. Most application servers have settings that usually specify the interval. You can also do it yourself programmatically by calling session.setMaxInactiveInterval(), which specifies the time in seconds between client requests before the servlet container will invalidate the session.

HTTP Keep-Alive
The majority of Web servers on the market, including iPlanet, IIS, and Apache, support HTTP Keep-Alive. This function keeps an open connection from client to server so that subsequent requests to the server don't have to be established or reestablished. This is usually a good technique for sites serving static content. The problem with sites with heavier loads is that the benefit of keeping a connection open for a single client also has a performance penalty as it ties up resources when the process is idle. This resource usage is even more important if your Web and application server are one and the same. Choose the Right Include Mechanism

A typical JSP architecture may break out headers, footers, and navigation into their own resources, included in each JSP page as appropriate. Currently there are two methods to include a resource: the include directive and the include action.

  • Include directive <%@ include file="copyleft.html" %> : Includes the content of the resource at compile time. The page with the directive and the resource are merged into one file before final compilation. When resources are resolved at compile time, they'll always be faster than resources resolved at runtime.
  • Include action <jsp:include page="copyleft.jsp" /> : Includes the response generated by executing the specified page. Since this is done at runtime, we can vary the output produced. Use this action only for content that changes often and for scenarios in which pages to include can't be decided until the main page has been requested.
Use Cache Tagging Features
Several vendors have added cache tagging features to their application servers for use with JSP. BEA's WebLogic Server introduced this feature in the 6.0 versions of its product. This feature is also supported by the Open Symphony project. JSP cache tagging allows both fragments and page-level information to be cached. When a JSP page executes, if a tagged fragment is found in cache, the code that creates the fragment is skipped. Page-level caching catches requests for specific URLs and caches the resulting output. This feature is extremely useful for shopping cart/catalog and/or portal home pages. In this scenario a page-level cache can store the resulting content to satisfy future requests. Here's an example URL that would be a good candidate: http://quote.yahoo.com/q?s=hig&d=t".

Use of cache tagging features provides performance increases for applications where there's significant logic; and has less of an effect for truly architected sites that utilize an MVC (Model View Controller)-based framework.

Always Access Entity Beans from Session Beans
Accessing entity beans directly is bad for performance. When a client application accesses an entity bean, each get method is a remote call. A session bean accessing the entity bean is local and can collect all data in a structure and return it by value. You can read more about the value pattern in Design Patterns by the Gang of Four.

Using a session bean to wrap access of an entity bean allows for better transaction management as the session bean will commit only when it reaches a transaction boundary. Each direct call to a get method results in a transaction. The container will execute a store-and-load after each transaction on an entity bean.

At times using an entity bean will result in bad performance. If the only purpose for an entity bean is to retrieve and update values, you'll gain better performance using JDBC within session beans.

Use Read-Only in the Deployment Descriptor
The deployment descriptor for an entity bean allows all get methods to be set as Read-Only. This increases performance when the unit of work in a transaction contains no methods other than read-only, as the container won't invoke the store.

Cache Access to EJB Homes
EJB Home interfaces are obtained through a JNDI naming lookup. This operation requires significant resources. A good place to put lookup code is within a servlet's init() method. If your application requires EJB access by multiple servlets, it would be wise to create an EJBHomeCache class. This class typically would be implemented as a singleton.

Consider Local Interfaces for EJBs
Local interfaces is an addition to the EJB 2.0 specification, allowing a bean to avoid the overhead of a remote invocation call. Consider the following code:

PayrollBeanHome home = (PayrollBeanHome) javax.rmi.PortableRemoteObject.narrow (ctx.lookup ("PayrollBeanHome"), PayrollBeanHome.class);

PayrollBean bean = (PayrollBean) javax.rmi.PortableRemoteObject.narrow (home.create(), PayrollBean.class);

The first statement indicates that we want to find the bean's home interface. This lookup is via JNDI, which is an RMI call. We then locate the remote object and return the proxy reference. This too is an RMI call. The second statement demonstrates creating an instance. This code points to a stub that creates an IIOP request and transmits it over the network. This too is an RMI call.

To implement this functionality, all you have to do is extend from EJBLocalObject instead of EJBObject. My Pentium 700Mhz machine, a change from remote to local interfaces, sped up method calls overall by 20%.

To implement local interfaces, you may have to make the following changes:

  1. Methods can no longer throw java.rmi.RemoteException. The rule also applies to exceptions extended from RemoteException, such as TransactionRe- quiredException, TransactionRolledBackException, and NoSuchObjectExcep- tion. EJBs provide equivalent local exceptions (TransactionRequired- LocalException, TransactionRolledBackLocalException, and NoSuchObject- LocalException).
  2. All data and return values are passed by reference, not by value.
  3. The local interface must be used on the machine where the EJB is deployed. In simpler terms, everything must be within the same JVM. This limits you to deploying on nonclusterable applications.
  4. References for beans that implement local interfaces aren't serializable.
Consider Writing Your Own Stubs
Stubs are responsible for forwarding method invocations to remote beans, and are typically generated by most deployment tools. If you haven't already implemented the value pattern, you can implement this functionality before anything is transmitted over the wire by modifying the stub. In modifying the stub, you can also implement your own caching routine or even compress data before it's transmitted.

Normally this technique isn't recommended and would be against previous recommendations about being clever. You'll have to worry about the deployment tool overwriting your changes as well as having your stub figure out when to reload data if another client changes information.

Generating Primary Keys
There are many clever ways of generating primary keys within an EJB. I'll list several common techniques and then explain why they're all bad.

You can use the database's built-in identity (SQL Server IDENTITY or Oracle's SEQUENCE). This makes the implementation of your EJB nonportable (bad).

You could have an entity bean increment its own value, but this is bad as it requires serializable transactions, which are also slow.

You could use a time service such as NTP, but this requires native code and locks your bean to the particular OS. This approach also allows for the potential of generating two primary keys in the same millisecond on multiple CPU servers.

You could architect your bean and steal some ideas from Microsoft by creating a GUID, but you'll run into the fact that Java can't determine the MAC address of your network card without resorting to JNI, which will make your bean OS- dependent.

You'll also run into an issue if you try to utilize System.currentTimeMillis(), which will have the same issues previously mentioned. It'll be hard to identify a comparable formula. You could try to implement statics, but you'll fail as they aren't supported in the EJB specification.

There are several other approaches but they all have their limitations. There's only one appropriate answer: consider using RMI and JNDI together. You'll start with binding the RMI remote object to the JNDI tree via the RMI registry using the JNDI service provider interface. Your clients will look up the singleton via JNDI. Here's an example:

public class keyGen extends UnicastRemoteObject implements Remote {

private static long keyVal = System.currentTimeMillis();

public static synchronized long getKey() throws RemoteException { return keyVal++; }

JDBC and Unicode
Hopefully you've read the typical industry recommendations about using JDBC such as using connection pools, preferring stored procedures or direct SQL, using type 4 drivers, removing extra columns from the result set, using prepared statements when practical, having your DBA tune the query, and choosing the appropriate transaction levels.

Besides the more obvious choices, the best action you can take to increase performance is to consider storing all character data in Unicode (Code page 13488). Java processes all data in Unicode and therefore the database driver doesn't have to perform a conversion. But beware: taking this step will cause your database size to grow, as Unicode requires 2 bytes per character. You'll have to worry about performance when you implement this tip if you have non-Unicode applications accessing the data, as a conversion will also occur.

JDBC and I/O
When your application requires access to a large result set, consider implementing block fetches. By default, JDBC fetches 32 rows at a time. As an example, if you needed to iterate through a result set of 5,000 rows, this would cause JDBC to make 157 calls to the database to fetch data. If you changed the block size to 512, this would require only 10 round-trips.

This tip may not work in several scenarios. If you use scrollable result sets or specify FOR UPDATE as part of the query, blocking isn't used. Another technique to use is the Page-by-Page Iterator pattern.

Consider Using an In-Memory Database
Many applications have the need to store a significant amount of data on a per-user basis in the session. Typically, you may see this implemented as a shopping cart and catalog. Since this type of data is represented as row/column data, many applications may create either large vectors or hashmaps. Keeping this type of data in session severely limits scalability as you must have at least the amount of memory per session times the maximum number of concurrent users, which can either be a very expensive server and/or could stretch garbage collection times to unbearably long periods.

To achieve slightly better scalability, some people have offloaded the shopping cart/catalog functionality to the database tier. The fundamental problem with the database tier is based on the architecture of most relational databases. The main principle at work is that they try to make all writes durable; hence all performance is tied to the ability to physically write the data to disk. Relational databases try to reduce I/O, especially for read operations, but accomplish this goal only by execution of complex algorithms that implement caching and are the main reason that the database tier's number-one bottleneck is usually CPU.

There is an alternative. Consider using an in-memory database. Several vendors have addressed this market. I'm a fan of TimesTen, but you're welcome to choose your own. They start by allowing data to be temporarily written but not necessarily persisted to disk, and keeping all operations in memory. As a result, they also don't need complex algorithms to reduce I/O, and are faster because they can employ simpler locking mechanisms.

Develop a Smarter Caching Mechanism
Many application developers have implemented caching mechanisms for frequently requested data. These caches are typically implemented as hashmaps. The main problem with this approach is that there's no constraint on how large the hashmap can grow. Many applications should consider placing a constraint on cache growth by using algorithms utilizing a strategy of keeping only the most recently used objects. This is best accomplished by combining a hashmap with a LinkedList.

The code should implement the following logic:

  1. If the cache is full, remove the last object from the tail of the list and insert the new object at the head of the list.
  2. If the cache isn't full, and you want to insert a new object, put it at the head of the list.
  3. If the object is already in cache, move it to the head of the list.
Conclusion
Optimizing code is one of the last things developers should consider. Slow applications that work are preferred to fast applications that don't. Keep in mind that performance is sometimes in perception. It's possible to optimize a user's perception of performance without necessarily optimizing an application. Consider providing immediate feedback, as users will be happier to view a screen that paints immediately and takes 10 seconds to process than to have a screen that paints itself in seven seconds.
About James McGovern
James McGovern is an industry thought leader and the author of the bestselling book: A Practical Guide to Enterprise Architecture (Prentice Hall). He is working on two upcoming books entitled: Agile Enterprise Architecture and Enterprise SOA. He is employed as an Enterprise Architect for The Hartford Financial Services Group, Inc. He holds industry certifications from Microsoft, Cisco and Sun. He is member of the Java Community Process and of the Worldwide Institute of Software Architects.

LATEST JAVA STORIES & POSTS
The one thing that unifies the distributed computing style known as SOA, in most of its manifestations, is self-describing data via the Extensible Markup Language (XML). The benefits of XML over opaque message formats in data interchange are well established. No matter if your fo...
In the past couple of years, interest in Jetty has surged. Jetty is an open source Java-based web and application server and servlet container, but what else do you know about it? To commemorate the 12th anniversary of Jetty, here are 12 things that might surprise you
JavaScript is one of the most interesting and misunderstood programming languages in common use today. Most developers will go their entire careers without realizing its full potential. It's not often that you get a language that supports the feature set that JavaScript does, whi...
JavaScript 2 is becoming increasingly important. Learn how to take advantage of JavaScript 2 while still running in today's browsers. Leverage your current JavaScript and HTML skills to build applications that run in Flash 7-9, DHTML and more with no code changes! OpenLaszlo 4.2 ...
JavaScript is a language with more than its share of bad parts. It went from non-existence to global adoption in an alarmingly short period of time. It never had an interval in the lab when it could be tried out and polished. JavaScript has some extraordinarily good parts. In Jav...
Cloud computing is an opportunity for businesses to implement low-cost, low-power and high-efficiency systems to deliver scalable infrastructure. But moving to a cloud infrastructure is not necessarily as nice and clean as the providers would want you to think. With cloud infrast...
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON FEATURED WHITEPAPERS

SPONSORED BY INFRAGISTICS
In every field of design one of the first things students do is learn from the work of others. They ...
There are many forces that influence technological evolution. After a decade of building enterprise ...
2008 is going to be an important year for Rich Internet Applications. Most organizations are deliver...
The OpenAjax Alliance is developing an Ajax industry wishlist for future browsers, using a dedicated...
Infragistics announced the availability of two Community Technology Preview (CTP) User Interface (UI...
The YUI development team has released version 2.5.2; you can download the new release from SourceFor...
ADS BY GOOGLE