# Lab 10: Messaging-basierte Interaktion Wir werden in diesem Lab Messaging überaschenderweise am Beispiel einer Datenbank -- [Redis](https://redis.io) -- demonstrieren. Wir nutzen Redis vor allem deswegen, weil es sehr einfach zu deployen ist und bereits an anderen Stellen in Labs verwendet wurde und wir so den Technologiestack übersichtlich und die Komplexität überschaubar halten können. Redis wurde zwar primär als In-Memory Key-Value Datenbank entwickelt, hat jedoch mittlerweile sowohl Publish-Subscribe als auch Queueing Features erhalten, die für einfache Anwendungsfälle durchaus ausreichend sind. Als Messaging-Komponenten werden in Cloud-nativen Systemen häufig "klassische" Lösungen wie bspw. [Kafka](https://kafka.apache.org), [Nats](https://nats.io), [RabbitMQ](https://www.rabbitmq.com), [ActiveMQ](https://activemq.apache.org) und weitere [AMQP](https://www.amqp.org)- oder [MQTT](https://mqtt.org)-konforme Lösungen verwendet. Die in diesem Lab am Beispiel von Redis vermittelten Prinzipien sind aber durchaus auf diese Systeme übertragbar, da die zu Grunde liegenden Kommunikationsmuster Publish-Subscribe und Queueing letztlich von all diesen Messaging-Systemen ermöglicht werden. ## Inhalt - [Lab 10: Messaging-basierte Interaktion](#lab-10-messaging-basierte-interaktion) - [Inhalt](#inhalt) - [Vorbereitung](#vorbereitung) - [Übung 01: Pub/Sub Messaging (Fan Out)](#übung-01-pubsub-messaging-fan-out) - [Übung 02: Persistentes Pub/Sub Messaging](#übung-02-persistentes-pubsub-messaging) - [Übung 03: Event Sourcing](#übung-03-event-sourcing) - [Übung 04: Queueing](#übung-04-queueing) - [Verständnis- und Transferfragen](#verständnis--und-transferfragen) - [Links](#links) - [Was sollten Sie mitnehmen](#was-sollten-sie-mitnehmen) ## Vorbereitung Sie benötigen auf Ihren lokalen Entwicklungsrechner: - [Python 3](https://www.python.org/downloads) - [Docker](https://www.docker.com/get-started) - [Lens](https://k8slens.io) Führen Sie anschließend bitte folgende Schritte aus: 1. [Forken](https://git.mylab.th-luebeck.de/cloud-native/lab-rest/-/forks/new) Sie bitte dieses GitLab-Repository in Ihren GitLab-Namensraum. 2. Klonen Sie das in Schritt 1 geforkte Repository bitte anschließend auf ihrem lokalen Rechner (`git clone`). 3. Installieren Sie anschließend bitte lokal auf Ihrem Rechner die Kubernetes-IDE [Lens](https://k8slens.dev/). 4. Laden Sie sich Ihre `kubeconfig` Datei im [Moodle-Kurs](https://to-be-donex) herunter. 5. Starten Sie Lens und fügen Sie der IDE die kubeconfig Datei hinzu, um auf Ihren Cluster zugreifen zu können. Sie sollten dann Ihren Namespace in dem für Sie bereitgestellten K8S-Cluster sehen. 6. Erstellen Sie anschließend in Gitlab unter `Einstellungen -> Repository -> Bereitstellungstoken` für das in Schritt 1 geforkte Repository einen Bereitstellungstoken, um selbstgebaute Container Images deployen zu können. - **Name:** `Registry read access (deployment)` - **Username:** `image-registry` (bitte exakt so!) - **Scope:** `read-registry` (nicht mit read repository verwechseln!) - Klicken Sie anschließend auf Bereitstellungstoken erstellen und kopieren Sie sich dieses geheime Token in die Zwischenablage! 7. Hinterlegen Sie nun für Gitlab Build-Pipelines dieses geheime Token unter `Einstellungen -> CI/CD -> Variables (Aufklappen) -> ADD VARIABLE` als CI/CD-Variable. - **Key:** `CI_REGISTRY_TOKEN` (exakt so) - **Value:** Fügen Sie hier das geheime Token (Schritt 2) aus der Zwischenablage ein. - **Type:** `Variable` (nichts anderes) - **Flags:** Selektieren Sie `Mask Variable` damit das geheime Token in Log-Dateien maskiert wird. 8. Hinterlegen Sie in Ihrem geforkten GitLab-Repository nun die `kubeconfig`-Datei als CI-Environment-Variable mittels `Einstellungen -> CI/CI -> Variables (Aufklappen) -> ADD VARIABLE` (setzen Sie hierfür folgende Werte) - **Key:** `KUBECONFIG` (Exakt so eingeben) - **Value:** Inhalt der kubeconfig (z.B. mittels Copy-Paste aus Editor) - **Typ:** `File` (Auswählen, WICHTIG!!!) 9. Öffnen Sie Lens und hinterlegen Sie mittels `+` die `kubeconfig`-Datei, die Sie auch im vorherigen Schritt in der Deployment Pipeline hinterlegt haben. ## Übung 01: Pub/Sub Messaging (Fan Out) In dieser Übung werden wir uns folgenden Publish-Subscribe Kommunikationsmuster widmen. ``` +--M3,M2,M1-> C | P --M3,M2,M1--+--M3,M2,M1-> C | +--M3,M2,M1-> C ``` Ein Producer *P* erzeugt Messages, die in einen Channel einer Message Queue gegeben werden (Publish). Diese Queue verteilt dann alle Messages an Consumer *C*, die sich für diesen Channel angemeldet haben (Subscribe). Auf diese Weise erhalten alle Consumer alle Messages, ohne dass Producer die Empfänger kennen muss. Die Message Queue entkoppelt so Producer von Consumer und umgekehrt. - Studieren Sie bitte sowie den [Publish/Subscribe Abschnitt](https://github.com/andymccurdy/redis-py#publish--subscribe) der Redis Python API. - Versuchen Sie nun die beiden Dateien `messaging/pubsub-producer.py` und `messaging/pubsub-consumer.py` nachzuvollziehen. - Versuchen Sie nun die `.gitlab-ci.yaml` sowie die Kubernetes Manifests im Ordner `deploy` nachzuvollziehen. Die Deployment Pipeline dieses Labs erzeugt eine Redis Datenbank in Ihrem Kubernetes Namespace und sieht diverse manuell triggerbare Jobs für unterschiedliche Consumer und Producer vor, um Teile dieses Labs zu starten. - Triggern Sie nun diese Pipeline (bspw. durch einen Commit dieses Repos). - Wenn die Redis Datenbank erfolgreich in Kubernetes läuft (checken Sie dies in Lens), wechseln Sie in Gitlab in die Pipelines Ansicht (`CI/CD -> Pipelines` -> auf letzte bestandene Pipeline klicken) und starten Sie manuell die beiden Jobs `pubsub-consumer` und `pubsub-producer` in der Web-Oberfläche (Play Buttons der Jobs). - Im Lens Terminal (oder der Oberfläche sollten Sie nun drei Pods sehen) ```Bash > kubectl get pods NAME READY STATUS RESTARTS AGE redis-599f4cc796-6pltl 1/1 Running 0 25m pubsub-consumer-b9756d886-62z8l 1/1 Running 0 19m pubsub-producer-79bcdbf9d8-bdxrn 1/1 Running 0 19m ``` - Sehen Sie sich in Lens nun die Logs des Producers an: ``` ... Publishing message 'Hi, this is message #4317 from pubsub-producer-79bcdbf9d8-bdxrn.' to channel 'xpubsub' Publishing message 'Hi, this is message #4318 from pubsub-producer-79bcdbf9d8-bdxrn.' to channel 'xpubsub' Publishing message 'Hi, this is message #4319 from pubsub-producer-79bcdbf9d8-bdxrn.' to channel 'xpubsub' Publishing message 'Hi, this is message #4320 from pubsub-producer-79bcdbf9d8-bdxrn.' to channel 'xpubsub' Publishing message 'Hi, this is message #4321 from pubsub-producer-79bcdbf9d8-bdxrn.' to channel 'xpubsub' ``` - Die Logs des Consumers sollten in etwa so aussehen: ``` ... 0.92ms | msg: {"timestamp": 1614764396330193114, "message": "Hi, this is message #4689 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.64ms | msg: {"timestamp": 1614764396731672144, "message": "Hi, this is message #4690 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.79ms | msg: {"timestamp": 1614764397232874681, "message": "Hi, this is message #4691 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.79ms | msg: {"timestamp": 1614764397734203948, "message": "Hi, this is message #4692 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.81ms | msg: {"timestamp": 1614764398035370260, "message": "Hi, this is message #4693 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.52ms | msg: {"timestamp": 1614764398236610874, "message": "Hi, this is message #4694 from pubsub-producer-79bcdbf9d8-bdxrn."} 0.70ms | msg: {"timestamp": 1614764398737878344, "message": "Hi, this is message #4695 from pubsub-producer-79bcdbf9d8-bdxrn."} ``` Die Zeitangaben in ms geben an, wie lange eine Message vom Producer zum Consumer benötigt hat (Latenz). Vergleichen Sie diese Werte mit den Werten, die Sie im letzten Lab zu REST und gRPC basierten Interaktionsverfahren erhoben haben. - Merken Sie sich in etwa die letzte Messagenummer, die der Consumer bis dahin erhalten hat. Löschen Sie dann in Lens den Consumer und warten Sie ab, bis der Pod wieder durch Kubernetes automatisch neu gestartet wurde. Prüfen Sie im neuen Container Log des regenerierten Pods ab welcher Message Nummer dieser das Streaming wieder auf nimmt? - Löschen Sie nun das Producer Deployment in Lens, so dass kein neuer Producer Pod gestartet wird? Laufen noch weitere Messages im Consumer auf? Stürzt der Consumer ab? - Deployen Sie in Gitlab mittels des manuellen Pipeline Jobs erneut den Producer (Play Button des Jobs). - Der Producer sollte wieder ab 1 nummerierte Messages erzeugen, die der Consumer im Log anzeigt. - Skalieren Sie nun in Lens den Producer auf 3 Instanzen hoch (`Producer Deployment -> Scale`). Achten Sie nun im Consumer Log auf die Ursprünge der Messages. Sie erhalten nun Messages von mehreren Producern. ``` 0.89ms | msg: {"timestamp": 1614765108327074527, "message": "Hi, this is message #95 from pubsub-producer-79bcdbf9d8-ch4w9."} 1.10ms | msg: {"timestamp": 1614765108467772402, "message": "Hi, this is message #610 from pubsub-producer-79bcdbf9d8-lc2rq."} 0.78ms | msg: {"timestamp": 1614765108746772325, "message": "Hi, this is message #100 from pubsub-producer-79bcdbf9d8-nzr2v."} 0.86ms | msg: {"timestamp": 1614765108828138961, "message": "Hi, this is message #96 from pubsub-producer-79bcdbf9d8-ch4w9."} 0.81ms | msg: {"timestamp": 1614765108869005443, "message": "Hi, this is message #611 from pubsub-producer-79bcdbf9d8-lc2rq."} ``` - Skalieren Sie auch die Consumer auf drei Instanzen hoch. Vergleichen Sie die Logs der drei Pods in Lens. Laufen unterschiedliche Messages auf? - Löschen Sie nun das Producer Deployment und das Consumer Deployment (entweder in Lens oder mit dem Gitlab Pipeline `pubsub`-Job in der `terminate`-Stage). Diese Übung hat nicht persistentes PubSub-Messaging mittels Redis demonstriert. Sie haben gesehen, dass Sie sowohl Consumer wie auch Producer unabhängig von einander hoch- und herunterskalieren können. Sie haben allerdings auch gesehen, dass diese Form des Messaging stateless ist. Messages, die einmal verschickt wurden, werden von Redis vergessen. Wenn Sie Anwendungsfälle haben, in denen die Historie von Events wichtig ist, weil Sie ggf. wieder abgespielt werden müssen (z.B. um eine Datenbank zu rekonstruieren), benötigen wir persistente Messaging Systeme. Als Datenbank, kann Redis dies natürlich auch. ## Übung 02: Persistentes Pub/Sub Messaging Diese Übung zeigt Ihnen wie man Redis als persistentes Messaging System einsetzen kann. Wir nutzen hierfür das `xadd`-[Command](https://redis.io/commands/XADD) (Producer) von Redis mit dem Redis Event Streams aufbauen kann. Mittels des `xread`-[Commands](https://redis.io/commands/XREAD) lässt sich aus solchen Streams lesen (Consumer). - Lesen Sie sich hierzu als erstes ein wenig in [Redis Streams](https://redis.io/topics/streams-intro) ein. - Studieren Sie anschließend die Klasse `messaging/MQueue.py`. Hier ist Ihnen eine Wrapper-Klasse um Redis gegeben, die die Commands `xadd`, `xread` und `xgroupread` so kapselt, dass diese komfortabel mittels einer `listen()`-Methode für Consumer und mittels einer `publish()`-Methode für Producer genutzt werden kann. *Auf `listen_as_group()` gehen wir in Übung 04 noch genauer ein.* - Versuchen Sie nun die Dateien `messaging/queueing-producer.py` und `messaging/queueing-consumer.py` nachzuvollziehen, um zu verstehen, wie man die Klasse `MQueue` für ein Publish-Subscribe Pattern einsetzen kann. - Starten Sie nun in Gitlab manuell die Jobs `queueing-consumer` und `queueing-producer` in der `deploy`-Stage um einen Consumer und einen Producer zu erzeugen. - Warten Sie ab, bis beide Deployments erzeugt wurden (vollziehen Sie dies in Lens nach). - Sehen Sie sich dann in Lens die Logs des Consumer Pods und die Logs des Producer Pods an. Sie sehen, das funktinioniert wie in Übung 01 auch. - Löschen Sie nun das Consuming Deployment (es soll also wirklich kein Consuming Pod laufen). Warten Sie ein paar Minuten und merken Sie sich im Consumer in etwa die Message die zum Zeitpunkt des Löschens erzeugt wurde. - Deployen Sie dann den Consumer in Gitlab erneut. Beobachten Sie nun in Lens das Verhalten im Pod Log des neuen Consumers. Sie werden feststellen, dass es im Consumer immer noch einen Gap bei den empfangenen Messages gibt. Die Messages während der Consumer down war, werden weiterhin nicht empfangen. Was soll also der ganze Aufwand mit der Persistierung von Message Streams? ## Übung 03: Event Sourcing Messaging Systeme werden normalerweise so eingesetzt, dass Consumer ab dem Zeitpunkt auf Events lauschen, ab dem Sie gestartet wurden. Man verfolgt also normalerweise Messages in (naher) Echtzeit und ist nicht an Events der Vergangenheit interessiert. Es kann aber durchaus sinnvoll sein, auch Events der Vergangenheit zu verarbeiten. Z.B. weil eine Teilkomponenten down war (ggf. sogar mehrere Stunden). Dann wäre es schön, wenn man dieses "Backlog" wieder aufarbeiten könnte, einfach indem man die Events noch einmal ablaufen lässt. Dies ist -- vereinfacht ausgedrückt -- [Event Sourcing](http://martinfowler.com/eaaDev/EventSourcing.html) (vgl. auch [Wikipedia](https://de.wikipedia.org/wiki/Event_Sourcing)). Man kann persistenten Messaging Systemen normalerweise mitteilen, ab welchem Zeitpunkt Events abgerufen werden sollen. Unsere Wrapper-Klasse sieht hierzu den `since`-Parameter vor. Ergänzen Sie nun in der `messaging/queueing-consumer.py` diesen `since`-Parameter. ```Python for since, msg in queue.listen(since=0): print(msg) ``` Committen Sie diese Änderung in das Repo und deployen Sie dann den Consumer mittels der Gitlab Pipeline erneut. Beobachten Sie nun in Lens das Verhalten im Pod Log des neuen Consumers. Sie sollten feststellen, dass einige Messages sehr schnell einfliegen, und sich dann irgendwann des Tempo verlangsamt. Woher kommt das? Es werden nun alle Messages abgerufen (seit Anbeginn der Queue). In Übung 01 wären diese Messages einfach "verschwunden". Sie können auch ab einem beliebigen Zeitpunkt aufsetzen. Schauen Sie doch einfach in Ihr Log des Consumers, um sich einen beliebigen Aufsetzpunkt zu wählen. ``` 15331.28ms | msg b'1614769654088-0': {'text': 'Hi, this is message #625 from queueing-producer-64b575bb98-wssf2.'} 10327.25ms | msg b'1614769659092-0': {'text': 'Hi, this is message #626 from queueing-producer-64b575bb98-wssf2.'} 6322.52ms | msg b'1614769663096-0': {'text': 'Hi, this is message #627 from queueing-producer-64b575bb98-wssf2.'} 5320.72ms | msg b'1614769664098-0': {'text': 'Hi, this is message #628 from queueing-producer-64b575bb98-wssf2.'} 1319.34ms | msg b'1614769668100-0': {'text': 'Hi, this is message #629 from queueing-producer-64b575bb98-wssf2.'} ``` Um z.B. ab der Message `#628` weiter zu lesen, könnten dann folgendes eingeben: ```Python for since, msg in queue.listen(since=1614769663096): print(msg) ``` Committen Sie, pushen Sie in die Gitlab Pipeline und redeployen anschließend den Consumer erneut. Sie werden feststellen, die Logs setzen ab Message `#628` fort. ``` queueing-consumer-66cc6f8cfb-v55w8 has found already existing consumer group for xqueue 594444.00ms | msg b'1614769664098-0': {'text': 'Hi, this is message #628 from queueing-producer-64b575bb98-wssf2.'} 590442.67ms | msg b'1614769668100-0': {'text': 'Hi, this is message #629 from queueing-producer-64b575bb98-wssf2.'} 588439.98ms | msg b'1614769670102-0': {'text': 'Hi, this is message #630 from queueing-producer-64b575bb98-wssf2.'} 583434.14ms | msg b'1614769675108-0': {'text': 'Hi, this is message #631 from queueing-producer-64b575bb98-wssf2.'} 581431.20ms | msg b'1614769677111-0': {'text': 'Hi, this is message #632 from queueing-producer-64b575bb98-wssf2.'} 579428.24ms | msg b'1614769679114-0': {'text': 'Hi, this is message #633 from queueing-producer-64b575bb98-wssf2.'} ... ``` __Transferaufgabe:__ - Schreiben Sie den Consumer so um, dass er sich den Zeitpunkt der letzten von Ihm verarbeiteten Nachricht merkt (Achtung Stateful! Sie brauchen dann wohl ein Volume oder Sie speichern sich dies in Redis selber!), damit er bei einem Restart an exakt dieser Stelle mit der Verarbeitung des Event Streams fortsetzen kann. - Passen Sie ggf. die Deployment Pipeline und das Deployment Manifest an (falls Sie ein Volume nutzen wollen). Sie können auch gerne mehrere Consumer starten. Sie werden feststellen, dass diese alle ab derselben Stelle mit der Bearbeitung fortsetzen werden. D.h. die Messages gehen immer noch wie in Übung 01 und 02 an alle Consumer. Was können wir machen, damit Messages über mehrere Consumer gleichmäßig verteilt werden, um Arbeit über mehrere Instanzen verteilen zu können? ## Übung 04: Queueing Beim Queueing Kommunikationsmuster erzeugt ein Producer *P* Messages, die wie gehabt in einen Channel einer Message Queue gegeben werden (Publish). Diese Queue verteilt dann allerdings alle Messages an mehrere Consumer *C1, C2, C3, ..* einer Gruppe, die sich für diesen Channel angemeldet haben (Subscribe). So gehen nicht alle Messages an alle Consumer, sondern werden innerhalb der Gruppe verteilt. Weiterhin müssen sich die Consumer untereinander nicht kennen und der Producer die Consumer ebenfalls nicht. ``` +--M4,M1-> C1 | P --M4,M3,M2,M1--+-----M2-> C2 | +-----M3-> C3 ``` Messaging Systeme benötigen hierfür zusätzlich die Information welche Consumer sich zu einer Gruppe zusammenfinden. Für die Subscription ist also auf Seiten des Consumers zusätzlich die Angabe einer Gruppe erforderlich, damit das Messaging System Messages innerhalb der Gruppe auch verteilen kann. Um dies auszuprobieren, können Sie in der `messaging/queueing-consumer.py` die `listen_as_group()`-Methode nutzen. ```Python for since, msg in queue.listen_as_group("consumers"): print(msg) ``` Committen Sie diese Änderung in das Repo und deployen Sie dann den Consumer mittels der Gitlab Pipeline erneut. Beobachten Sie nun in Lens das Verhalten im Pod Log des neuen Consumers. Auf den ersten Blick werden Sie keine Änderung feststellen. Das Verhalten des Consumers ist wie in Übung 02. ``` [...] 1.07ms | msg b'1614773969217-0': {'text': 'Hi, this is message #2066 from queueing-producer-64b575bb98-wssf2.'} 1.25ms | msg b'1614773973223-0': {'text': 'Hi, this is message #2067 from queueing-producer-64b575bb98-wssf2.'} 1.00ms | msg b'1614773974225-0': {'text': 'Hi, this is message #2068 from queueing-producer-64b575bb98-wssf2.'} 1.05ms | msg b'1614773976228-0': {'text': 'Hi, this is message #2069 from queueing-producer-64b575bb98-wssf2.'} 1.20ms | msg b'1614773981234-0': {'text': 'Hi, this is message #2070 from queueing-producer-64b575bb98-wssf2.'} [...] ``` Ändern Sie nun in Lens unter `Deployment ->` Consumer Deployment `-> Scale` die Anzahl an Replikas auf 2. Nachdem diese Änderung durchgeführt wurde, sollten Sie das Log wie folgt ändern. ``` [...] {b'timestamp': b'1614774102389935781', b'data': b'{"text": "Hi, this is message #2116 from queueing-producer-64b575bb98-wssf2."}'} {b'timestamp': b'1614774109399088060', b'data': b'{"text": "Hi, this is message #2118 from queueing-producer-64b575bb98-wssf2."}'} {b'timestamp': b'1614774115402776414', b'data': b'{"text": "Hi, this is message #2120 from queueing-producer-64b575bb98-wssf2."}'} {b'timestamp': b'1614774122410759056', b'data': b'{"text": "Hi, this is message #2122 from queueing-producer-64b575bb98-wssf2."}'} [...] ``` D.h. die Message Nummern steigen nun in zweier Schritten (da zwei Replikas des Consumers vorhanden sind). Wenn Sie die Replikas auf fünf setzen, werden die Messages in einem Consumer Pod, dann in fünfer Schritten steigen. Usw. Sie können dies gerne in den einzelnen Logs der Consumer Pods nachvollziehen. ## Verständnis- und Transferfragen - Für welche Anwendungsfälle würden Sie das PubSub-Kommunikationsmuster einsetzen? - Für welche Anwendungsfälle würden Sie das Queueing-Kommunikationsmuster einsetzen? - Welche Vor- und Nachteile hat die Persistierung von Message Queues? - Erklären Sie Event Sourcing in eigenen Worten. - Vergleichen Sie die Latenzzeiten bei PubSub und Queue? Gibt es nennenswerte Unterschiede? - Vergleichen Sie die Latenzzeiten dieses Labs mit dem gRPC-Lab? Welche Technologie ist grundsätzlich performanter? Woher kommt dies vermutlich? - Wie stufen Sie den Grad der Kopplung bei Messaging/Streaming im Vergleich zu gRPC ein? - Wie stufen Sie den Grad der Kopplung bei Messaging/Streaming im Vergleich zu REST ein? - Blicken wir nun auf die Labs zu REST, gRPC und Streaming zurück. Vor dem Hintergrund loser Kopplung und Performanz: - In welchen Fällen würden Sie REST einsetzen? - In welchen Fällen würden Sie gRPC einsetzen? - In welchen Fällen würden Sie Messaging einsetzen? - In welchen Messaging Fällen würden Sie non-persistent Publish-Subscribe einsetzen? - In welchen Messaging Fällen würden Sie persistent Publish-Subscribe einsetzen? - In welchen Messaging Fällen würden Sie non-persistent Queueing einsetzen? - In welchen Messaging Fällen würden Sie persistent Queueing einsetzen? ## Links - [Redis](https://redis.io) - [Introduction to Redis Streams](https://redis.io/topics/streams-intro) - Weitere Messaging Lösungen wie [Kafka](https://kafka.apache.org), [Nats](https://nats.io), [RabbitMQ](https://www.rabbitmq.com), [ActiveMQ](https://activemq.apache.org) - Messaging Standards wie [AMQP](https://www.amqp.org) und [MQTT](https://mqtt.org) - [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) (Martin Fowler) - [Event Sourcing](https://de.wikipedia.org/wiki/Event_Sourcing) (Wikipedia) ## Was sollten Sie mitnehmen - Obwohl Redis eigentlich eine In-Memory Key-Value Datenbank ist, kann Sie (für viele überraschend) auch für (einfaches) Messaging eingesetzt werden. Gegenüber komplexeren Lösungen wie bspw. Kafka kann dies durchaus von Vorteil sein. - Das Kommunikationsmuster Publish-Subscribe kann für vor allem für Fan-Out Anwendungsfälle eingesetzt werden, d.h. bei der Nachrichten an ALLE Consumer gehen. Wenn Publish-Subscribe Messaging persistiert wird, kann es zum [Event Sourcing](https://de.wikipedia.org/wiki/Event_Sourcing) verwendet werden. - Das Kommunikationsmuster Queueing wird vor allem für Load Balancing eingesetzt werden, bei der Nachrichten über mehrere Consumer zur Verarbeitung verteilt und dort verarbeitet werden müssen. Sowohl Producer als auch Consumer können dabei unabhängig von einander skaliert werden. - Persistente Messaging Systeme können als Event Stores im Rahmen des Event Sourcings eingesetzt werden. - Messaging ist hinsichtlich Übertragungslatenzen meist performanter als gRPC, gRPC ist üblicherweise performanter als REST. - Sowohl REST als auch Messaging ermöglichen eine lose Kopplung von Services. - Die bislang betrachteten Technologien kann man aufsteigend anhand des Grads Ihrer Kopplung ordnen: 1. **Messaging** (Consumer und Producer gehen eine Kopplung zu einem Use Case agnostischen Message Broker ein) 2. **REST** (Consuming Services gehen eine Kopplung zu einem Providing Service ein) 3. **gRPC** (Consuming und Providing Service gehen eine gegenseitige Kopplung ein) Eine abschließende Platzierung der betrachteten Ansätze könnte daher wie folgt aussehen: | Technologie | Kopplung | Performanz | Broker | Summe der Platzierungen | Kommunikationsmuster |-------------|:--------:|:----------:|:------: |:------:|-------------------------- | REST | 2 | 3 | nein (1)| **6** | Request-Response | gRPC | 3 | 2 | nein (1)| **6** | Request-Response | Messaging | 1 | 1 | ja (3) | **5** | Publish-Subscribe + Queueing Einen klaren Gewinner gibt es also nicht (ansonsten hätte sich dieser vermutlich auch schon durchgesetzt). Es kommt also (wie so häufig) auf den Use Case an.