Académique Documents
Professionnel Documents
Culture Documents
26 May 2010
Modern enterprise systems are being confronted with the need for more complex
processing, coupled with higher loads and greater demand for resources. This reality
is driving a need for separation of functional units and motivating the use of
asynchronous methods to accomplish work and aggregate results. This article
describes an example that brings the power and scalability of IBM® WebSphere®
eXtreme Scale to work on the problem, providing nearly limitless flexibility and
expandability to the asynchronous paradigm.
Introduction
Even the most casual observers of technology must be aware of the migration
toward systems and services that can perform increasingly more complex tasks with
more data sources than ever before, and all with an interface that's even easier to
use. Mash-up is the term that’s been coined to express this concept. For example,
providing comprehensive and detailed street maps is good. Adding current traffic
data to the maps is even better. And including the closest place to get lunch with
user ratings? Now that’s cool.
Whether it's something for the average consumer or within the massive grids of a
financial trading system, the trend is obvious. Making more decisions based on more
data sources more quickly is becoming vital to cutting-edge systems. Luckily, we're
starting to learn exactly what it takes to get these kinds of problems solved, and one
of the best tools for this evolution is a move from synchronous, linear processing to
With an asynchronous model, the queue itself acts as a relief valve. The slow
component is isolated behind the queue, and the biggest effect is requests building
up in the queue, which will eventually catch up. Even if it never does, only the
services dependent on the slow resource will be affected. This decoupling has an
effect on the overall system that will prevent bottlenecks during scale-up simply due
to the fact that each resource is able to act independently.
There are several benefits to using WebSphere eXtreme Scale over the established
frameworks (such as JMS and other messaging infrastructures) for asynchronous
processing:
An example
Let's implement a simple "Hello World" application to illustrate the simplicity of the
WebSphere eXtreme Scale asynchronous service framework. This example will
dispatch a message into the grid, identify which grid partition has been assigned to
process the message, and return that information back to the dispatcher. While this
is a simple example, you'll see the core concepts in action, which you can apply to a
wide variety of applications.
First, you need to define the message itself, as well as the business logic to be
processed. Do this by creating a POJO that implements the "serializable" interface.
This interface indicates that the object can be sent as a parameter with a remote
method call, which is the basic requirement of any object being inserted into a
WebSphere eXtreme Scale grid.
package com.ibm.websphere.asyncservice.test;
import java.io.Serializable;
public class TestMessage implements Serializable {
This object serves as the data container for the work that needs to be done upon
receipt of the message in the grid. In this case, you’ll stick to a single Integer field
which will be used as a unique identifier and enable you to track the progress of a
message through the grid.
When such an instance is inserted into the grid, the grid partition that receives the
message will execute the logic in the message listener using the data in the instance
via a local pool of threads devoted only to processing these requests. We'll call this
pool a processing unit, with one pool hosted in each shard. Configuration of the
processing unit can be achieved with some use of the Spring framework (to be
covered in an upcoming article). By default, each processing unit uses three threads,
and since this is replicated for each partition, it would likely be ideal for many types
of applications.
To implement the message processing logic, you need only create a class that
implements the
com.ibm.websphere.objectgrid.asyncservice.MessageProcessor interface,
which only requires the implementation of a method called onMessage. This
method is passed a unique message ID, a reference to the grid where the message
was sent, as well as the message itself as an object. The code for this is shown in
Listing 2.
package com.ibm.websphere.asyncservice.test;
import java.io.Serializable;
import com.ibm.websphere.objectgrid.Session;
import com.ibm.websphere.objectgrid.asyncservice.MessageProcessor;
public class TestProcessor implements MessageProcessor<Integer> {
public Integer onMessage(Session session, String msgId, Serializable msg){
int partitionId = session.getObjectGrid().getMap("Queue").getPartitionId();
TestMessage testMsg = (TestMessage) msg;
System.out.println("SHARD: Message " + testMsg.id + " processed by partition "
+ partitionId);
return partitionId;
}
}
This example returns an Integer object that identifies the processing partition's ID to
the process/thread that initially sent the message. The asynchronous service
framework will take this value and fulfill the Future object that was returned to the
client so that any client processes interested in this value will then be able to
The client
Let's take a look at what you would do to send one of these messages into the grid
and process the result.
Apart from the brief code segment in Listing 3, there is also a bit of code needed to
create the connection to the grid represented by the clientGrid object, which will be
covered next when we discuss WebSphere eXtreme Scale deployment details.
Once the message has been sent, the sender can store a reference to the Future
object and check periodically for completion, or it can block and wait if needed by
calling the get() method. The code in Listing 3 shows a blocking call, in which the
client waits until the messsage has been processed to report which grid partition was
chosen to consume the message.
The source code and deployment files for this example are included with this article
for download. In addition, you’ll find links for obtaining the asynchronous service
framework as well as a fully functional trial version of WebSphere eXtreme Scale in
the Resources section.
The grid
The included sample grid can be started and deployed in two ways. The first is a
simple in-process catalog service and container, which is convenient for
development environments and quick testing. For the second, scripts are provided to
deploy standalone grid containers which might be deployed across a cluster of
machines. This would be the standard type of deployment for a production or
performance testing environment.
• In-process grid
Deploying and running the sample with an in-process grid is the easiest
way to see these concepts in action. A script is provided to run the client.
When this script is run with no arguments, the grid is automatically
deployed in-process. No other changes are necessary. If you've imported
the code into Eclipse or a similar IDE, simply run the main method from
the com.ibm.websphere.asyncservice.test.TestClient class to accomplish
the same function.
• Remote grid
Start by launching a catalog service, which is described in the scripts
included with the sample. You can find these scripts in the bin directory of
the sample code and need only change the JAVA_HOME variable in
env.sh to reflect the path to your desired JVM, and the directory where
the WebSphere eXtreme Scale product code is located.
With your server processes started, you can connect to and use the grid
by retrieving your reference to the WebSphere eXtreme Scale grid in the
client with the code shown in Listing 4.
// Connect to the Catalog Server. The security and client override XML are not specified
ClientClusterContext ccc = ObjectGridManagerFactory.getObjectGridManager()
.connect(“localhost”, null, null);
Based on the standard WebSphere eXtreme Scale development pattern, you first
get a context object from the catalog service (here deployed on localhost, which
should be changed or parameterized for a remote catalog service). Then, you get a
reference to the grid, which is subsequently provided to the
AsyncServiceManagerImpl object above to send the asynchronous messages.
The runclient.sh script can also be used to run the sample against a remote grid by
providing the hostname and port to the processing unit grid's catalog service as a
single parameter. For example, execute the command runclient.sh
localhost:2809 to run the client against a grid deployed on the local machine.
Runtime
The purpose here was to maximize scalability and reliability. From a scalability
perspective, you only need to start additional JVMs to participate in the grid, which
will automatically start servicing asynchronous messaging requests. More capacity is
as simple as starting a new JVM with the same command line above, save for a new
unique server ID, easily providing additional processing resources.
An important detail to mention is that "deliver once" is within the context of your
message listener implementation. The asynchronous service framework will deliver
and commit the message in the grid ONLY once, however because of failure
windows it is possible that the actual logic in the listener might be executed more
than once. This means that if the listener logic changes any state in an external data
source (database, mainframe, and so on) then these interactions must be treated
with an "at least once" delivery paradigm. To be clear, the onMessage method will
be processed in its entirety only once, but it might be attempted multiple times and,
as such, portions of the method might be executed multiple times. For example, if a
container JVM fails while processing a message, the onMessage method will be
executed again on the new primary partition once it is promoted. Any code that
might have had an effect on outside resources must be aware of this possibility.
Transactional considerations
This framework, as well as WebSphere eXtreme Scale on which it is based, does
not formally participate in JTA transactions (WebSphere eXtreme Scale has its own
transaction manager). However, the standard "nesting" technique can be used to
make the processing of a message a logical part of a JTA transaction. That is, your
listener (MessageProcessor) can be written to perform the following logic in this
order, insuring that each step has succeeded prior to beginning the next:
2. Process a message.
If any step fails (for example, you fail to successfully mark the message as
processed), you can rollback the JTA transaction and that message can be validly
processed again. The above logic makes the act of processing a message a logical
participant in the JTA transaction.
Conclusion
This article illustrated the WebSphere eXtreme Scale asynchronous service
framework that is available as a sample for deployment in your environment. The
example shown here demonstrated this new capability of WebSphere eXtreme
Scale servers to help solve some of the more troubling and challenging growth
issues in an ever-changing transaction processing environment. Asynchronous
archetypes and the scalable environments they create will be essential in many
evolving systems.
Resources
Learn
• WebSphere eXtreme Scale product information
• WebSphere eXtreme Scale Information Center
• WebSphere eXtreme Scale documentation library
• Redbook: User's Guide to WebSphere eXtreme Scale.
• IBM developerWorks WebSphere
• Billy Newport's XTP blog
• WebSphere Extreme Scale YouTube channel
Get products and technologies
• Download the Asynchronous Service Framework from the WebSphere eXtreme
Scale Samples Gallery
• Download IBM WebSphere eXtreme Scale trial version
• WebSphere eXtreme Scale Amazon EC2 Images (AMIs) (Development and
Production).
Discuss
• Engage with the development community as well as the eXtreme Scale product
team! Get your questions answered at the WebSphere XD forum