Sunday, 24 June 2012

Mule meet ZeroMQ. ZeroMQ meet Mule.

These past few weeks I've been experimenting with ZeroMQ (a.k.a. ØMQ or ZMQ). I like the idea of a library that provides you the building blocks for constructing your own messaging architecture. For example, we may want to send messages to an application that might be unavailable at times. In our system, losing some messages isn't the end of the world so we don't need to have a high degree of message reliability. A common solution for this type of problem is to introduce a message broker, such as ActiveMQ, and let the broker worry about making sure that messages are eventually delivered to the recipient.

The main disadvantage of this approach is that a broker adds another hop to the path of the message. Also, a broker is another point in your distributed system where things could go wrong.

Another option is to let the sender ensure that the message gets delivered to the recipient. Since guaranteed message delivery isn't a requirement, we can afford to lose messages should the sender go down.

Using ØMQ's asynchronous socket-like API, we can easily implement this scenario in a few minutes. All we need is to submit the message to ØMQ, and ØMQ will deliver the message to the recipient on our behalf. However, because ØMQ has its own protocol, the library must be embedded within the sender and receiver applications.

This simple example just scratches the surface of what you can do with ØMQ. Real-world applications require the architecture to scale and ØMQ offers building blocks to tackle this challenge. Consult the ØMQ guide to learn more.

How does Mule, an integration framework, fit in with ØMQ? Well, one simple use-case is that even though the back-end is talking in ØMQ, the outside world is speaking in a standard language such as HTTP. Mule can serve as the bridge between the outside world and the ØMQ back-end as shown below:

On my GitHub page, you'll find the first release of the Mule 3 ZeroMQ Transport for ZeroMQ 2.2. This transport frees you from having to know all the details of ØMQ's API. Furthermore, you don't need to worry about processing messages concurrently: the transport takes care of that.

This snippet is all that it takes to implement the bridge in Mule. Those of you who are familiar with ØMQ API should find the zeromq:outbound-endpoint easy to understand. The outbound-endpoint is telling ØMQ to "connect" to the receiver listening on port 9090. All of this will happen once, at initialisation time. At run-time, the outbound-endpoint will transform messages to arrays of bytes and send them off to the receiver. Replies are returned by the outbound-endpoint as arrays of bytes. 

The exchange pattern request-response is just one of several exchange patterns the ØMQ transport supports. What if we don't want to wait for the reply from the back-end? Just set the exchange pattern to one-way. ØMQ folks, you may specify push instead of one-way. The same code is executed underneath.

Of course, it's quite possible that we have another Mule instance on the other end accepting ØMQ messages as shown below:

Apart from different exchange patterns (see the project's README for the complete list of supported exchange patterns) and socket operations (i.e., connect and bind), the transport also supports multi-part messages. In the event a ØMQ inbound-endpoint receives a multi-part message, a java.util.List is spit out. Each element in the list is a byte array representing a message part. 

The outbound-endpoint works a little different when it comes to multi-part messages. To send a multi-part message, the multipart attribute must be set to true on the outbound-endpoint. Additionally, the message must be a java.util.List where each element represents a message part.

Let me know how you find this transport and how it may be improved. Code contributions are more than welcome :-). Future releases of the transport will support missing features such as durable sockets so keep an eye on the repo.

1 comment: