Der Artikel zeigt die verwendeten Komponenten, die Eigenschaften des Protokolls und die Anforderungen an die Funktionalität für einen zuverlässigen Message-Broker auf. Beispielcode veranschaulicht die einfache Entwicklung eines Java-MQTT-Clients. Der Abschluss des Artikels zeigt das Zusammenspiel der Komponenten auf.
MQTT-Protokoll
Heute gilt das bereits 1999 entwickelte MQTT-Protokoll (OASIS Message Queuing Telemetry Transport, [MQTT]) als De-facto-Standard für die Datenübertragung im Internet der Dinge (Internet of Things, IoT). Das leichtgewichtige ISO-Standardprotokoll wird in Anwendungsfällen im Bereich Industrie 4.0, Connected Car, Consumer Electronics, Manufacturing und genereller IoT-Kommunikation so wie vor allem auch für leichtgewichtige Microservices im Backend verwendet. Im Januar 2018 wurde die neueste Version des Protokolls, MQTT 5, der Nachfolger von MQTT 3.1.1, offiziell veröffentlicht, was Benutzern eine noch bessere Bedienbarkeit und größere Funktionalität bietet.
Die Verbreitung von MQTT zeigen Trends wie das „Eclipse Foundation IoT Survey“ [IoT19] oder auch eine aktuelle Google-Trends-Analyse (s. Abb. 1), die die Häufigkeit des Interesses am Protokoll über die verwendeten Suchbegriffe weltweit darstellt. Wer im Jahr 2019 ein IoT-Projekt umsetzen möchte, kommt an MQTT nicht vorbei.
Abb. 1: Interesse an IoT-Protokollen
Eigenschaften von MQTT
MQTT setzt auf TCP als Transportprotokoll (s. Tabelle 1) und setzt damit voraus, dass Informationen geordnet, verlustfrei und bi-direktional transportiert werden.
Tabelle 1: Schichtenmodell
Basierend darauf bietet MQTT eine Reihe weiterer wichtiger Eigenschaften, deren wesentliche Elemente sind:
- Das Protokoll spezifiziert die Verwendung des Publish-/Subscribe-Paradigmas (s. Abb. 2), welches eine n-zu-m-Nachrichtenverteilung und eine Entkopplung von Sendern und Empfängern von Nachrichten mit sich bringt.
- MQTT erlaubt die Übertragung sämtlicher Datenformate, sowohl von Text als auch von binären Nutzdaten.
- Das Protokoll ist binär und besitzt nur einen extrem geringen Protokoll-Overhead, was erlaubt, Bandbreite zu sparen und den gesamten Traffic zu reduzieren.
- MQTT wurde entwickelt, um zuverlässige Datenübertragung in unzuverlässigen Netzwerken zu gewährleisten. Deshalb gibt es viele Funktionalitäten, die es Entwicklern leicht macht, sich auf eine sichere Datenübertragung verlassen zu können.
Abb. 2: Pub/Sub-Pattern
Mit dem Release der neuen MQTT-Spezifikation MQTT 5 zum Beginn des Jahres 2019 wurden viele lang erwartete Neuerungen und Verbesserungen eingeführt, weshalb es sich empfiehlt, bei neuen Projekten gleich die neueste Version des Protokolls zu verwenden. Alle in diesem Artikel besprochene Software unterstützt diese neue Version bereits zu 100 Prozent.
Einen guten Überblick für Neueinsteiger ins Thema „MQTT“ bietet die populäre Blog-Post-Serie „MQTT Essentials” [MQTT-E], welche alle Funktionen des Protokolls detailliert beschreibt.
Komponenten
MQTT in eigenen Projekten einzusetzen, ist sehr einfach. Üblicherweise verwendet man als Anwendungsentwickler MQTT-Bibliotheken, welche es einer Applikation ermöglichen, als Client an der MQTT-Kommunikation teilzunehmen. MQTT ist ein sogenanntes Wire-Protokoll, daher definiert es, im Gegensatz zu JMS, keine Programmierschnittstelle für Entwickler. MQTT ist vielmehr eine Spezifikation der Datenübertragung. Es gibt für sehr viele Programmiersprachen Bibliotheken, welche Entwickler verwenden können. Ein vollwertiger MQTT-Stack besteht im Allgemeinen aus den folgenden Komponenten:
- MQTT-Clients,
- MQTT-Broker und
- MQTT-Tools.
Ein MQTT-Client ist hier üblicherweise eine Applikation, welche Daten senden und/oder empfangen möchte. Dabei kann es sich bei der Applikation um die Software für ein „Ding” handeln, wie etwa eine Maschinensteuerung, die Software für ein Auto oder ganz banal um einen Temperatursensor. Aber natürlich kann ein MQTT-Client auch eine Applikation im Backend sein, wie etwa ein Microservice, welcher (Streaming-)Daten direkt konsumiert und weiterverarbeitet. Es gibt eine große Vielfalt an MQTT-Bibliotheken für alle gängigen Programmiersprachen, unter anderem natürlich auch für Java.
Der MQTT-Broker ist das Herzstück bei MQTT, da es der zentrale Datenverteiler für alle MQTT-Clients ist. Die MQTT-Clients melden sich beim Broker an und abonnieren oder senden Daten. Der MQTT-Broker ist nun in der Lage, via Push-Kommunikation die Nachrichten an alle interessierten Clients zu senden. Er stellt dabei sicher, dass alle Teilnehmer authentifiziert sind und die nötigen Berechtigungen besitzen.
Moderne MQTT-Broker wie HiveMQ [HiveMQ] sind für Cloud-native Anwendungsfälle ausgelegt. Sie sind elastisch skalierbar und für Umgebungen wie Kubernetes oder Openshift geeignet. Besonders wichtig ist es in professionellen Umgebungen, dass Third-Party-Security-Systeme angebunden werden können, was üblicherweise über ein Extension-System am Broker realisiert wird. Nicht zuletzt werden bei der vielen MQTT-Projekten noch MQTT-Tools eingesetzt, um MQTT-Clients zu simulieren und um schnelle Tests zu realisieren.
Im Folgenden wird ein Java-basierter MQTT-Stack aufbauend auf einer MQTT-Client-Bibliothek, einem MQTT-Broker und einem MQTT-Tool vorgestellt, welche in einer Beispielanwendung miteinander verwendet werden.
MQTT-Message-Broker – HiveMQ CE
HiveMQ [HiveMQ-CE] ist ein in Deutschland entwickelter, kommerzieller MQTT-Broker, welcher in vielen der größten IoT-Deployments der Welt verwendet wird und sich durch seine Stabilität und Performanz auszeichnet. Seit 2019 gibt es eine gemäß Apache 2 lizenzierte Open-Source-Version, die HiveMQ Community Edition (CE) ([HiveMQ-D], s. Abb. 3).
Abb. 3: HiveMQ Community-Komponenten
HiveMQ CE ist ein Java-basierter Open-Source-MQTT-Broker, der MQTT 3.x und MQTT 5 vollständig unterstützt, inklusive aller optionalen Funktionalitäten. HiveMQ CE ist für alle gängigen Betriebssysteme verfügbar (Windows, Linux, MacOS) und für den produktiven Einsatz geeignet. HiveMQ verfügt neben der Core-Implementierung, die alle MQTT-spezifischen Features abdeckt, auch über ein umfangreiches Extension-Framework mit einem offenen Java-API, welches es erlaubt, den Broker auf Geschäftslogik anzupassen, ohne dabei dessen Quellcode zu modifizieren.
Das Extension-System erlaubt unter anderem:
- Entwicklern die Integration der eigenen Infrastruktur,
- eigene kundenspezifische Lösungen zur Authentifizierung und Autorisierung zu entwickeln,
- Daten an andere Backend-Services weiterzuleiten,
- MQTT-Pakete und das Protokollverhalten zu modifizieren,
- Änderungen an den Extensions ohne Broker-Downtime (Hot Reload) zu migrieren.
Vorgefertigte Erweiterungen für typische Anwendungsfälle, wie Role Based Access Control, Authentifizierung, Monitoring usw., stehen neben Enterprise-Extensions, wie einer Kafka- oder der Security-Extension, ebenfalls als Open-Source-Lösung zur Verfügung [HiveMQ-E].
Java MQTT Client – HiveMQ MQTT Client
HiveMQ MQTT Client ist eine MQTT-Java-Bibliothek, die für die Nutzung in hoch performanten Szenarien und mit geringem Speicherbedarf entwickelt wurde. Die Bibliothek ist unter der Open-Source-Lizenz Apache 2 verfügbar und wurde von HiveMQ und der BMW-Car IT entwickelt. Die Bibliothek hat sich mittlerweile zur Standardbibliothek für alle Java-basierten MQTT-Anwendungen entwickelt.
Die Bibliothek HiveMQ MQTT Client bringt unter anderen folgenden Features mit:
- vollständige Implementierung aller MQTT 5.0- und 3.1.1-Features, inklusive TLS/SSL,
- Message-Persistenz,
- Offline Buffering,
- Automatic Reconnect
- Backpressure-Support,
- HTTP-CONNECT-Support,
- Websocket-Support,
- Server-Failover ,
- Pluggable Thread-Pools.Sie bietet drei API-Varianten:
- Simple (Blocking),
- Future (Asynchron) und
- Reaktiv.
Jede Variante verfügt über ein eigenes Interface, sodass eine klare Trennung bezüglich der Methoden besteht. Trotzdem ist es für die Implementierung eines MQTT-Clients jederzeit möglich, die API-Version zu wechseln und gleichzeitig verschiedene API-Versionen desselben Clients zu verwenden. Code, Dokumentation und Community sind via GitHub verfügbar [HIVEMQ-CL].
Tools – MQTT CLI
Sowohl für Entwickler als auch für Administratoren ist es hilfreich, MQTT-Clients simulieren zu können, welche als Publisher oder Subscriber agieren können. Mit dem Java-basierten Open-Source-Projekt „MQTT CLI“ [MQTT-CLI], welches unter der Apache 2-Lizenz verfügbar ist, ist es möglich, direkt auf der Kommandozeile beliebig komplexe MQTT-Clients zu simulieren und diese direkt mit dem Broker kommunizieren zu lassen. Dabei können Daten gesendet und auch empfangen werden.
MQTT CLI unterstützt alle MQTT-Features für MQTT 3.1.1 und MQTT 5 und kann verwendet werden, um sowohl lokale MQTT-Broker als auch remote Server zu testen. Dabei ist es sogar möglich, mit TLS eine verschlüsselte Kommunikation aufzubauen. Ein interaktiver Shell-Modus erlaubt eine feingranulare Simulation auch komplexester MQTT-Clients.
Beispielanwendung
Abbildung 4 gibt einen Überblick über die Beispielanwendung. Im Beispiel simulieren MQTT-Clients Sensoren und deren Übertragung der Raumtemperatur an einen Service (MQTT-Client). Der Backend-Client überprüft die Daten und agiert anhand der Werte. Als Broker wird HiveMQ CE genutzt. Der Backend-Client wird als Java-App mit der HiveMQ-Client-Bibliothek implementiert. Die Sensoren werden mit der HiveMQ CLI simuliert. Die vollständige Beispielanwendung steht im GitHub zur Verfügung [J-MQTT-St].
Abb. 4: Beispiel-Use-Case
HiveMQ MQTT Broker Start
Neben dem GitHub-Repository sind auf der HiveMQ-Homepage verschiedene Distributionen verfügbar. In der einfachsten Variante ist HiveMQ als Zip-Datei verfügbar. Alternativ dazu kann HiveMQ direkt per AMI auf AWS deployt oder auch ein Docker-Image aus Dockerhub geladen und so der Broker im Docker-Container betrieben werden [HiveMQ-E].
Wird die Zip-Datei ausgepackt, findet man die Ordnerstruktur aus Tabelle 2. Der Broker kann einfach über das RUN-Skript im bin-Verzeichnis gestartet werden (s. Abb. 5).
Tabelle 2: HiveMQ-Ordnerstruktur
Abb. 5: HiveMQ-Start
Beispiel-Implementierung mit der Bibliothek HiveMQ MQTT Client
Die Bibliothek wird über Gradle oder Maven einem Java-Projekt hinzugefügt. Listing 1 zeigt die Gradle Dependencies Definition in der Datei build.gradle.
dependencies {
implementation group: 'com.hivemq', name: 'hivemq-mqtt-client',
version: '1.1.2'
}
Erzeugen des MQTT-Clients: Die Klasse MyClientBackend erzeugt den MQTT-Client, abonniert diesen auf eine Anzahl von Topics und veröffentlicht Daten an den Client in Abhängigkeit der Werte, welche der Client empfängt.
CONNECT: Der MQTT 5-Client baut zunächst über einen Call der Blocking-Client-Bibliothek eine Verbindung auf. Das Connect wird ausgeführt und der Status gesetzt. Im Anschluss abonniert sich der Client auf seine Topics (s. Listing 2).
public void startClimateControllerBackend() {
final Mqtt5BlockingClient client = MqttClient.builder()
.serverHost(BROKER_HIVEMQ_ADR)
.serverPort(BROKER_HIVEMQ_PORT)
.useMqttVersion5()
.identifier(CLIMATE_CONTROLLER_BACKEND)
.buildBlocking();
Mqtt5ConnAck ack = client.connect();
doSubscribeToRooms(client.toAsync());
}
SUBSCRIBE: Abonnierungen können mithilfe von Subscription-Objekten vollständig beschrieben und beim Abonnieren des Clients als Parameter übergeben werden. Hier wird alternativ der Async-Client der MQTT-Bibliothek verwendet. Der Client abonniert sich auf das Topic „room/+/temperature“, also auf alle Temperatursensoren mit Quality of Service Level 1. Über die completable Future kann dann wieder zum Beispiel im Fehlerfall reagiert werden (s. Listing 3).
private void doSubscribeToRooms(Mqtt5AsyncClient client) {
final Mqtt5Subscription subTemp = Mqtt5Subscription.builder()
.topicFilter(TOPIC_ROOMS_TEMP).qos(MqttQos.AT_LEAST_ONCE)
.build();
client.subscribeWith()
.addSubscription(subTemp)
.callback(publish -> { doPublishCommand(client, publish);})
.send();
}
PUBLISH: Durch die Callback-Funktionalität wird im Falle eines Publishers die Methode doPublish aufgerufen. Aus dem MQTT Publish Packet wird der Payload gelesen, das Topic wird via Topic-Filter verglichen. Bei einem positiven Match und einer erfolgreichen Verifizierung des Wertes des Payloads wird ein Publish auf ein separates Topic ausgeführt, welches dazu dient, Kommandos zur Temperaturregelung zu empfangen (s. Listing 4).
private void doPublishCommand(Mqtt5AsyncClient client,
Mqtt5Publish publish) {
final Integer val = getIntValueFromPayload(publish);
if (MqttTopicFilter.of(TOPIC_ROOMS_TEMP).matches(
publish.getTopic())) {
final String temp = temperatureControl(val);
publishCommand (client, temp, publish.getTopic());
} ...
}
private void publishCommand (
Mqtt5AsyncClient client, String payload, String topic) {
final Mqtt5Publish command = Mqtt5Publish.builder()
.topic(topic + "/command")
.payload(payload.getBytes())
.build();
client.publish(command);
...
}
Test der Beispielanwendung
Der HiveMQ-Broker und der Backend-Service werden gestartet. Die Temperatursensoren werden über das MQTT CLI simuliert. Das CLI wird im Terminal im Shell-Modus ausgeführt:
$>mqtt shell
MQTT-Clients werden connected und auf das Command-Topic des jeweiligen Raumes für die Temperatur abonniert. Der Publish der Temperaturnachricht durch die Clients wird am Backend-Service, der mit dem Topic-Filter „room/+/temperature“ auf die Temperatur-Topics aller Räume abonniert ist, verifiziert und entsprechend verarbeitet.
Die MQTT-Aktionen sind im Logfile des MQTT CLI und des HiveMQ Message Broker (Trace Level) sichtbar (s. Abb. 6).
Abb. 6: MQTT CLI Verbose log
Fazit
Mit wenig Einarbeitungsaufwand und ohne Kosten ist es möglich, einen zuverlässigen, quelloffenen und Java-basierten MQTT-Stack aufzusetzen mittels HiveMQ MQTT Client und HiveMQ CE. Die Lösung verwendet Industriestandards, kann einfach in vorhandene Unternehmensstrukturen integriert, in jeder beliebigen Umgebung installiert und bei steigender Anzahl von verbundenen Geräten entsprechend ausgebaut werden. Für den Betrieb einer geschäftskritischen Anwendung kann ohne Migrationsaufwand die Edition des HiveMQ Message Broker den Anforderungen an Skalierung und Support angepasst werden.
Literatur und Links
[IoT19]
Eclipse Foundation, IoT Developer Survey 2019 Results,
https://iot.eclipse.org/resources/iot-developer-survey/ iot-developer-survey-2019.pdf
[HiveMQ]
https://www.hivemq.com/
[HiveMQ-CE]
GitHub, HiveMQ CE,
https://github.com/hivemq/hivemq-community-edition
[HiveMQ-CL]
GithHub, HiveMQ-Client-Bibliothek,
https://github.com/hivemq/hivemq-mqtt-client
[HiveMQ-D]
HiveMQ Downloads,
https://www.hivemq.com/downloads/
[HiveMQ-E]
HiveMQ Extensions,
https://www.hivemq.com/extensions/
[J-MQTT-St]
GitHub, Java-MQTT-Stack,
https://github.com/hivemq/article-java-mqtt-stack
[MQTT]
MQTT Version 5.0, OASIS Standard,
https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html
[MQTT-CLI] GitHub, MQTT-CLI,
https://github.com/hivemq/mqtt-cli
[MQTT-E]
MQTT Essentials,
https://www.hivemq.com/mqtt-essentials/