Archive for the ‘Hasenwerkstatt’ Category

AMQP 1.0 prototyping

Wednesday, December 1st, 2010

We have been prototyping support for a new protocol, as is our wont. This one is called "AMQP 1.0 R0", and it is the new issue from the AMQP working group (of which RabbitMQ, and latterly VMware, are a member). The "R0" indicates that it's the first revision of a recommendation. The specification is incomplete: there are many TODOs, and to a large extent it is unproven. Those two facts are part of what prompted this prototyping.

The prototype code is mirrored at github: It is built just the same as all our plugins.

The AMQP 1.0 R0 specification differs from the specification of previous versions of AMQP, in that it does not define a broker model; i.e., it doesn't define exchanges queues and bindings, or their equivalents. The protocol is really only about transferring messages from one agent to another, and then agreeing on what the outcome was. That means it is amenable to bolting on to a message broker implementation, among other uses -- the idea is that one can adapt an existing model to suit.

In our case, the incumbent model is that of AMQP 0-9-1, with some generalisations and extensions (for example, chained bindings). Our target with the prototype is therefore to be able to get something useful done with both 1.0 clients and 0-9-1 clients connected at the same time.

Well, the good news is, we've achieved that. In fact the plugin can be set up to replace Rabbit's usual network listener, and will happily talk to AMQP 0-8, 0-9-1, and 1.0 clients. We did have to do some invention along the way, and there are some parts of the specification that we are conspicuously not implementing. These will be detailed in the README soon.

One large part of the invention is to fill in semantics where the specification is silent. Some of these are detailed in this client-broker protocol work we did for the AMQP working group. We're hoping the prototyping will help fill this out some more.

Next week I'll be taking our prototype to the AMQP 1.0 "Connectathon", where it'll be tested against other implementations of the core protocol (not all of which are open source). Again, this will help to flush out barriers to interoperability in the specification.

rabbitmq + node.js = rabbit.js

Friday, November 12th, 2010

For those who have been away from the internets, node.js is an evented JavaScript engine based on Google's V8. Because it is essentially one big, efficient event loop, it's a natural fit for programs that shuffle data backwards and forwards with little state in-between. And it's fun to program, an opinion apparently lots of people share, because there have been loads of libraries crop up around it.

Among the more impressive of these libraries is Socket.IO. One can combine Socket.IO with node.js's built-in web server to make a websocket server, with a socket abstraction for browsers that degrades to XHR tricks for when there's no websockets. (I would be happy to believe that node.js and Socket.IO were made for us by a benevolent and foresightful precursor race; but of course, they were made by hard-working clever people. Thank you, people!)

Once one has a socket abstraction in the browser, a whole world opens up. Specifically, for our purposes, a whole world of messaging. Since node.js has an AMQP client, we can easily hook it up with RabbitMQ; not only to bridge to other protocols and back-end systems, but also to provide messaging between browsers, and between application servers, and so on.

Following on from the work we've been doing with Martin Sustrik of ZeroMQ, I decided to make a very simple protocol for using on the browser sockets, reflecting the messaging patterns used in ZeroMQ (and thereby in RMQ-0MQ) -- pub/sub, request/reply, and push/pull (or pipeline). I wrote a node.js library that uses RabbitMQ to implement message patterns using its routing and buffering; the bridging then comes for free, since RabbitMQ has a bunch of protocol adapters and clients for various languages.

A brief explanation of the messaging patterns:

Publish/Subscribe is for the situation in which a published message should be delivered to multiple subscribers. In the general case, various kinds of routing can be used to filter the messages for each subscriber. This might be used to broadcast notifications from a backend system to users' browsers, for example.

Request/Reply is for RPC over messaging; requests are distributed round-robin among worker processes, and replies are routed back to the requesting socket. This might be used by browsers to query back-end services; or even for browsers to query each other.

Pipeline is for chaining together processes. Messages are pushed to worker processes in a round-robin, which themselves may push to another stage of processing. This might be used to co-ordinate a workflow among sets of users (or indeed individuals).

Having duly dispensed with ado, here is rabbit.js.

All it needs is a bare-bones RabbitMQ and node.js installed; and, the node-amqp and Socket.IO libraries. Instructions and the locations of these things are in the README. (Do note that you need my fork of node-amqp.)

It also includes a tiny message socket server; that is, a node.js server that accepts socket connections and speaks in length-prefixed messages. Since it's all going through RabbitMQ, you can talk to the browsers hooked up with Socket.IO via a socket. You can also use the in-process pipe server from code running in node.js itself.

All in all, I am surprised how much I could get done with only a handful of lines of code and some technologies that each hit a sweet spot -- node.js for fun network server programming, Socket.IO for magical browser sockets, and RabbitMQ for the no-tears messaging.

RabbitMQ/0MQ bridge

Monday, October 18th, 2010

Recently, Michael Bridgen and I implemented a bridge to connect the RabbitMQ broker with applications using 0MQ for messaging.

Here it is:

So: What kind of benefit the users can get by using both products in parallel?

In short, there are two different points of view involved here. RabbitMQ users will experience different benefits than users of 0MQ. Those already using both will simply get an easy way to interconnect the two technologies.

This is RabbitMQ blog so let's start with Rabbit-focused point of view.

First and most obviously, using 0MQ as a client for RabbitMQ broker makes sense on the platforms where there's no AMQP client available. Ever fancied speaking to RabbitMQ broker from Lisp? Or -- say -- from Cobol? The bridge may come handy here.

The same applies to OS/HW platforms. Do you need to speak to the broker from a device heavily constrained on memory, with very slow CPU or limited battery life? 0MQ client is pretty concise and very fast, which means that you'll get reasonable performance even on slow chips. Effectiveness also translates to lower power consumption, which in turn makes the battery last longer. The r0mq bridge itself is collocated with the RabbitMQ broker requiring no additional resources on the client.

Another usage of the bridge is much more sophisticated. If you are using RabbitMQ in very simple scenarios you may not even appreciate it. If you are managing a big geographically distributed system, it may become a lifesaver. The bridge can be used to interconnect RabbitMQ brokers into loose federation. Just edit the configuration files for the two brokers and everything will just work. You won't have to care about order of starting up the brokers, managing the reconnections after network disruptions etc. A nice feature is that these federations are truly distributed. There's no need for central governance of the federation. Simply connect your broker to a broker in a different company. That one in turn connects to brokers in yet different companies etc. Ultimately you end up with loose world-wide federation maintained in collaborative fashion by all the participants.

Yet one more advantage you may take advantage of is efficient usage of network resources. Unlike AMQP, 0MQ allows you to split your messaging traffic into logically separate flows. You pass your entertainment video in a separate flow from commands used to keep the aircraft flying. This not only means that you'll never experience head-of-line blocking problems, but also that network-level QoS can be set separately for the entertainment channel and for the steering system. Also, network engineers will appreciate that you can monitor the network traffic flow-by-flow rather than having a big opaque chunk of bandwidth used by "messaging".

Finally, 0MQ is bundled with OpenPGM library which implements a reliable mutlicast protocol called PGM. The r0mq bridge thus allows to multicast messages from RabbitMQ broker to the clients (0MQ clients to be precise -- AMQP has no multicast support). This kind of functionality is extremely useful in scenarios where a lot of identical data is passed to many boxes on the LAN. If a separate copy of each datum is sent to each subscriber, you can easily exceed capacity of your network. With multicast, data is sent once only to all the subscribers thus keeping the bandwidth usage constant even when the number of subscribers grows.

When you looking at r0mq bridge from the other side, you are probably developing at a low level using 0MQ as your network transport.

Using RabbitMQ broker has some obvious uses. The most trivial of them is to use the broker as a bridge to connect 0MQ applications to AMQP, STOMP or XMPP applications.

However, the real use case is to use RabbitMQ as a "device" in 0MQ network. 0MQ comes with few simple precompiled devices. Some hardware can be used as 0MQ device (say IP switch in case of multicast transport). There've been some attempts to create more sophisticated devices but these are in very early stages of development. So, what 0MQ developers are missing is a full-blown, sophisticated and production-ready device.

RabbitMQ broker can serve as such a device. First of all, it has been deployed widely and thus it is stable enough to be used in production environment safely. As for the feature set, it offers much more than anything found in 0MQ world. The two most useful features are persistence and monitoring.

Persistence means that the messages passing through the broker are saved on the disk. When you shut down the broker, if the box crashes because of power outage or a different technical problem, the messages are still available on the disk. When the broker is restarted they will be sent further as if the crash hasn't happened. It is similar to how email works.

Monitoring is asked for maybe even more often than persistence. Once you have a non-trivial system you want to know what each node is doing: How many messages there are stored for a particular feed What's the current throughput? And so on. RabbitMQ can tell you these things through its command-line tools or through the management plugin.

As a conclusion I would like to stress that bridging 0MQ and RabbitMQ is not just that dumb kind of bridge you get when you bridge two incompatible but more or less equivalent products. RabbitMQ and 0MQ are focusing on different aspects of messaging. 0MQ puts much more focus on how the messages are transferred over the wire. RabbitMQ, on the other hand, focuses on how messages are stored, filtered and monitored. By combining the two technologies you can get the best from both worlds.