Murali Kaundinya

Subscribe to Murali Kaundinya: eMailAlertsEmail Alerts
Get Murali Kaundinya: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Related Topics: Java EE Journal, Java Developer Magazine

J2EE Journal: Article

JDJ Feature: Isolating Concurrent Java Apps In JVM, Java Virtual Machine

Peaceful Coexistence In Java Runtime Environment

It's not at all uncommon to see a server machine or even a desktop machine that runs the same or multiple applications each with its own Java Runtime Environment. In the server environment, aside from the scaling issues with garbage collection, the real motivation was for different applications to not be adversely affected by sharing application data and state within the same JVM. However, launching and running multiple processes, even on a server, comes with a price.

JVM researchers have long investigated the possibility of running multiple applications concurrently on the same VM and yet have sufficient degree of isolation to not step on each other's toes. Java Isolates (JSR-121) is a JCP effort to come up with a standard set of APIs that when implemented in the platform can someday provide the degree of isolation between applications that could run concurrently and coexist on the same physical JVM.

Introduction
About four years ago, a large client had experienced a sporadic outage with their application that was running on a J2EE server. There were multiple applications deployed on the same server, each having their own URL. The code review within these applications did not reveal anything untoward and they did not load any native libraries. The application server in question did have a significant amount of native code. We investigated the possibilities by which an application can become unstable. Our efforts to reproduce the problem were largely unsuccessful. We found some useful literature that stressed the importance of doing static analysis of native code, allowing/disallowing signal handling routines between native code and the underlying OS, the potential for collisions, etc. Since the native code was loaded by the application server and not by the application, there was very little we could do in terms of analyzing and monitoring the suspect code. Such debugging experiences are not uncommon and they emphasize the importance of isolating applications and their native libraries from each other. That begs an understanding on how the J2EE platform provides for isolation between multiple concurrent applications. A J2EE server uses the classloader mechanism to provide isolation between these enterprise applications and it has its limitations, which we'll discuss later. A J2EE server virtualizes the underlying resources to an application similar to an operating system. It makes it possible to share JDBC connections between applications and some application servers allow the creation of connection pools per application. It provides life-cycle services to components and applications but doesn't have a way to stop threads safely. It doesn't have the means to control CPU or to renegotiate memory, storage, etc. As a consequence of these limitations and from the fear of contention between co-located applications (discussed earlier), enterprises rely on the protection offered by the operating system. They deploy a single application on a single application server instance even on highly scalable SMP servers. They add more J2EE server instances for running different applications, resulting in overheads that take more system resources. This approach requires a separate administrative server to manage the server instances and that adds to the overheads further. This is not optimal and there has been a pressing need for applications to safely co-exist within the same J2EE server.

What Is Wrong with Classloaders?
Classloaders make it possible to load multiple instances of the same class. It's possible to modify the search mechanism for class files within the JVM. Classloaders act like a namespace whereby the classes loaded by a particular classloader are tagged to provide a unique identity. With classloaders, it's also possible to dynamically modify the bytecodes just prior to their loading by performing certain transformations. An application can be unloaded by discarding its classloader. However, a classloader can only be discarded if the reference count for all the classes loaded by this classloader becomes zero and the garbage collector deems them as unreachable. Classloader share basic classes; this can be exploited to change the shared data, thus making the other classloader and its applications vulnerable. The security model is debatable at best. Here's an example: if there exists a utility class that's used by an application and that application is distributed across two separate classloaders, replicating the utility class in both of these classloaders is obviously expensive. It's certainly possible to create a hierarchy of classloaders and having the parent classloader load the utility class, thus allowing the two classloaders to share code. Isolation provided by classloaders is weak because objects can leak and be captured. This approach therefore is incomplete and error-prone.

Isolates
Isolates are Java APIs that provide a uniform mechanism for managing Java applications that are isolated from each other, but can potentially share underlying implementation resources. Each application is given the illusion of running in its own isolated virtual machine and they each have their own system properties, classpath, static class state, etc. There are two primary motivations behind this. One is to prevent the faults within an application from propagating to other applications. The other is to ensure that an isolate can be terminated. The primary platform targeted has been J2SE, although nothing within the API inhibits adoption in any platform. There has been a strong case for adoption within the J2ME. The specification is currently under public review. As an API, it doesn't influence the implementation too much. Isolates provides a means of deploying new Java implementation features that enable and enhance scalability while providing an alternative to ad hoc control schemes. A conformant implementation of the API must guarantee at least isolation of Java state (i.e., logically disjoint heap spaces, per application mutable static fields, etc). Java applications that span across virtual machine instances can be wrapped with the Isolation API by adding only a few mechanisms for control. It's also possible to have implementations of Java isolation that provide high degrees of class, bytecode, and native code sharing within the same VM or between multiple VMs. The specific features of the chosen implementation will be discernable via a combination of vendor-specific and standard command-line arguments and properties.

Isolates' Architecture
The Architecture for Isolates is shown in Figure 1. An Isolate is a class and is part of the Isolate API. Isolates have their own security manager, application classpath, and disjoint heap. They share the statics of all of the classes with AWT. Isolates cannot share any objects between them. An Isolate has a halt () method that unlike the Thread.stop () method causes all the threads within the Isolate to stop and keep the state consistent. It's still recommended that this approach be pursued after attempts to shut down an Isolate have failed. An Isolate can communicate with another Isolate through a new mechanism called a Link, which is a class that is part of the Isolate API. A Link allows I/O objects such as files, and sockets to be passed between Isolates. RMI can just as well be used and in most cases may be preferable to Link. Thus each Isolate acts as a separate logical virtual machine. An Aggregate is a logical group of Isolates that share the runtime executable bytecodes and the class representation of all the classes within. An aggregate can contain one or many Isolates; however, it's not a class. Aggregates generally share state that is managed or owned by the operating system. State such as the "current working directory", the hostname, the user ID who launched the JVM, etc., are outside the JVM and are considered to be state at the aggregator level. Isolates can use all forms of external communication including RMI and RMI-over-IIOP.

More Stories By Murali Kaundinya

Murali Kaundinya is a Senior Enterprise Architect with Sun Software Services. At Sun, he helps customers with strategy for enterprise software architecture and delivers standards-based solutions.

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
JDJ News Desk 10/21/05 10:11:45 PM EDT

Isolating Concurrent Java Apps In JVM, Java Virtual Machine. It's not at all uncommon to see a server machine or even a desktop machine that runs the same or multiple applications each with its own Java Runtime Environment. In the server environment, aside from the scaling issues with garbage collection, the real motivation was for different applications to not be adversely affected by sharing application data and state within the same JVM. However, launching and running multiple processes, even on a server, comes with a price.

Java Developer's Journal 07/31/05 06:49:25 PM EDT

Isolating Concurrent Java Apps In JVM, Java Virtual Machine. It's not at all uncommon to see a server machine or even a desktop machine that runs the same or multiple applications each with its own Java Runtime Environment. In the server environment, aside from the scaling issues with garbage collection, the real motivation was for different applications to not be adversely affected by sharing application data and state within the same JVM. However, launching and running multiple processes, even on a server, comes with a price.