Die Zukunft des Messaging

Messaging mit RabbitMQ, AMQP und Spring

Eberhard Wolff

Kaum ein Bereich ist so stabil wie Messaging – seit 2002 hat sich der einschlägige JMS-Standard nicht weiterentwickelt. Aber die Welt dreht sich weiter: Außerhalb der Java-Welt wird AMQP als Messaging-Lösung immer wichtiger. Jetzt steht mit Spring AMQP ein Projekt bereit, das diesen Standard auch im Java-Bereich unterstützt. Zeit also, ein Blick zu wagen.

Die Kommunikation zwischen verteilten Systemen findet oft mit RPC (Remote Procedure Call) statt, bei denen Methoden auf dem Server aufgerufen werden. In diese Kategorie fallen Technologien wie RMI (Remote Method Invocation), SOAP Web Services oder CORBA. Im Wesentlichen wird eine Methode in einem entfernten Prozess aufgerufen und man wartet auf das Ergebnis. Dieses Vorgehen schafft einige Probleme: So muss sich der Entwickler mit Netzwerkproblemen oder -ausfällen beschäftigen und auch mit langen Antwortzeiten zurechtkommen. Zudem gibt der Methodenaufruf genau an, was passieren soll, also beispielsweise: „Lege einen neuen Bestellung in der Datenbank an“.

Bei einer Nachricht wie „Neue Bestellung“ kann der Server entscheiden, was er aufgrund dieser Nachricht tut. Er kann die Bestellung in der Datenbank anlegen oder die Rechnung vorbereiten. Dadurch sind die Systeme stärker entkoppelt, da jedes System selber entscheiden kann, wie es auf eine Nachricht reagiert. Außerdem kann die Bearbeitung der Nachricht zu einem anderen Zeitpunkt stattfinden als das Verschicken, so dass Sender und Empfänger auch zeitlich entkoppelt sind.

Bei einem Netzwerkausfall können Nachrichten lokal gespeichert und die Übertragung so lange verzögert werden, bis das Netzwerk wieder verfügbar ist. Bei einem Fehler in der Bearbeitung der Nachricht kann diese dann so oft neu übertragen werden, bis sie erfolgreich bearbeitet worden ist. Typische Probleme verteilter Systeme wie Netzwerkausfälle oder Latenzzeiten können also mit Messaging elegant gelöst werden.

Dieser Vorteil bedeutet aber auch, dass man die Architektur anpassen muss. Das System muss asynchron arbeiten, was ein anderes Denken als die synchrone Abarbeitung von Methoden erfordert. Dieses Vorgehen ist jedoch nicht so ungewöhnlich: Ansätze wie AJAX (Asychronous JavaScript and XML) sind ebenfalls asynchron, so dass eine solche Architektur auch zum Beispiel im Bereich GUI relevant ist. Zum tieferen Einstieg in asynchrone Mechanismen lohnt sich die Lektüre von Enterprise Integration Patterns. (Gregor Hohpe, Bobby Woolf: Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions, Addison-Wesley, 2003, ISBN 0321200683).

AMQP: Der neue Messaging-Standard

AMQP (Advanced Message Queuing Protocol) ist ein Standard im Messaging-Bereich. Er definiert nicht etwa ein API, sondern ein Netzwerkprotokoll, das von Messaging-Lösungen zum Übertragen der Nachrichten genutzt wird. Die Standardisierung auf dieser Ebene hat einige Vorteile:

  • Ein Client benötigt nur eine Library, auch wenn er verschiedene AMQP-Implementierungen parallel nutzt.
  • Die Abhängigkeit zu einem Hersteller verringert sich, weil Produkte einfach gegeneinander ausgetauscht werden können. Da sie alle dasselbe Netzwerkprotokoll verwenden, verhalten sie sich gleich. Natürlich sind dennoch in der Praxis Unterschiede bezüglich Performance oder Inkompatibilitäten nicht ausgeschlossen.
  • Das Protokoll ist effizient. So werden beispielsweise Daten binär übertragen.
  • Schon jetzt gibt es Unterstützung für praktisch alle wichtigen Programmiersprachen und Betriebssysteme.
RabbitMQ

RabbitMQ ist eine Implementierung des AMQP-Standards. Es implementiert neben AMQP 0.8, 0.9 und 0.9.1 auch noch zahlreiche weitere Messaging-Protokolle wie STOMP oder XMPP. Außerdem ist es auf der Amazon-EC2-Plattform sehr beliebt und auch die Basis für NASAs Nebula-Cloud-Initiative. RabbitMQ ist in der Programmiersprache Erlang implementiert und liegt im Moment in der Version 2.4.1 vor. Auch Enterprise-Features wie Clustering werden von RabbitMQ unterstützt.

Im Java-Bereich gibt es ebenfalls Support: Angeboten werden ein Grails-Plug-in, ein nativer Java-Client und auch Unterstützung für Scala/Lift. In diesem Artikel wird die Unterstützung von Java mithilfe von Spring AMQP 1.0.0RC1 im Mittelpunkt stehen.

Wie geht nun die Kommunikation mit AMQP konkret vonstatten? Im einfachsten Fall schickt der Producer Nachrichten an eine Queue, die dann die Nachrichten speichert, bis sie vom Consumer abgeholt werden. Queues können „durable“ sein: Dann überstehen sie auch einen Server-Neustart. Sind sie „exclusive“, so stehen sie nur für eine Verbindung zur Verfügung, und Queues mit autoDelete werden gelöscht, wenn die Verbindung abgebaut wird. Queues werden meistens vom Consumer der Nachrichten erzeugt. Alle Ressourcen in AMQP sind dynamisch und werden zur Laufzeit erzeugt.

Listing 1 zeigt den dazu notwendigen Code: Zunächst wird eine CachingConnectionFactory angelegt, mit der auf den RabbitMQ-Server zugegriffen werden kann. Dann wird eine Instanz von RabbitAdmin erzeugt. Dieses Objekt erlaubt es, Ressourcen im RabbitMQ-Server anzulegen. Es implementiert das Interface AmqpAdmin, das die Operation des AMQP-Standards enthält. Dann wird eine Queue erzeugt oder, genauer gesagt, deklariert. Sollte sie nämlich schon vorhanden sein, wird sie nicht etwa erneut erzeugt, sondern lediglich eine Referenz auf die Queue zurückgegeben, wenn sie der geforderten Konfiguration entspricht. Gibt es bereits eine Queue mit dem übergebenen Namen, aber einer anderen Konfiguration, wird eine Exception geworfen.

ConnectionFactory conFactory = new CachingConnectionFactory("localhost");
RabbitAdmin admin = new RabbitAdmin(conFactory);
admin.declareQueue(new Queue("myQueue"));
RabbitTemplate template = new RabbitTemplate(conFactory);
template.convertAndSend("myQueue", "Hi AMQP!");
String receive = (String) template.receiveAndConvert("myQueue");
Assert.assertEquals("Hi AMQP!", receive);

Listing 1

In der nächsten Zeile in Listing 1 wird ein RabbitTemplate erzeugt. Auch hier gibt es das RabbitMQ-spezifische Interface RabbitOperations und das allgemeinere AMQP-Interface AmqpTemplate. Man erkennt hier, dass Spring AMQP in Zukunft auch andere AMQP-Implementierungen neben RabbitMQ unterstützen könnte.

Geschrieben von
Eberhard Wolff
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.