NATS Core Messaging für Cloud & Microservices

Von: Thomas Bayer
Datum: 22. Oktober 2020

NATS ist eine leichtgewichtige und performante Messaging Plattform für die Cloud. Entwickelt wird NATS als Open Source Projekt unter dem Schirm der Cloud Native Foundation in der Programmiersprache Go.

Die Anwendungsfälle für NATS sind vielfältig und reichen vom Cloud Messaging für Microservices über ServiceMeshes bis zu IoT und Telemetrie.

Derek Collison, der NATS ursprünglich für die Cloud Foundry Plattform entwickelt hat, gab dem Projekt den Namen Neural Autonomic Transport System in Anlehnung an das zentrale Nervensystem.

1. Unterschied zwischen NATS Core und NATS Streaming

Es gibt zwei NATS Server: zum einen NATS Core und zum anderen NATS Streaming, welches auf NATS Core aufbaut.

Der wesentliche Unterschied zwischen NATS Core und NATS Streaming ist die Nachrichten Persistenz und die Garantie der Zustellung. Weitere Unterschiede sind in der folgenden Tabelle aufgeführt:

NATS Core NATS Streaming
Garantie der Zustellung höchstens einmal (At most once)
➔ Zustellung wird nicht garantiert
Mindestens einmal (At least once)
➔ Zustellung ist garantiert, könnte aber mehrfach erfolgen.
Nachrichten Persistenz nein Ja
Zugriff auf alte Nachrichten nein Ja

Ohne die Garantie einer Zustellung mag NATS Core für viele Anwendungsfälle als unzureichend erscheinen. Ein vorschnelles Urteil könnte eine interessante Alternative verbauen. Fehlende Garantien können auf der Anwendungsebene ausgeglichen werden. Der Verzicht auf die Garantien und die Persistenz ermöglicht im Ausgleich, den NATS Core Broker wartungsfrei zu betreiben.

Dieser Artikel beschränkt sich auf die Beschreibung von NATS Core. Ein zweiter Artikel wird sich mit NATS Streaming beschäftigen.

1.1. NATS Core

Wird auch als NATS oder NATS Server bezeichnet.

Auf den ersten Blick erscheint NATS Core für viele Aufgaben ungeeignet zu sein, da Nachrichten verloren gehen können. Die at-most-once Garantie besagt, dass eine Nachricht maximal nur einmal zugestellt wird. Dass überhaupt eine Zustellung erfolgt, wird nicht garantiert. Trotz dieser Einschränkung können mit NATS Core und den richtigen Mustern viele Anwendungsfälle realisiert werden. Wird auf eine Nachrichten-Persistenz im Broker verzichtet, so reduziert sich der Verwaltungsaufwand für den Server erheblich.

Das dauerhafte Abspeichern einer Nachricht (Message Persistenz) dient dazu die Quality of Service zu erhöhen, bringt aber auch Nachteile mit sich. Das Abspeichern kostet Zeit und der zur Verfügung stehende Speicherplatz kann volllaufen. NATS Core ermöglicht es mit Bestätigungen, den Acknowledgements und Sequenznummern selbst ohne persistenten Speicher zuverlässige Systeme zu bauen.

Da der Server die Nachrichten nicht persistent speichert, kann der Sender nicht sicher sein, ob seine Nachricht empfangen wurde. Mit einer Antwort oder einer Bestätigung (Acknowledge) kann ein Empfänger dem Sender den Empfang oder auch die ordnungsgemäße Verarbeitung signalisieren. Der Sender weiß dann, dass seine Nachricht erfolgreich zugestellt wurde ( Fire-and-know Muster).

Wer auf die Message Persistenz nicht verzichten möchte, kann anstatt NATS Core das NATS Streaming Projekt verwenden.

2. Installation

Betrieben werden kann NATS als einzelner Server, als Cluster oder als Supercluster. Ein Supercluster ist ein Cluster, der sich aus mehreren Clustern zusammensetzt.

NATS kann als Binary, Docker Image oder mit einem Package Manager wie Chocolately für Windows oder mit Homebrew für macOS installiert werden.

NATS Core besteht aus einer einzigen Binärdatei von nur 4 MByte Größe. Der Start des Servers erfolgt in einem Bruchteil einer Sekunde.

3. Message Exchange Patterns

NATS unterstützt neben den asynchronen Aufrufmustern Publish/Subscribe und Queuing auch synchrone Aufrufe über das Request/Reply Muster.

3.1. Publish/Subscribe

Mit Publish/Subscribe kann ein Publisher Nachrichten an mehrere Empfänger schicken. Jeder Empfänger bekommt eine Kopie der Nachricht. Der Sender und die Empfänger sind entkoppelt. Der Publisher weiß nicht, wie viele Empfänger es gibt, wer die Empfänger sind oder ob sich überhaupt jemand für die Nachrichten interessiert.

3.2. Queuing

Command-Nachrichten, die Befehle enthalten, sollen in der Regel nur von einem Empfänger verarbeitet werden. Ein Befehl könnte beispielsweise lauten: „Gehe ins Lager und suche alle Waren für die Bestellung 123“. Solch ein Befehl sollte nur von einem Empfänger ausgeführt werden. Um Ausfallsicherheit zu erzielen wäre es hilfreich, wenn mehrere Empfänger bereitstünden und um die Nachrichten konkurrieren. Dieses Muster unterstützt das Queuing. Bei NATS können sich mehrere Empfänger über eine Queue-Subscription bündeln. Innerhalb der Queue-Subscription geht dann jede Nachricht nur an einen einzigen Empfänger.

In einer Cloud Umgebung lassen sich Queue Subscriber gut skalieren. Bei Bedarf werden neue Subscriber gestartet und bei geringer Last wieder beendet.

3.3. Request/Reply

NATS unterstützt neben dem asynchronen Publish/Subscribe auch das synchrone Request/Reply Muster. Dazu gibt der Publisher beim Senden ein Reply-Subject, welches auch Inbox genannt wird an. Ein Subscriber kann über die Inbox eine Nachricht zurück an den Sender schicken.

4. Quality of Service

Die Garantie Exactly once stellt sicher, dass jede Nachricht zugestellt wird und es keine Duplikate gibt. Dies ist die umfassendste Garantie der Zustellung, aber auch die, die am meisten Zeit und Ressourcen kostet. Eine robuste Anwendungsarchitektur sollte mit Duplikation umgehen können, aus diesem Grund verzichten viele Messaging Systeme wie NATS auf die Exactly once Garantie. Wer dennoch nicht auf Exactly once verzichten möchte, kann sich die Persistence Engine JetStream ansehen.

NATS Core bietet ausschließlich die Quality of Service Stufe at-most-once an, d.h. eine Zustellung ist nicht garantiert. Ein Beispiel dafür wären langsame Subscriber. Ein JMS Broker speicht Nachrichten zwischen, falls ein Consumer langsamer ist als ein Producer. Kommt der Konsonder nicht mit, so stauen sich Nachrichten für eine spätere Verarbeitung an. NATS Core bietet keine Persistenz um Nachrichten zwischenzuspeichern. Nachrichten werden in diesem Fall einfach verworfen. Das verhindert, dass die Platte des Brokers mit Nachrichten vollläuft und dadurch eine Wartung nötig wird. Bei NATS Core ist die Verfügbarkeit des Brokers wichtiger, als die Zustellung einer einzelnen Nachricht.

5. Unterschiede zu anderen Messaging Brokern

Der auffälligste Unterschied zu ActiveMQ, Artemis, RabbitMQ und anderen Brokern ist das Fehlen der Zwischenspeicherung der Nachrichten auf der Platte.

NATS besteht im Gegensatz zu anderen Brokern nur aus einer einzigen ausführbaren Datei. Weitere Dateien gibt es nicht. Bei Bedarf kann noch eine Konfigurationsdatei erstellt werden. Der simple Aufbau erleichtert das erstellen eines Docker Containers und den Betrieb in der Cloud.

Neben der Nachricht selbst bieten viele Broker die Möglichkeit in Header-Feldern zusätzlich Metadaten wie z.B. ein Zeitstempel oder eine Correlation-Id mitzuschicken. Bei NATS gibt es keine Header-Felder. Sollen Metadaten mitgeschickt werden, muss das Header/Body Muster verwendet werden und die eigentliche Nachricht in eine Hülle zusammen mit den Metadaten eingepackt werden.

6. Entwicklung

Für die Entwicklung eines Producer oder Subscribers stehen Client Bibliotheken zur Verfügung. Die Art und Weise, wie Producer und Consumer erstellt werden, ist von der Client API abhängig und unterscheidet sich stark von Programmiersprache zu Programmiersprache.

Als Payload akzeptiert NATS außschließlich Byte-Arrays. Die Serialisierung und Deserialisierung von und nach Bytes übernimmt NATS nicht. Der Entwickler muss sich selbst darum kümmern, wie er Nachrichten umwandelt.

6.1. Client APIs

Für NATS gibt es ca. drei Dutzend Client APIs für unterschiedliche Programmiersprachen und Betriebssysteme:

  • Arduino
  • C
  • .NET, C#
  • Go
  • Java
  • Javascript/TypeScript
  • NGINX
  • PHP
  • Python
  • Rust

Beispiel Client in Go

Mit allen Client Bibliotheken können NATS Clients mit wenigen Zeilen Code realisiert werden. Das folgende Beispiel zeigt einen Producer in der Sprache Go.

nc, _ := nats.Connect(nats.DefaultURL)
defer nc.Close()

nc.Publish("nrw.bonn", []byte("Hallo aus Bonn"))
					

6.2. Java mit Spring Boot

Wer mit Spring Boot arbeitet kann den Starter für NATS verwenden um dann auf NATS über Spring Cloud Stream zuzugreifen.

7. Ökosystem

Die überschaubare Anzahl an Features kompensiert NATS mit einem umfangreichen Ökosystem an Konnektoren und Tools. Stand Oktober 2020 sind über 50 Konnektoren, Integrationen und Werkzeuge für NATS verfügbar. Dazu zählen unter anderem:

  • Konnektoren für Streaming z.B. Apache Flink und Apache Spark
  • Templates und Vorlagen für die Cloud z.B. AWS, Dokku, Kubernetes
  • Logging für Elastic Search, Fluent, Logrus, ...
  • Messaging Bridges für: IBM MQS Series, Redis, Kafka
  • Erweiterung für synchrone RPC Aufrufe über NATS
  • Websocket Gateways
  • Monitoring Dashboards

8. NATS und Microservices

Microservices sind lose gekoppelte Teile einer Anwendung, die möglichst isoliert entwickelt, getestet und betrieben werden sollten. Für die lose Verbindung der Services eignet sich asynchrones Messaging. NATS ist eine beliebte Plattform um Microservices zu verbinden. Beispielsweise setzt das Microservices Toolkit Hemera auf NATS auf.

9. Performanz

Bei Messaging Lösungen hängt die Performanz von den gewünschten Garantien ab. Da NATS Core keine Garantien bietet, ist die Performanz erwartungsgemäß recht hoch. So lassen sich Übertragungsraten von mehreren Millionen Nachrichten pro Sekunde erzielen.

10. Betrieb

Der einfache Aufbau von NATS verspricht einen unkomplizierten Betrieb. Der Broker hält selbst keinerlei Status, das heißt er schreibt nichts ins Dateisystem, daher reduzieren sich die Wartungsarbeiten auf Restarts und Updates.

Für das Einrichten und den Betrieb unter Kubernetes gibt es eine ausführliche Anleitung.

10.1. Monitoring

Für NATS gibt es eine Prometheus Integration sowie Konnektoren für ELK und weitere Logging Plattformen.

11. Clustering

Ein NATS Cluster kann Hochverfügbarkeit und Skalierbarkeit bieten.

NATS Knoten können einem Cluster beitreten und wieder verlassen. Es bildet sich selbstständig ein Mesh. Um dem Cluster beizutreten muss sich ein Knoten an ein Mitglied im Cluster wenden. Dieser Knoten übernimmt für ihn die Rolle des Seed-Knotens. Die Knoten tauschen sich untereinander über neue Knoten oder über Knoten, die nicht mehr erreichbar sind aus. Für den Austausch wird ein Gossip-Protokoll verwendet, eine verteilte Registry wie Zookeeper ist nicht notwendig.

Clients verbinden sich mit einem Knoten im Cluster. Der Knoten informiert seine Clients über die anderen Knoten im Cluster. Der Client merkt sich die Liste der Knoten und kann im Fehlerfall auf einen anderen Knoten wechseln.

11.1. Supercluster

Mehrere Cluster können über Gateways zu Superclustern zusammen geschlossen werden.

Die Firma, die NATS hauptsächlich entwickelt, bietet mit NGS einen Cloud Service auf der Basis von NATS an. NGS ist ein hochverfügbarer Supercluster, der die gesamte Welt umspannt. Über die Mandantenfähigkeit (Multitenency) ist es möglich diese Infrastruktur isoliert den Kunden anzubieten. Diese bekommen mit NGS einen weltweiten hochverfügbaren Cluster für das asynchrone Messaging, der in wenigen Minuten zur Verfügung steht und nur wenige Euros an Servicegebühr pro Monat kostet.

12. Mandantenfähigkeit Multi Tenancy

Eine NATS Infrastruktur kann von mehreren Mandaten z.B. Microservices Anwendungen gleichzeitig verwendet werden. Für jeden Mandaten wird ein Account angelegt, die vollkommen isoliert voneinander arbeiten. Das Empfangen von Nachrichten eines anderen Mandanten wird so verhindert.

Falls gewünscht, kann ein geplanter und kontrollierter Austausch auch zwischen mehreren Mandaten stattfinden.

Über die Mandantenfähigkeit kann eine NATS Installation für viele Kunden in der Cloud als Service bereit gestellt werden.

13. Sicherheit

Die Kommunikation mit NATS kann mit TLS abgesichert werden. Für die Authentifizierung von Client-Verbindungen stehen die folgenden Verfahren zur Verfügung:

  • TLS Zertifikate
  • NATS Credentials
  • NKEYS (ED25519)
  • Benutzername und Passwort

Für die Autorizierung könnnen für das Schreiben und Lesen von einem Subject Berechtigungen eingerichtet werden.

14. Fazit

Wer eine wartungsarme und schlanke Messaging Plattform für die Cloud, für Microservices oder für die Integration in eigene Produkte sucht, sollte sich NATS Core anschauen.

NATS ist keine Enterprise Messaging Lösung wie z.B. die Java Messaging Service Implementierungen Apache ActiveMQ oder Artemis, die Transaktionen und eine sichere Zustellung bieten. Dafür ist NATS schlank und ermöglicht den wartungsarmen Betrieb einer performanten und hochverfügbaren Messaging Infrastruktur. Die fehlende Message Persistenz sollte nicht abschrecken. Mit Kommunikationsmustern in der Anwendungsschicht kann das Fehlen der Persistenz bei einigen Anwendungsfällen ausgeglichen werden. Wer dennoch nicht auf die Message Persistenz verzichten kann sollte einen Blick auf NATS Streaming werfen.

Videos zum Artikel

Publish/Subscribe
Request-Reply und Queuing
Slow Consumers
Clustering
Mandanten, Accounts
Quellcode Demoprojekt

Den Code zu den Videos findest du auf github.