Apache ActiveMQ (Teil 1/2)

In dieser Artikelserie geht es um die Funktionsweise von Publish-Subscribe Systemen am Beispiel von Apache ActiveMQ. Anwendungsfälle hierfür könnten ein effizientes Load-Balancing oder eine einfache Replikation sein. Hier ist die Verwendung eines Systems, welches das Publish-Subscribe Pattern implementiert, essenziell. Die Verwendung eines RESTful Request-Response-System und einer Client-Server-Architektur wäre in derartigen Fällen äußerst aufwendig und dazu ineffizient.

Zu ActiveMQ wird es eine zweiteilige Artikelserie auf diesem Blog geben. Sie beginnt in diesem ersten Teil mit einer Einführung in Apache ActiveMQ und die unterstützen Features, gefolgt von einer Einführung in die verwendeten Publish-Subscribe Systeme, sowie der Definitionen einiger Quality Of Service Levels. Abschließend werden die Systeme Apache ActiveMQ und Apache ActiveMQ Artemis erläutert und verglichen.

Der zweite Teil der Artikelserie wird neben einigen Java-Code-Beispielen auch eine Einführung in das mitgelieferte Webinterface von Apache ActiveMQ enthalten.

Was ist Apache ActiveMQ?

Bei Apache ActiveMQ handelt es sich um ein Publish/Subscribe-System, welches Topics und Queues für Channels, sowie gruppenbasierte Multicasts unterstützt. Es bietet Unterstützung für eine Vielzahl von Programmiersprachen. Darunter sind auch Java, die .Net-Sprachen (wie etwa C#), C, Python, PHP, Ruby und Perl.

Apache ActiveMQ zeichnet sich aufgrund der unterliegenden nicht-blockierenden Architektur als besonders performant aus und ermöglicht laut eigenen Aussagen auch das Verteilen großer Nachrichtenmengen über größere Netzwerke mit einfach einzurichtender Replikation und Clustering. Verwalten lassen sich die Cluster dann mit JMX oder JMS. Es gibt eine vollständige Implementierung von JMS 1.1 und künftig auch Unterstützung für JMS 2.0 (mit ActiveMQ Artemis). Hinzu kommt voller Support für das Modularisierungssystem OSGi. Sicherheit wird über den integrierten SSL-Support gewährleistet.

Außerdem bietet es Unterstützung für viele Machine-To-Machine (M2M) Protokolle, die besonders in Zeiten der Industrie 4.0 und des Internet of Things (IoT) von enormer Wichtigkeit sind. Anstatt das integrierte OpenWire zu verwenden, kann man auch die unterstützten Protokolle, wie MQTT, AMQP und STOMP verwenden.

Apache ActiveMQ verwendet als interne Routing- und Konvertierungs-Engine Apache Camel. Als Persistenzdatenbank kann beispielsweise die integrierte KahaDB verwendet werden. Damit können Nachrichten im Message Broker auch gespeichert werden, oder einige Zeit aufbewahrt werden (beispielsweise, bis ein bestimmter Subscriber sich meldet). Alternativ kann ein Connector für ein fremdes relationales Datenbanksystem verwendet werden. Außerdem gibt es eine Flusskontrolle für die Messagestreams von Publisher und Subscriber. Apache ActiveMQ ist Teil von Apache ServiceMix (ein Open Source Container) und Mule (ein Open Source Enterprise Service Bus, bzw. eine Integrationsplattform).

Publish-Subscribe

ActiveMQ ermöglicht eine Nachrichtenverteilung sowohl nach dem Topic-basierten Publish-Subscribe-Pattern, als auch nach dem Queue-basierten Publish-Subscribe-Pattern. Um diese Patterns zu verstehen, müssen wir zunächst einige Grundbegriffe klären.

Publisher: Ein „Publisher“ oder auch „Producer“ kann als Sender betrachtet werden, denn er wird verwendet, um Nachrichten an den Message Broker zu verschicken.

Message Broker: Der „Message Broker“ repräsentiert den zentralen Server. Er verwaltet die Topics und Queues, sowie die Subscriber. Wenn ein Publisher eine Nachricht an den Message Broker sendet, schickt dieser die Nachricht weiter an alle Subscriber.

Subscriber: Der „Subscriber“, oder auch „Consumer“ kann sich beim Message Broker registrieren. Daraufhin bekommt der Subscriber alle Nachrichten weitergeleitet, die beim Message Broker eintreffen.

Ein simples Publish-Subscribe-System sieht wie folgt aus:
Publish Subscribe
Sobald der Message Broker die Nachricht M1 von Pub 1 empfangen hat, liefert er diese an die 3 Subscriber aus. Jeder Subscriber erhält eine Kopie der Nachricht.

Topics: Ein „Topic“, oder auch „Channel“, dient dazu, die Nachrichten zu filtern und ein gruppenbasiertes Multicast zu ermöglichen, anstatt alle Nachrichten zu broadcasten. Die Subscriber können also ein Topic beim Message Broker abonnieren und erhalten dann nur die Nachrichten, die über das Topic verteilt werden. Natürlich kann ein Subscriber auch mehrere Topics abonnieren. Außerdem kann ein Publisher bei jeder Nachricht entscheiden, über welche Topics diese verteilt werden soll.

Publish Subscribe Topic

Wie wir in der Abbildung sehen, sendet Publisher 1 die Nachricht M1 an den Message Broker an Topic 1. Da nur die beiden Subscriber 1 und 3 das Topic 1 abonniert haben, erhalten auch nur sie die Nachricht. Subscriber 2 erhält die Nachricht nicht.

Queues: Eine „Queue“ ist ein Topic, bei welchem jede Nachricht immer nur an einen der registrierten Subscriber weitergeleitet wird. Dies dient dazu, die Nachrichtenverarbeitung gleichmäßig auf die Subscriber zu verteilen. Der Publisher hat dabei keine Kontrolle darüber, von welchem Subscriber seine Nachricht letztendlich abgearbeitet wird.
Publish Subscribe Queue

Wie diese Abbildung illustriert, schickt Publisher 1 nun drei Nachrichten an Queue 1 im Message Broker. Diese Nachrichten werden daraufhin vom Message Broker nach dem Round-Robin-Prinzip auf die beiden Subscriber verteilt. Bei unserem Beispiel mit nur zwei Subscribern wechseln diese sich also mit der Nachrichtenverarbeitung ab. So erhält Subscriber 1 die erste Nachricht, Subscriber 2 die zweite Nachricht und Subscriber 1 wieder die dritte Nachricht. Subscriber 2 wird die nächste Nachricht erhalten.

Quality Of Service Levels

Wahrscheinlich kann man Multicast-Systeme kaum diskutieren, ohne dabei den Begriff der Quality Of Service Levels einzuführen. Denn wie all diese Nachrichten konkret ausgeliefert werden, ist nicht spezifiziert. So kann etwa der Subscriber einen offenen TCP, oder UDP-Socket haben, über den Nachrichten empfangen werden können. Alternativ könnte der Subscriber auch in regelmäßigen Intervallen beim Message Broker abfragen, ob neue Nachrichten für einen seiner abonnierten Channels eingetroffen sind. Beim Ausliefern gibt es zusätzlich noch unterschiedliche Quality of Service Levels. Einige davon sind üblicherweise:

Best Effort: Die Nachricht wird ohne weitere Kontrollmechanismen einfach abgeschickt. Ob sie einmal, mehrmals oder gar nicht ankommt, wird nicht geprüft. Diesen Ansatz nennt man daher auch „fire and forget“.

At Most Once: Es wird sichergestellt, dass jede Nachricht maximal einmal empfangen wird. Dazu werden die empfangenen Nachrichten beim Empfänger gecacht. So kann festgestellt werden, ob eine neu empfangene Nachricht schon einmal eingetroffen ist. Es gibt allerdings keinen Kontrollmechanismus, der dafür sorgt, dass eine Nachricht überhaupt ankommt.

At Least Once: Es wird sichergestellt, dass jede Nachricht mindestens einmal empfangen wird. Dazu wird ein ACKNOWLEDGE vom Empfänger an den Sender geschickt, nachdem ersterer die Nachricht erhalten hat. Der Sender versucht so lange erneut die Nachricht auszuliefern, bis er das ACKNOWLEDGE empfangen hat. Dadurch kann eine Nachricht auch mehrmals beim Empfänger ankommen.

Exactly Once: Es wird sichergestellt, dass jede Nachricht genau einmal zugestellt wird. Es muss also sowohl ein Kontrollmechanismus für die Ausschließbarkeit von doppelt zugestellten Nachrichten existieren (Caching), als auch ein Kontrollmechanismus für die Garantie, dass jede Nachricht auch zugestellt wird (ACKNOWLEDGE). Dieses Level ist bei Kommunikation über TCP/IP gegeben.

Bei Apache ActiveMQ sind die 3 Optionen Best-Effort, At Least Once und Exactly Once verfügbar. Da ActiveMQ auf einer Vielzahl von Protokollen auf unterschiedlichen OSI-Schichten lauffähig ist (etwa TCP/IP, UDP, NIO Transport, aber auch AMQP oder MQTT), sind diese Zustellungsverträge besonders dann interessant, wenn das unterliegende Protokoll noch keinen Kontrollmechanismus enthält (zum Beispiel UDP).

Zusätzlich kann man mehrere Message Broker gleichzeitig einsetzen und mit relativ wenig Aufwand auch als Failover deklarieren. Somit ist das System gegen einzelne Ausfälle gewappnet, da dann die Publisher/Subscriber einfach auf den Failover Broker umschalten. Wenn man möchte, kann man sogar einstellen, dass die Nachrichten persistiert werden, unter anderem in einer relationalen Datenbank. So gehen bei einem Ausfall auch keine von den Nachrichten verloren, welche sich gerade in der Zustellung oder einer nicht persistierten Queue auf dem Message Broker befinden.

Zusätzlich können in Apache ActiveMQ auch dauerhafte Subscriber (DurableSubscribers) erstellt werden, welche einen festen Identifier erhalten, und für die die empfangenen Nachrichten automatisch gepuffert werden, wenn sie nicht online sind.

Apache ActiveMQ und Apache ActiveMQ Artemis

Was hat es auf sich mit Apache ActiveMQ und Apache ActiveMQ Artemis?
Nun, Apache ActiveMQ Artemis ist aus der Codebase von HornetQ hervorgegangen. HornetQ wurde 2007 von Tim Fox bei JBoss unter den Namen „JBoss Messaging“ übernommen und daraufhin komplett umstrukturiert und in HornetQ umbenannt. 2015 wurde die Codebasis von HornetQ dann an die Apache Foundation übergeben, bzw. an das Team hinter Apache ActiveMQ gespendet. Dort wurde es dann als Apache ActiveMQ Artemis aufgenommen. Eine erste Version wurde danach relativ zeitnah veröffentlicht.

Mit Apache ActiveMQ Version 6 sollen das alte Apache ActiveMQ und Apache ActiveMQ Artemis zu einem Produkt vereint werden. Da HornetQ auch Unterstützung für JMS 2.0 enthält, wird Apache ActiveMQ ab Version 6 JMS 2.0 ebenfalls unterstützen. Da die aktuelle Version beim Erscheinen dieses Artikels (November 2016) ActiveMQ 5.x ist, beziehen sich die Codebeispiele im nächsten Artikel ebenfalls auf diese Version und nicht auf Apache ActiveMQ Artemis.

Short URL for this post: http://wp.me/p4nxik-2M4
This entry was posted in Java Runtimes - VM, Appserver & Cloud and tagged , , , , . Bookmark the permalink.