I’m currently working on a project using JMS. It’s my first experience with messaging, though I’ve read a bit about it; back in the dot.com boom, you could get the O’Reilly JMS book just for giving up demographic data (thanks Sonic!). However, this project is using JBossMQ, sending TextMessages containing XML into a number of Queues. I’ve integrated message sending into existing client applications. These applications come under heavy load periodically, so we wanted to make producing messages as simple as possible. The XML documents that these applications create are simply well-formed, and typically small. The consumers of these messages, on the other hand, undertake some fairly slow activities: they do some data massaging, and update or insert into multiple databases. Therefore, the consumers process messages asynchronously.
Such behavior demonstrates the strength of messaging (outlined most eloquently here): because of the decoupling between the producer of the message and the consumer, some objects can do “stuff” at a different rate of speed than the other objects which are needed to finish handling the “stuff”. The downside, of course, is the difficulty of receiving any form of confirmation (unlike typical synchronous systems, where, since the calling object blocks until return, passing back values is simple). Enterprise messaging systems, for which JMS simply provides a uniform (and somewhat limited) API, provide some guarantees–at least the producer can rest assured that the message did get to some consumer. This contract means that the producer can throw many many messages into a queue, confident that even if it takes a long time to parse and handle each message, every one will be passed off to a consumer. Of course, if the rates of message production and consumption are vastly different, there can be problems.
(When a component of an typical, synchronous system fails, then the caller is left to handle the wreckage. Since messaging systems interpose, when a consumer fails, the producer never finds out or has to deal with it.)
It seems like messaging systems would be great for integrating disparate systems as well–after all, message formats can be entirely arbitrary and don’t have to be understood by the messaging server at all. For example, this project has a perl program that was generating quite a bit of interesting data; it would have been nice to put this into a queue for a java program to consume. Unfortunately, the options for having a non-java producer participate in a JMS system are limited:
1. Some implementations provide client APIs for other languages (I saw a posting about SonicMQ and C++). JBossMQ has none that I could find.
2. Perl can call methods on java objects. A bit scary for a production system, and not a solution for producers/consumers written in other languages.
3. You could set up a java service listening on a port that would just take what’s given and send a JMS message containing that to a queue. Now you lose much of the robustness of a messaging solution, since you’re dependent on this service to make sure your messages get through.
4. Cut out the java service above, and decode the format that JBossMQ is using–since it’s listening on a port, and you have access to the JBossMQ source you could probably hack up a client to send a message directly. This would be a maintenance hassle and isn’t portable between JMS implementations.
The perl client problem ended up going away because we used a scalable, asynchronous message delivery system–Sendmail. (I wonder whether anyone has ever slapped JMS on top of Sendmail. A quick Google search showed nothing, but it seems like a natural pairing. I’m a bit worried about the reliability of delivery, but I’ve a sysadmin friend who says that if you control both the beginning and endpoints of a mail system, you can guarantee delivery.) All in all, JMS seems like a clean standard manner in which to enforce separation of concerns and gain a fair amount of robustness.
I love messaging. It is one of the number one underused parts of J2EE, and enterprise development in general.
It is a great way to do integration, and perfect for scaling up. As soon as your process is asynchronous you can manage the scale by simply creating more nodes that can pull things off of the queue/topic. Great stuff. (of course these agents have to not be hitting a bottleneck on the backside… e.g. a db)