55
AMQP and Beyond Messaging by Extending RabbitMQ Tony Garnock-Jones <[email protected]> Friday, 26 March 2010 I’d like to talk today about the what, the why, and the how of messaging; about approaches to building distributed systems using AMQP and RabbitMQ in particular, that are motivated by real use cases. I’m going to show how extending RabbitMQ with plugins and new exchange types can help build elegant solutions to these kinds of problems. Because this is an Erlang conference, I’m also going to talk a little bit about some of the Erlang features that make this easier.

AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

Page 1: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

AMQP and BeyondMessaging by Extending RabbitMQ

Tony Garnock-Jones <[email protected]>

Friday, 26 March 2010

I’d like to talk today about the what, the why, and the how of messaging; about approaches to building distributed systems using AMQP and RabbitMQ in particular, that are motivated by real use cases. I’m going to show how extending RabbitMQ with plugins and new exchange types can help build elegant solutions to these kinds of problems. Because this is an Erlang conference, I’m also going to talk a little bit about some of the Erlang features that make this easier.

Page 2: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Why messaging?

Database is to Filesystemas

Messaging is to Network

Messaging abstracts away from the details of your network topology

SQL

AMQP

Friday, 26 March 2010

So what is messaging, and why should you care about it? One way of thinking about it is as a way of abstracting away from the fine details of your network topology when you’re designing and building a distributed system. Just as Databases give you a high-level means of working with a data store, the file system, a good messaging system should give you a high-level means of working with communications between parts of a distributed system.

Page 3: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Why messaging?

• Scaling, load-balancing

• Delayed jobs, task queues

• Multicast, broadcast

• Trusted store-and-forward

• Management, monitoring

• Decoupling of components

Friday, 26 March 2010

In terms of distributed system architecture, messaging can help with the scaling of a system, with ensuring good resource usage, and with batching and batch processing. In terms of simple communications between applications, messaging systems often offer seamless support for multicast and broadcast communication just as easily as point-to-point communication. Messaging systems can let you place trust in the network to eventually get your message through---think Fedex---and they’re often engineered to give you good insight into and control over the behaviour of your messaging networks. Ultimately, they let you decouple components from each other, helping you build systems that are more flexible, more performant, and easier to understand.

Page 4: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

What is messaging?

Relaying and filtering

Buffering and queueing

msg

ack

Transfer ofresponsibility

Naming

Friday, 26 March 2010

The basic elements of a messaging systemA messaging system...- Provides names for resources in the abstract network- Relays and filters messages, like mailman on steroids- Buffers and queues messages in mailboxes, for later consumption- Carefully transfers responsibility for reliable deliveries

Page 5: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Where is messaging?

Enterprise Service Bus

Client/Server and Hub n' Spoke

Peer Network

Pipeline

Enterprise Service Network

Friday, 26 March 2010

It is, of course, everywhere. If messaging is an abstraction over your network, like databases are an abstraction over your filesystem, then we should expect to see messaging in a lot of different network contexts. And we do.

Page 6: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Why AMQP?

Friday, 26 March 2010

A few slides back I compared AMQP to SQL. To explain why I think that’s not an unreasonable analogy, I need to explain a little more about AMQP.

The protocol originated at JP Morgan Chase, who decided they’d had enough of paying annual fees for expensive, closed, non-interoperable systems. They started off wanting a JMS replacement that could cover their use cases -- essentially the features of Tibco RV (topics, unreliable, fast) combined with those of MQ series (queues, reliable, slowish). The spec evolved into a general framework for messaging.

Page 7: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

The Options

• JMS?

• API-only: lots of baggage if you’re dealing with multiple brokers; lock-in

• Fine for Java, but ...

• Tibco RV? $$$

• IBM MQ Series? $$$

Friday, 26 March 2010

There were other options out there, but they all failed to satisfy one or other of the requirements. (Expensive, closed, non-interoperable)

Page 8: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

The Options

• XMPP?

• transport, not messaging (modulo xep60)

• HTTP?

• transport, not messaging

• SMTP + mailman?

• slow, heavy; fiddly to set up

• Redis, kestrel, starling, ...

• vertical solutions

Friday, 26 March 2010

Some of the options are a little more open or interoperable than others.

XMPP; HTTP; SMTP and mailman

Redis, kestrel, starling: These systems tend to concentrate on only one or two of the use cases motivating AMQP, often omitting the flexibility of relaying and filtering that AMQP provides. You could think of the difference between something like CouchDB and something like PostgreSQL.

Page 9: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

The Options

• Queue up work in your DB?

• Not designed for messaging!

• Scaling up can be awkward

• Use the filesystem?

Friday, 26 March 2010

Finally, there’s always the old fallback of rolling your own. It almost always ends up in problems.

Page 10: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

AMQP

• General model for messaging

• Simple, efficient transport

• Wire-level protocol helps avoid vendor lock-in

• API-neutral, multi-language

• Configuration & management within the protocol

Friday, 26 March 2010

Page 11: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

AMQP Specification

• Version 0-8 released June 2006

• Version 0-9-1 released Nov 2008(“Interop” release of spec)

• Version 1.0 being developed currently

Friday, 26 March 2010

If you read one spec document, read the 0-9-1 spec document. The 0-8 spec is really pretty great as specs go, but there are bugs and unclear areas in it which have been cleaned up for 0-9-1. The 1.0 spec is proceeding nicely, but there’s still a lot of work to be done before it’s at the same level as the 0-9-1 spec is.

Page 12: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

X

AMQP Model

Exchanges

QueuesQ

bind to

(0-9-1)

App

App

Producers

Consumers

publish to

deliver to

Friday, 26 March 2010

In explaining the AMQP model, roughly en par with the relational calculus in the database world, but not yet formalised as well, I’ll start from the consumer side and work back along the pipeline.

Consumers create queues; these buffer messages for pushQueues are stateful, ordered, and can be persistent or transient, private or shared.Exchanges are stateless routing tables.Consumers tell queues to bind to named exchanges; each binding has a pattern or filter, e.g. “bob” or “*.ibm.*”Producers send messages to exchanges with a routing key e.g. “bob”, or “buy.ibm.nyse”, some headers, and an uninterpreted binary body.Exchanges route messages to queues whose binding patterns match the message

** but **Sometimes AMQP isn’t enoughPeople are starting to think in terms of having a programmable networkAMQP takes steps in this direction but isn’t quite there yetSo this is where RabbitMQ comes in. RabbitMQ implements the AMQP spec as faithfully as possible, and provides hooks for exploring the possibilities beyond AMQP.

Page 13: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

RabbitMQGoal: Do the right thing, out-of-the-box

“RabbitMQ is a pleasure to use and it just works. Everyday, every time, every message” - Michael Arnoldus, project lead, algo trading firm

“In my experience, you can have a clustered rabbitmq setup running at home in under 20 minutes. It's all in the admin guide.”Steve Jenson, Scala hacker

Friday, 26 March 2010

Page 14: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

RabbitMQ

• Erlang/OTP AMQP broker

• Ships with Ubuntu

• Clients for C, Java, C#, Python, Ruby, PHP, ...

• Supports (almost) all the protocol

• Persistent, Transactional, Clusterable, ...

• Connectors for lots of other networks

Friday, 26 March 2010

Page 15: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

RabbitMQ Universe

Friday, 26 March 2010

This is an old picture now. It was put together back in 2008. Things have changed a little since then: we’ve seen some new client libraries appear, and the new plugin feature has helped extend the reach of the core server functionality even into some environments where an AMQP client isn’t available. The core AMQP model stays the same, but the language used to access it can vary quite a lot without causing problems.

Page 16: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Beyond core AMQP

Friday, 26 March 2010

Now that I’ve covered the core AMQP model and Rabbit’s relation to it, I’m going to present a couple of motivating examples of applications where plain old AMQP isn’t quite enough to let you build an elegant solution. As I go, I’ll introduce some of the ways RabbitMQ exposes hooks that can be used to make things cleaner.

Page 17: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

RabbitMQ Plugins

• Erlang applications bundled into a jar-like archive (*.ez)

• Booted as part of RabbitMQ startup

• “Boot steps” for integrating with Rabbit’s own startup sequence

• Exchange type registry (to appear in v1.8)

• Can do anything at all!

Friday, 26 March 2010

The main tool for customising RabbitMQ is the plugin system.

The design and implementation of RabbitMQ’s plugin system was done by my colleagues Paul Jones and Ben Hood. It’s a neat system, similar to Java’s war files, where a bundle of application functionality can be dropped into a special directory for RabbitMQ to notice next time it restarts. They can be used for anything at all, general-purpose or domain-specific, so now not only can you hook your distributed applications together using RabbitMQ as an intermediary, you can also embed parts of your applications into the server itself as custom plugins.

Page 18: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

RabbitMQ Pluginsrabbitmq-status

rabbitmq-jsonrpc-channelrabbitmq-jsonrpcrfc4627_jsonrpc

rabbitmq-mochiwebmochiweb

rabbit_stomprabbithub

rabbitmq-bqlamqp_client

rabbitmq-shovelrabbitmq-toke

Broker health check web pageAMQP over JSONRPC, for browsersJSONRPC server instance for RabbitJSON and JSONRPC libraryMochiweb instance for RabbitMochiweb library pluginSTOMP message transportPubSubHubBub implementationSQL-like Broker Query LanguageEmbedded AMQP clientBroker-to-broker relay pluginTokyo Cabinet support for new persister

Friday, 26 March 2010

There are already quite a few plugins available, for such things as embedding web functionality within RabbitMQ, extending RabbitMQ with new messaging transports, replicating messages from broker to broker in an HA setting, providing new command-line user interfaces to the broker, and supporting the new high-speed persistence engine that’s coming up in a release soon.

I’m going to be concentrating today on using plugins to augment the core AMQP model with new functionality to address some of its weaknesses.

Page 19: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

AMQP model limitations• No message transformation

• No custom message routing; you get exactly one of:

• Fanout,

• Direct,

• Topic, or

• Headers

• No stateful multicast

Friday, 26 March 2010

No transformation: what goes in, comes out unmodified (useful to be able to rely on it, but sometimes inconvenient)

No custom routing: you can’t mix and match behaviours, or do anything more complex than the ad-hoc glob-style topic matching or the weird pseudo-query-language for headers matching

No stateful multicast: Queues are the only stateful parts of the core AMQP, and they’re just a simple buffer. If you want parts of your messaging infrastructure to be stateful in other ways, like a hash table for example, you’re out of luck.

Page 20: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Example 1.

Friday, 26 March 2010

Page 21: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Github Commit Hooks

• URL-encoded JSON data blob

• Delivered by HTTP POST

• I want them in my XMPP client

• (Let’s ignore Github’s existing XMPP gateway!)

Friday, 26 March 2010

Github provides this wonderful feature of commit hooks, for integration with various messaging systems. Whenever I push a commit, it can invoke a webhook for me. ...

Page 22: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Github Commit HooksGithub

Custom HTTP

gateway

POST

X Q

“github”“[email protected]

ejabberd

mod_rabbitmq

my chatclient

Friday, 26 March 2010

This is an initial sketch of a solution, where we use only core AMQP features as well as the RabbitMQ adapter for ejabberd. If we’re going to implement this, we’ll need to build a custom HTTP receiver gateway, and unless we put some Github-specific logic into the gateway for un-URL-quoting and pretty-printing the JSON blob, we get a reasonably unfriendly message appearing in our chat windows.

Page 23: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Problems

• Need to respond to HTTP POST

• Want to transform “payload=%7b%22repository%22%3a%7b%22watchers%22...” to something nicer before sending it out over XMPP

Friday, 26 March 2010

Page 24: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Github Commit HooksGithub

RabbitHub

POST

X Q

“github”“[email protected]

ejabberd

mod_rabbitmq

my chatclient

Friday, 26 March 2010

To address the first problem, we can get some leverage out of the existing RabbitHub plugin, which is an implementation of the non-Atom-centric parts of a PubSubHubBub hub, meaning effectively an HTTP messaging gateway. It still leaves us with the problem of the unfriendly message ending up on the user’s screen.

Page 25: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Github Commit HooksGithub

RabbitHub

POST

XQ

“github”

[email protected]

ejabberd

mod_rabbitmq

my chatclient

X“github_pretty”

Decode & Prettify

Friday, 26 March 2010

For that, using unextended AMQP, we’d need to complicate our nice simple solution significantly. To interpose a program able to undo the URL-encoding and pretty-print the resulting JSON, we need to write, maintain, deploy, manage and monitor an external application running alongside the RabbitMQ broker, and within the broker we need to add a second exchange, which we subscribe to instead of the exchange that Github is posting into. Lots more moving pieces, lots more things to have to remember when working with the system.

Page 26: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

???

Github Commit HooksGithub

RabbitHub

POST

Q“[email protected]

ejabberd

mod_rabbitmq

my chatclient

“github”

Friday, 26 March 2010

What would really be nice would be to be able to perform the transforms on the message as part of the operation of the exchange itself, to avoid the conceptual clutter of a second exchange and the operational clutter of yet another daemon to keep running.

Page 27: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

‘x-script’ Exchange Type

• github.com/tonyg/script-exchange

• Embeds Spidermonkey and Python

• Upload filter & transformation scripts to the server (like stored procedures!)

• It’s a prototype/demo, for now

Friday, 26 March 2010

This has been bugging me for a while, long enough that I managed to find some time to do something about it. The result is the Script Exchange.

Page 28: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

‘x-script’ Exchange Typech.exchange_declare(exchange='github', type='x-script', arguments={ "type": "text/javascript", "definition": r""" return function (msg) { if (msg.body.substring(0, 8) == "payload=") { // It's a github hook! Unescape and // pretty-print. var b = msg.body.substring(8); b = JSON.parse(unescape(b)); msg.body = JSON.stringify(b, null, 2); } msg.fanout(); } """})

Friday, 26 March 2010

Page 29: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Transforms this...payload=%7b%22repository%22%3a%7b%22watchers%22%3a1%2c%22description%22%3a%22RabbitMQ%20%5c%22Script%20Exchange%5c%22%20plugin%22%2c%22open_issues%22%3a0%2c%22fork%22%3afalse%2c%22forks%22%3a0%2c%22url%22%3a%22http%3a%2f%2fgithub.com%2ftonyg%2fscript-exchange%22%2c%22private%22%3afalse%2c%22homepage%22%3a%22%22%2c%22owner%22%3a%7b%22email%22%3a%22tonygarnockjones%40gmail.com%22%2c%22name%22%3a%22tonyg%22%7d%2c%22name%22%3a%22script-exchange%22%7d%2c%22before%22%3a%220ed4a60180857f1b00afcc93fff6b42a7d27b39e%22%2c%22ref%22%3a%22refs%2fheads%2fmaster%22%2c%22commits%22%3a%5b%7b%22message%22%3a%22Make%20JS%20scripts%20interpreted%20as%20function%20bodies%20with%20their%20own%20scope.%22%2c%22removed%22%3a%5b%5d%2c%22url%22%3a%22http%3a%2f%2fgithub.com%2ftonyg%2fscript-exchange%2fcommit%2f095931d3f3c01284423999349a55164ab6a964d3%22%2c%22modified%22%3a%5b%22examples%2fexample_js.py%22%2c%22priv%2fjs_exchange_boot.js%22%5d%2c%22author%22%3a%7b%22email%22%3a%22tonygarnockjones%40gmail.com%22%2c%22name%22%3a%22Tony%20Garnock-Jones%22%7d%2c%22timestamp%22%3a%222010-03-07T01%3a45%3a48-08%3a00%22%2c%22added%22%3a%5b%5d%2c%22id%22%3a%22095931d3f3c01284423999349a55164ab6a964d3%22%7d%2c%7b%22message%22%3a%22Documentation.%22%2c%22removed%22%3a%5b%5d%2c%22url%22%3a%22http%3a%2f%2fgithub.com%2ftonyg%2fscript-exchange%2fcommit%2f7606a22d66169044c1352d956c63b362e783aca5%22%2c%22modified%22%3a%5b%22README.md%22%5d%2c%22author%22%3a%7b%22email%22%3a%22tonygarnockjones%40gmail.com%22%2c%22name%22%3a%22Tony%20Garnock-Jones%22%7d%2c%22timestamp%22%3a%222010-03-07T01%3a45%3a56-08%3a00%22%2c%22added%22%3a%5b%5d%2c%22id%22%3a%227606a22d66169044c1352d956c63b362e783aca5%22%7d%5d%2c%22after%22%3a%227606a22d66169044c1352d956c63b362e783aca5%22%7d

Friday, 26 March 2010

Page 30: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

...to this{ "repository":{ "watchers":1, "description":"RabbitMQ \"Script Exchange\" plugin", "open_issues":0, "fork":false, "forks":0, "url":"http://github.com/tonyg/script-exchange", "private":false, "homepage":"", "owner":{ "email":"[email protected]", "name":"tonyg" }, "name":"script-exchange" }, "before":"0ed4a60180857f1b00afcc93fff6b42a7d27b39e", ...

Friday, 26 March 2010

Page 31: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

What can it do?

• Rewrite routing key, properties, headers and body as desired

• Any or none of fanout-, direct-, and topic-style routing for each message

• No custom binding filter languages yet

• Security implications! (Salmon signatures)

• Be warned: it’s just a prototype for now

Friday, 26 March 2010

Page 32: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Example 2.

Friday, 26 March 2010

Page 33: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Stock Ticker

• Classic “Last Value Cache” pubsub

• New prices are arriving all the time

• When I connect, I want the newest price so far, without delay

• When the price updates, I want to hear it

Friday, 26 March 2010

Page 34: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Stock Ticker

Price Source X Q

“prices”“myapp”

my application

Friday, 26 March 2010

Here’s a sketch of a partial solution: an exchange, topic or direct, is used to route price quotes out to interested applications. It doesn’t solve the whole problem, though: when a new application connects, creates a queue, and binds it to the exchange, nothing is sent on to the application until a new price arrives.

Page 35: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Stock Ticker

Price Source X Q

“prices”“myapp”

my applicationHash Table

Price Cache

X “presence”

Friday, 26 March 2010

So what we’re forced to do is add an external price cache service, which is essentially a glorified hash-table. Whenever a new application connects, it sends a message to the price cache to let it know it’s there, including details on the prices it’s interested in. The price cache then sends the most recent information it has directly on to the new application’s queue. So we’ve now not only again got a whole separate program we have to write, maintain, deploy, manage and monitor, but we’ve also had to somewhat redundantly tell the price cache the same information as we told the broker when we actually bound our queue to the “prices” exchange. Double the protocol, double the opportunities for bugs.

Page 36: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

???

Stock Ticker

Price Source Q

“prices”“myapp”

my application

Friday, 26 March 2010

What we really want is a kind of exchange that manages the hash-table and sends out a catch-up message for us whenever a new binding is created.

Page 37: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

‘x-lvc’ Exchange Type

• github.com/squaremo/rabbitmq-lvc-plugin

• A Last Value Cache exchange type plugin

• Declared just like built-in exchange types, using Exchange.Declare

• Uses mnesia to hold the cache

• It’s a prototype/demo, for now

Friday, 26 March 2010

The Last Value Cache exchange type was written by my colleague Michael Bridgen as a useful sample extension exchange type.

Page 38: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

‘x-lvc’ Exchange Typeimport amqplib.client_0_8 as amqpch = amqp.Connection().channel()ch.exchange_declare("lvc", type="x-lvc")ch.basic_publish(amqp.Message("value"), exchange="lvc", routing_key="rabbit")...ch.queue_declare("q")ch.queue_bind("q", "lvc", "rabbit")print ch.basic_get("q").body

Friday, 26 March 2010

Page 39: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Writing Plugins and Exchange Types

Friday, 26 March 2010

Now that we’ve looked at these two real-world use cases, and seen the kinds of plugin and custom exchange type that helped solve them in a clean and manageable way, I’m going to show you how easy it is to write RabbitMQ plugins and exchange types of your own.

Because the Last Value Cache is a nice simple example, it provides a good running example for helping to explain some of the technical issues in more depth.

Page 40: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

• Write an Erlang OTP application, including its .app file

• Package it up as a .ez file

• Consider using rabbitmq-public-umbrella

It’s easy

Friday, 26 March 2010

Write an application, an .app file, and zip it up into an .ez file.

If you want some help automating the building and packaging of your plugin, you can use the rabbitmq-public-umbrella from our mercurial repository, which lets you write your plugin using a nice terse Makefile format that can handle inter-plugin dependencies and packaging in a standard way. The majority of the existing plugins use the umbrella’s include.mk file.

Page 41: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

.ez files

Friday, 26 March 2010

Each .ez file is an ordinary zip file, containing a single directory named the same as the plugin. That directory can contain anything at all. About the only required piece is an “ebin” directory holding the code for the plugin, but if your plugin exposes APIs for other plugins to build on, it’s useful to include an “include” directory too with any header files required. Finally, it’s crucial that each plugin be a real OTP application, complete with a “.app” application descriptor.

Page 42: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

The .app file{application, rabbit_lvc_plugin, [{description, "RabbitMQ LVC exchange"}, {vsn, "0.01"}, {modules, [ rabbit_lvc_plugin, rabbit_exchange_type_lvc ]}, {registered, []}, {env, []}, {applications, [kernel, stdlib, rabbit, mnesia]}]}.

Friday, 26 March 2010

You can choose to build plugins as library applications, in which case they don’t have an independent existence of their own, and exist to provide functionality to other pieces of the system, or as full applications, in which case they’re started up after RabbitMQ itself in the same virtual machine.

You can even make them a kind of hybrid: for example, the mochiweb plugin we provide sets itself up as a running webserver, but exposes some API for other plugins to hook into the server, like Java servlets.

This particular example is a library application, and relies on the “boot step” mechanism RabbitMQ provides (which is coming up in a couple of slides) to hook in to the running system.

Page 43: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Writing Exchange Types

• Write an ordinary plugin

• Add a boot step that registers the new type

• Implement the rabbit_exchange_type behaviour

Friday, 26 March 2010

So a plugin is just an Erlang/OTP application in a zip file. With that out of the way, let’s look at implementing custom exchange types. Each plugin simply needs to register the exchange types it wants to add during RabbitMQ’s boot sequence, and to provide a module for each new type of exchange.

Page 44: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Boot Steps

• For starting up with RabbitMQ, not after

• Uses Erlang’s module attributes

• Uses Erlang’s built-in support for reasoning about graphs

• Topological sort of dependencies gives order-of-operations

Friday, 26 March 2010

Because RabbitMQ has a fairly complicated boot sequence that’s much more fine-grained than the OTP-level application startup sequence, we needed to come up with a declarative way of deciding what to do and which order to do it in. You can hook a plugin automatically into the boot sequence by using module attributes in a certain way that is picked up by the Rabbit boot loader when RabbitMQ starts up.

Page 45: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Boot Steps

-rabbit_boot_step({my_boot_step_name, [{description, "do something cool"}, {mfa, {mymodule, myfunc1, [arg0, arg1]}}, {mfa, {mymodule, myfunc2, [arg]}}, {enables, some_feature}, {enables, another_step}, {requires, something_to_be_ready_first}]}).

Friday, 26 March 2010

Each boot step is named, and can depend on previous steps having been completed by the time it runs, and can delay other steps’ run time until it has finished running itself.

It executes its mfa clauses in order, if there are any. If there aren’t any, it considers the step to be a kind of ‘milestone’ in the boot sequence, which is printed differently but otherwise treated the same as other boot steps.

Page 46: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Boot Steps

%% Use topological sort to find a consistent ordering (if%% there is one, otherwise fail).

SortedStepsRev = [begin {StepName, Step} = digraph:vertex(G, StepName), Step end || StepName <- digraph_utils:topsort(G)],

SortedSteps = lists:reverse(SortedStepsRev).

Friday, 26 March 2010

Here’s how we compute the sequence of steps to run in the RabbitMQ boot loader, based on each step’s declared “requires” and “enables” clauses. We use Erlang’s great built-in support for working with DAGs and general graphs to produce a topological sort of the boot step dependency tree. It’s pretty cool stuff: I wish other languages had such a thoughtfully implemented graph library as a standard piece of kit.

Page 47: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Registering ‘x-lvc’

-rabbit_boot_step({?MODULE, [{description, "last-value cache exchange type"}, {mfa, {rabbit_lvc_plugin, setup_schema, []}}, {mfa, {rabbit_exchange_type_registry, register, [<<"x-lvc">>, rabbit_exchange_type_lvc]}}, {requires, rabbit_exchange_type_registry}, {enables, exchange_recovery}]}).

Friday, 26 March 2010

Here’s the boot step responsible for hooking the Last Value Cache exchange type into the system.

Remember, it executes the mfa clauses in order. Here we see first a call to a function that sets up the mnesia table used to hold the cached values, followed by a call to a function that registers the new exchange type. By including the “enables exchange_recovery” clause, we make sure that the new type is available before RabbitMQ reads durable exchange definitions from disk and instantiates the corresponding exchanges.

Page 48: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

AMQP 8-0Copyright (C) 2007-2010 LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.Licensed under the MPL. See http://www.rabbitmq.com/

node : rabbit@walkapp descriptor: /Users/tonyg/dev/rabbitmq-umbrella/rabbitmq-server/scripts/../ebin/rabbit.apphome dir : /Users/tonygcookie hash : mwtySYvzRGJyIxBy7NFuLA==log : /var/folders/YT/YTZtM5Y9GOG6zMVaktTkLE+++TI/-Tmp-//rabbit.logsasl log : /var/folders/YT/YTZtM5Y9GOG6zMVaktTkLE+++TI/-Tmp-//rabbit-sasl.logdatabase dir : /var/folders/YT/YTZtM5Y9GOG6zMVaktTkLE+++TI/-Tmp-/rabbitmq-rabbit-mnesia

starting worker pool ...donestarting database ...done-- external infrastructure readystarting exchange type registry ...donestarting last-value cache exchange type ...donestarting exchange type topic ...donestarting exchange type headers ...donestarting exchange type fanout ...donestarting exchange type direct ...donestarting internal event notification system ...donestarting logging server ...done-- kernel readystarting alarm handler ...donestarting queue supervisor ...donestarting node monitor ...donestarting cluster router ...done-- core initializedstarting empty DB check ...donestarting codec correctness check ...donestarting script_manager_sup ...donestarting script_exchange ...donestarting exchange recovery ...donestarting queue recovery ...donestarting persister ...donestarting guid generator ...done-- message delivery logic readystarting error log relay ...donestarting networking ...donestarting RabbitHub ...done-- network listeners available

broker running

starting last-value cache exchange type

starting exchange type registry

starting exchange recovery

Friday, 26 March 2010

When you look at the boot steps as they’re printed when RabbitMQ is started up, we see our Last Value Cache type appear pretty early on in the list of actions. It’s really important to get the declared dependencies right, because the topological sort engine is free to choose any solution that fits the constraints, and if you get them wrong, sometimes a piece of the broker you’re depending on isn’t ready by the time you need it. For example, our LVC plugin needs the exchange type registry to be available, and blocks exchange recovery until it has initialised itself. Notice that the exchange type registry is set up *immediately* before our new exchange type’s initialization step, but that exchange recovery happens much later in the show.

Page 49: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

rabbit_exchange_typedescription/0 :: () -> [{atom(), any()}]

publish/2 :: (exchange(), delivery()) -> {routing_result(), [pid()]}

validate/1 :: (exchange()) -> 'ok'create/1 :: (exchange()) -> 'ok'recover/2 :: (exchange(), list(binding())) -> 'ok'delete/2 :: (exchange(), list(binding())) -> 'ok'

add_binding/2 :: (exchange(), binding()) -> 'ok'remove_bindings/2 :: (exchange(), list(binding())) -> 'ok'

Friday, 26 March 2010

On to the exchange type behaviour itself. Besides human- and tool-friendly metadata about the exchange type, there are three groups of functions that need to be implemented: the publish operation; exchange type instance creation and deletion; and binding appearance and disappearance. You can do anything you like in these callbacks, but bear in mind that your exchange might be running inside a clustered Rabbit, so be careful about what state you carry around.

Page 50: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

‘x-lvc’ Implementation

• publish updates a row in mnesia before routing like a direct exchange

• add_binding queries mnesia and sends on the cached value to the newly-bound queue

• delete removes rows from mnesia

Friday, 26 March 2010

To illustrate those callbacks in the context of our running example, here’s what the Last Value Cache does.

Page 51: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

(almost done)

Friday, 26 March 2010

Back to the beginning: the high-level view of how your whole distributed system is put together.

Page 52: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Traditional View

Message Broker

Publishing Application

Consuming Application

Messaging Library Messaging Library

Network

Friday, 26 March 2010

The traditional view of messaging has the queues and relays as services that are subordinate to the producers and consumers of messages. This is fine up to a point; it starts to look a bit strange when you realise that you want to be able to trust the middleman as a peer, allowing it to make its own decisions about the messages you send to it as a first-class part of your distributed application.

Page 53: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Queueing/Relaying Application

Revised View

Messaging Library

Publishing Application

Consuming Application

Messaging Library Messaging Library

Network

Friday, 26 March 2010

So the way we’re starting to look at things has the broker -- the relays, exchanges, buffers and queues, as well as their management and monitoring and any custom extensions -- as a first-class peer in each distributed application.

Instead of treating the message broker as part of the underlying infrastructure, it can lead to a cleaner system architecture to include it as part of your application.

Page 54: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

Your Plugin Here?

• ...for new transports (e.g. RabbitHub)

• ...for new exchange types (lvc, script)

• Plugins are straightforward to write (esp. with umbrella)

• We’re looking forward to seeing what you all come up with!

Friday, 26 March 2010

We’d love to see what kinds of things the community will be able to come up with in this new model of plugins extending the core functionality of the network itself.

In conclusion, using messaging software is a good way to get a high-level perspective on the structure of your distributed application. AMQP is the up-and-coming standard language for describing messaging networks, and Erlang and RabbitMQ can be useful tools as platforms for developing and deploying distributed systems designed in this way.

Page 55: AMQP and Beyond - Oliver Wymantech.labs.oliverwyman.com/downloads/dev.lshift.net... · The main tool for customising RabbitMQ is the plugin system. The design and implementation of

www.rabbitmq.com/howgithub.com/tonyg/rabbithub

github.com/tonyg/script-exchangegithub.com/squaremo/rabbitmq-lvc-plugin

Thanks!

Friday, 26 March 2010