Understanding AMQP, the protocol used by RabbitMQ

Engineering | Peter Ledbrook | June 14, 2010 | ...

Update I changed the first paragraph to clarify the relationship between RabbitMQ and JMS.

RabbitMQ is a lightweight, reliable, scalable and portable message broker. But unlike many message brokers familiar to Java developers, it's not based on JMS. Instead, your applications communicate with it via a platform-neutral, wire-level protocol: the Advanced Message Queuing Protocol (AMQP). Fortunately there's already a Java client library and SpringSource is working on first class Spring and Grails integration - so don't worry about having to do low-level stuff to use RabbitMQ. You can even find AMQP client libraries that expose a JMS interface. But AMQP is sufficiently different in operation from JMS that it might cause headaches for Java developers that are used to the JMS model.

In order to ease the transition, I'll be looking in this post at the basic concepts that underpin AMQP along with three common usage scenarios. By the end, you will hopefully have a good enough understanding to configure RabbitMQ and use it via the APIs provided by Spring and Grails.

Exchanges, queues, and bindings

Like any messaging system, AMQP is a message protocol that deals with publishers and consumers. The publishers produce the messages, the consumers pick them up and process them. It's the job of the message broker (such as RabbitMQ) to ensure that the messages from a publisher go to the right consumers. In order to do that, the broker uses two key components: exchanges and queues. The following diagram shows how they connect a publisher to a consumer:

rabbit-basics

As you can see, the setup is pretty straightforward. A publisher sends messages to a named exchange and a consumer pulls messages from a queue (or the queue pushes them to the consumer depending on the configuration). Of course, the connections have to be made in the first place, so how do publishers and consumers discover each other? Via the name of the exchange. Usually, either the publisher or consumer creates the exchange with a given name and then makes that name public. How that publication happens depends on the circumstances, but one might put it in public API documentation or send it to known clients.

How are the messages routed from the exchange to the queue? Good question. First, the queue has to be attached to the given exchange. Typically, a consumer creates a queue and attaches it to an exchange at the same time. Second, messages received by the exchange have to be matched to the queue - a process called "binding".

To understand binding, it's useful to understand the structure of an AMQP message:

rabbit-message

The headers and properties of the message are basically key/value pairs. The difference between them is that headers are defined by the AMQP specification whereas properties can contain arbitrary, application-specific information. The actual message content is just a sequence of bytes, so if you want to pass text around in your messages, then you should standardise on an encoding. UTF-8 is a good bet. You can specify a content type and encoding in the message headers if you want, but that's apparently not particularly common.

What does this have to do with binding? One of the standard headers is called routing-key and it is this that the broker uses to match messages to queues. Each queue specifies a "binding key" and if that key matches the value of the routing-key header, the queue receives the message.

Things are slightly complicated by the concept of exchange types. The AMQP spec. defines the following four types:

Exchange type Behaviour
Direct The binding key must match the routing key exactly - no wildcard support.
Topic Same as Direct, but wildcards are allowed in the binding key. '#' matches zero or more dot-delimited words and '*' matches exactly one such word.
Fanout The routing and binding keys are ignored - all published messages go to all bound queues.
Headers

Update I corrected the information on wildcards, which work on the basis of dot-delimited words or terms.

For example, say a publisher sends a message with a routing key of "NYSE" to a topic exchange called "Stocks". If a consumer creates a queue attached to "Stocks" with a binding key of "#", "*", or "NYSE", then that consumer will get the message because all three binding keys match "NYSE". However, if the message is published to a direct exchange, then the consumer will not get the message if the binding key is "#" or "*" since those characters are treated as literals, not wildcards. Interestingly, "#.#" will also match "NYSE" despite the routing key not having a dot.

Now consider a message with a routing key of "NYSE.TECH.MSFT". What binding keys will match it given that the message is going to a topic exchange?

Binding key Match?
NYSE.TECH.MSFT Yes
# Yes
NYSE.# Yes
*.* No
NYSE.* No
NYSE.TECH.* Yes
NYSE.*.MSFT Yes

That's really all there is to it. Flexibility is provided by support for multiple consumers per queue and multiple queues per exchange. In fact, a single queue can even be bound to multiple exchanges. Now let's look at some of those scenarios.

RPC

An AMQP broker can act as an RPC mechanism between a client and a service. The general setup is like this, using a direct exchange:

rabbit-rpc

The general sequence goes:

  1. Client sends message to the queue, specifying: (a) a routing key that matches the service; and (b) the name of a queue to pick the response up from.
  2. Exchange passes the message to the service's queue ("ops_q" in this case).
  3. The queue pushes the message to the service, which then does some work and sends a response message back to the exchange, specifying a routing_key that matches the reply queue.
  4. The client picks the response message off the reply queue.

From the perspective of the client, the call could either be blocking or non-blocking. How easy it is to do one or the other, though, depends on the client library in use.

The key to the RPC scenario is making sure that the client and service are using the same exchange for the initial request and that the client knows what to specify for the routing key.

As for the reply queue, it's typically created by the client, which then populates the reply_to header appropriately. Also, although you can use a different exchange for the replies compared to the requests, it's much more common to use the same exchange for both requests and replies.

Pub(lish)/Sub(scribe)

JMS has the concept of topic queues that ensure that messages from a publisher go to all subscribers. You can easily achieve the same behaviour in AMQP by binding multiple queues to an exchange like so:

rabbit-pub-sub

Even better, the queues can filter which messages they receive via the binding key. If a consumer wants to receive all messages, then it can specify a binding key of "#" - the "match any number of words" wildcard. Rather confusingly for your average developer, "*" matches zero or one (dot-delimited) words as mentioned earlier.

Work distribution

Imagine you have an application that has a bunch of jobs that need executing. With AMQP, you can hook up multiple consumers such that each job goes to one, and only one, of those consumers. The publisher doesn't care which consumer does the work, just that the work is done. This is work distribution.

Configuring it is pretty straightforward, as shown in this diagram:

rabbit-work

So you have one queue bound to the exchange with multiple consumers sharing that queue. This setup guarantees that only one consumer processes a given message, no matter how many consumers there are.

Those are the three main usage patterns for AMQP brokers. Although I have described each individually, it's fairly common to combine them. For example, you could have multiple services sharing the same queue (work distribution) in the RPC pattern. It's really up to you to decide how to configure the exchanges and queues, and now you should have a good enough understanding to work out the appropriate setup for your situation.

If you want to go further into AMQP, then check out the specification itself, particularly the section on General Architecture. And to get started with RabbitMQ, just go to its website.

Spring: the foundation for Grails

Engineering | Peter Ledbrook | June 08, 2010 | ...

In the SpringSource training course for Groovy & Grails, we highlight that Grails stands on the shoulders of giants. One of those giants is Spring. Without it, Grails simply wouldn't have been developed as quickly as it was. It probably wouldn't have the flexibility to integrate easily with enterprise Java systems either. Just look at the number of plugins available: many are based on Java libraries with Spring support.

In this post, I want to start by looking at how Grails uses Spring and then cover the various ways in which you can access that raw power and flexibility.

A child of Spring

You may not be aware of this, but when you create a Grails application you are also creating a Spring MVC one. Under the hood, Grails creates a variant of Spring MVC's DispatcherServlet and configures a bunch of beans to do the heavy lifting. Of course, this means that there is a Spring context underpinning your application - one that you have access to as you'll see later.

Here are some…

Using SpringSource Tool Suite 2.3.3.M1 with Roo and GWT

Engineering | Christian Dupuis | June 02, 2010 | ...

By now, most of you probably have heard about the announcements at Google I/O around Spring, Roo, STS and GWT. Ben and Rod covered this in their respective blog posts recently. If you missed the keynote I strongly recommend to watch the recording on YouTube to catch up (the relevant section starts at 1:09:00 into the recording).

Today I'd like to provide some detailed steps and instructions on how you can use Roo and STS to create your first GWT application.

Installation

Before we can fire up the Roo shell and start typing commands, we need to download and install all pre-requisites. Although a lot of…

What's a plugin-oriented architecture?

Engineering | Peter Ledbrook | June 01, 2010 | ...

Grails is a fantastic framework for developing web applications quickly and easily. You also have access to a plethora of plugins that provide features or make integration with other systems nice and easy. That's all good, but in this article I want to talk about what happens when your application grows and you start drowning in a sea of controllers, domain classes, and other files.

Separation of concerns

One of the most useful patterns in software architecture is called separation of concerns. The idea is that you group everything related to a particular feature or concern into a single, self-contained unit. The code in that unit should not take on any other responsibility. For example, the business logic of a web service should be in one class while the handling of SOAP messages should be in another: the business logic and SOAP handling are two different concerns.

The real beauty of this pattern is that you can aggregate these units into coarser-grained concerns, so you end up using the pattern at multiple levels. For example, say that the web service mentioned above…

SpringSource dm Server 2.0.2 is released today.

Engineering | Christopher Frost | May 27, 2010 | ...

The release fixes a few bugs, release notes available from JIRA. This release can be downloaded from the project page on SpringSource.org.

  • The kernel startup hard timeout limit has been increased to allow dm Server to run on slower machines.
  • Documented a restriction in the OSGi web container, Tomcat <context> elements are not supported.
  • Fix to the ServiceScoper class to close all input streams.
  • Added support to tolerate File.list returning null occasionally, this manifested as the pickup directory wiping itself occasionally for seemingly no reason.
  • Usage of @Configurable with ServerOsgiBundleXmlWebApplicationContext now works.

The project is being donated to the Eclipse Foundation as Virgo. We aim to ship a baseline release of Virgo in due course which will be functionally equivalent to dm Server 2.0. See the Virgo website for further information. Along with dm Server SpringSource will offer commercial support for Virgo.

Spring Insight 1.0.0.M3 Released

Engineering | Jon Travis | May 26, 2010 | ...

The Spring Insight team is proud to announce the release of Spring Insight 1.0.0.M3.  This release contains a ton of new enhancements to give you more productivity and get your application to production even faster.  Spring Insight is available as part of tc Server Developer Edition and SpringSource Tool Suite but you can snag the new developer release at http://springsource.org/insight.  Setup time will take you the usual 10 seconds.

Spring Insight 1.0.0.M3 Screencast

Speed Tracer

The most-publicized new feature is our integration with Google Speed Tracer, which was announced at last week's Google IO conference.  This innovative combination gives developers a full view into all the work performed in a web request --  from CSS styling and view rendering to JDBC queries and JSP render times.  It was a real thrill to work with Google's engineers to come up with some cutting-edge use of this technology.  You'll love this feature!  It's a seamless integration that's trivial to work with and gives you a great deal of visibility you've never had before.

Simpler UI

We've also added a lot of information to the application: throughput and error rate metrics, health zones, deeper visibility into Spring controllers, deeper JDBC support, application health and more.  This new information should not be overwhelming, however, because we have also invested a lot of time in simplicity, making our UI obvious and easy to navigate.

Development Kit

Finally, we published our Insight Development Kit (IDK).  We've heard from many users that they want the ability to customize their application in Insight or want to add additional metrics.  Insight now provides this capability with its @InsightOperation and @InsightEndPoint annotations as well as the IDK and tutorials for creating deeper plugins.  The IDK includes the source for all the plugins that come with Insight (Apache 2.0 licensed) as well as the IDK APIs -- great examples and instructions for writing your own application.

The Spring Insight team is cranking on the next release, our train is cruising down the track, and we can't wait to hear your feedback and suggestions.  Go grab the release off http://springsource.org/insight and leave us a comment in the community forums

Spring Python 1.1 book is published

Engineering | Greg L. Turnquist | May 24, 2010 | ...

The Spring Python 1.1 book is published! Spring Python takes the concepts of the Spring Framework and Spring Security, and applies them to the world of Python.

In this book, you will be writing code using dependency injection, aspect oriented programming, data access, transaction management, remoting and security. Later on in the first case study, you will be building a banking web app and see how using all these components in concert quickly meets your needs. In the second case study you will integrate Python and Java together as you build a flight reservation system.

The book is full of code…

More Grails 1.3 features

Engineering | Peter Ledbrook | May 24, 2010 | ...

Last week, I described how Grails now treats plugins like normal dependencies that can be pulled from Maven-compatible repositories. Although this was the big new feature for 1.3, it wasn't the only one. In this post, I'll look at some of the others, starting with a feature that I only recently found out about.

Named queries

GORM provides three distinct ways of performing database queries:
  • dynamic finders, e.g. Book.findByTitleAndAuthorLike(...);
  • criteria queries, which use a nice DSL; and
  • HQL, Hibernate's SQL-like query language.
These three features provide a potent mix of ease-of-use and power, providing you with the flexibility you need. And yet there's something missing.

Develop a non-trivial Grails application and you will soon realise that you often use the same queries again and again. What should you do? The copy-and-paste technique is simple but leaves you with major maintenance issues. You could write service methods for each of your common…

Spring Roo 1.1.0.M1 Released

Engineering | Ben Alex | May 19, 2010 | ...

I'm delighted to announce that we've just released Spring Roo 1.1.0.M1. Spring Roo is the fastest way for Java developers to build Spring-based applications in the Java programming language. With the Roo 1.1.0.M1 you can build working web applications - complete with a Google Web Toolkit (GWT) front end - in as little as 200 keystrokes! Plus as usual we've concurrently released a new version of SpringSource Tool Suite (STS 2.3.3.M1) which is optimised for the latest and greatest Roo goodies!

There are over 200 fixes, enhancements and new features since our 1.0.2 release three months ago. Some…

Get the Spring newsletter

Stay connected with the Spring newsletter

Subscribe

Get ahead

VMware offers training and certification to turbo-charge your progress.

Learn more

Get support

Tanzu Spring offers support and binaries for OpenJDK™, Spring, and Apache Tomcat® in one simple subscription.

Learn more

Upcoming events

Check out all the upcoming events in the Spring community.

View all