Exactly Once in verteilten Systemen: Realität oder Utopie?

Bei verteilten Systemen wird eine asynchrone Kommunikation häufig über einen Message Broker abgedeckt. Dadurch soll eine Entkopplung zwischen zwei Diensten erreicht werden, die unter Umständen separat skaliert werden können. Eine Kommunikation über einen Message Broker ist inhärent immer mindestens zweigeteilt, nämlich in Producer und Consumer. Ein Producer erstellt dabei Nachrichten, wie in Abbildung 1 gezeigt, während ein Consumer sie verarbeitet. Abb.1: Einfacher Nachrichtenaustausch Der Message Broker ist häufig ein zustandsbehaftetes System – eine Art Datenbank – und vermittelt Nachrichten zwischen Producer und Consumer. Als zustandsbehaftetes System hat ein Message Broker die Aufgabe, Nachrichten vorzuhalten und abrufbar zu machen. Ein Producer schreibt also Nachrichten in den Broker, während ein Consumer sie zu einer beliebigen Zeit lesen kann. Exactly once, also einmaliges Ausliefern, bedeutet, dass der Producer genau eine Nachricht produziert und der Consumer diese genau einmal verarbeitet. Also ganz einfach, oder? .nl-in-blog {background: url(https://jax.de/wp-content/uploads/2024/02/JAX24_Blog_Textblock.jpg); background-size:cover; color:#ffffff;} .wp-nl-header .col-xl-12.col-lg-12.col-md-12.nlform{height: 100px; background-color: #f2f2f2; border-radius: 25px 25px 25px 25px; padding: 0px 2px;} .body .mc4wp-form-fields input {border-radius: 25px !important;} .wp-nl-header input.custom-primary-button.gdlr-button.dark-button{padding: 6px 40px !important; height: 70% !important; border-radius: 25px 25px 25px 25px !important; align-self: center;} Stay tuned Regelmäßig News zur Konferenz und der Java-Community erhalten (function() { window.mc4wp = window.mc4wp || { listeners: [], forms: { on: function(evt, cb) { window.mc4wp.listeners.push( { event : evt, callback: cb } ); } } } })(); Leave this field empty if you're human: Es kann so einfach sein Da eine Kommunikation zwischen den Systemen über eine Netzwerkebene stattfindet, ist nicht gewährleistet, dass die Systeme über den gleichen Wissensstand verfügen. Es muss also einen Rückkanal geben, der einzelne Operationen bestätigt, um einen Zustand zu teilen. Nur so wird sichergestellt, dass Nachrichten, die erstellt wurden, auch korrekt angekommen und verarbeitet worden sind. Aktualisiert sieht der Fluss also eher so aus, wie es Abbildung 2 zeigt. Abb. 2: Durch Bestätigungen wird der Zustand zwischen Systemen geteilt Erstellt ein Producer eine Nachricht, die vom Consumer gelesen werden soll, benötigt dieser eine Bestätigung (Abb. 2, Schritt 2). Nur dadurch weiß der Producer, dass die Nachricht korrekt im Broker persistiert vorliegt und er sie nicht erneut übertragen muss. Der Consumer wiederum liest die Nachricht und verarbeitet sie. Ist die Verarbeitung fehlerfrei abgeschlossen, bestätigt der Consumer das. Der Broker muss die Nachricht deshalb nicht noch einmal ausliefern. Immer Ärger mit der Kommunikation Bei einer verteilten Kommunikation über ein Netzwerk kann es leider immer passieren, dass diverse Kommunikationskanäle abbrechen oder Fehler entstehen – und zwar an vielen Stellen: beim Erstellen, vor dem Konsumieren und danach. Genau diese Eigenschaft macht es so schwer oder gar unmöglich, eine Exactly-once-Semantik zu erreichen. Angenommen, ein Producer produziert eine Nachricht (Abb. 3). Um sicherzustellen, dass diese auch vom Broker gespeichert wurde, wartet der Producer auf eine Bestätigung. Bleibt sie aus, ist nicht garantiert, dass der Broker diese Nachricht wirklich ausliefern wird. Abb. 3: Der Producer erhält keine Bestätigung und sendet die Nachricht erneut Der Producer muss diese Nachricht folglich erneut ausliefern. Genau das ist in Schritt 2 der Abbildung 3 auch geschehen, weshalb der Producer in Schritt 3 eine weitere Nachricht mit demselben Inhalt sendet. Da jetzt zwei Nachrichten vorliegen, verarbeitet der Consumer in den Schritt 4 und 5 beide Nachrichten – wohl eher nicht „exactly once“. Die Nachricht wird durch den Retry-Mechanismus „at least once“ – mindestens einmal, nicht genau einmal – übertragen. Denn wie im Bild zu erkennen ist, überträgt der Producer dieselbe Nachricht zweimal, um sicherzustellen, dass sie mindestens einmal vom Broker bestätigt wurde. Nur so ist sichergestellt, dass die Nachricht nicht verloren geht. .custom-primary-button.light-button{margin:auto;} @media only screen and (max-width: 767px){ .track--logo-blog{ margin-left: auto; margin-right: auto; } .blog-track-display{ display: flex; flex-direction: column; flex-wrap: wrap; } .blog-track-text{ text-align:center; } .blog-track-btn-main{ align-self: center!important; } } ALL ABOUT MICROSERVICES Microservices-Track entdecken Mehr erfahren .track-box-in-blog9542951.blog-track-display{ background-image: url("https://jax.de/wp-content/uploads/2024/02/JAX24_Blog_Textblock.jpg"); } .track-box-in-blog9542951.blog-track-display{ color:white; padding: 20px 25px; background-size: cover; } Natürlich kann die Bestätigung auch ignoriert werden. Schritt 2 kann also ausbleiben. Ein Retry-System würde folglich fehlen. Der Producer überträgt also eine Nachricht, ohne auf eine Bestätigung des Brokers zu warten. Kann der Broker die Nachricht selbst nicht verarbeiten oder wegspeichern, hat er keine Möglichkeit, das Fehlschlagen oder eine erfolgreiche Operation zu quittieren. Die Nachricht würde „at most once“ – maximal einmal oder eben keinmal – übertragen werden. Exactly once ist also grundsätzlich ein Problem verteilter Anwendungen, die mittels Bestätigungen funktionieren. Leider ist das noch nicht das Ende der Fahnenstange, wenn die Nachricht Ende zu Ende, also vom Producer bis zum Consumer, betrachtet wird. Denn es existiert in einem solchen System zusätzlich ein Consumer, der die Nachrichten wiederum einmalig verarbeiten muss. Selbst wenn garantiert wird, dass der Producer eine Nachricht einmalig erzeugt, ist ein einmaliges Verarbeiten nicht garantiert. Abb. 4: Ein Consumer verarbeitet die Nachricht und versucht diese danach zu bestätigen Es kann passieren, dass der Consumer wie in Abbildung 4 gezeigt die Nachricht in Schritt 3 liest und in Schritt 4 korrekt verarbeitet. In Schritt 5 geht die Bestätigung verloren. Das führt dazu, dass die Nachricht mehrmals, aber mindestens einmal – at least once – verarbeitet wird. Abb. 5: Ein Consumer bestätigt die Nachricht vor dem Verarbeiten Es ist natürlich umgekehrt auch möglich, die Nachricht vor dem Verarbeiten zu bestätigen. Der Consumer lädt also die Nachricht und bestätigt sie direkt. Erst dann wird in Schritt 5 von Abbildung 5 die Bearbeitung der Nachricht erfolgen. Schlägt jetzt die Bearbeitung fehl, ist die Nachricht in Schritt 4 bereits bestätigt worden und wird nicht erneut eingelesen. Die Nachricht wurde wieder maximal einmal oder keinmal – at most once – verarbeitet. Wie also zu erkennen, ist es leicht, At-most-once- und At-least-onceSemantiken in den verschiedenen Konstellationen sowohl auf Producer- als auch auf der Consumer-Seite herzustellen. Exactly once ist aber aufgrund der verteilten Systematik ein schwieriges Problem – oder gar unmöglich? .custom-primary-button.light-button{margin:auto;} @media only screen and (max-width: 767px){ .track--logo-blog{ margin-left: auto; margin-right: auto; } .blog-track-display{ display: flex; flex-direction: column; flex-wrap: wrap; } .blog-track-text{ text-align:center; } .blog-track-btn-main{ align-self: center!important; } } SIE LIEBEN JAVA? Den Core-Java-Track entdecken Mehr erfahren .track-box-in-blog9368944.blog-track-display{ background-image: url("https://jax.de/wp-content/uploads/2024/02/JAX24_Blog_Textblock.jpg"); } .track-box-in-blog9368944.blog-track-display{ color:white; padding: 20px 25px; background-size: cover; } Lösungen müssen her Für eine Möglichkeit, eine Exactly-once-Semantik zu erreichen, muss die Verarbeitung der Nachrichten einer Applikation eine bestimmte Eigenschaft unterstützen: Idempotenz. Idempotenz bedeutet, dass eine Operation, egal wie oft sie verarbeitet wird, immer dasselbe Ergebnis zur Folge hat. Ein Beispiel dieses Prinzips könnte das Setzen einer Variablen im Programmcode sein. Hier gibt es etwa die Möglichkeit, dies über Setter oder eben relative Mutationen zu implementieren. Zum Beispiel setAge oder incrementAge. Die Operation person.setAge(14); kann beliebig oft nacheinander ausgeführt werden, das Ergebnis bleibt immer dasselbe, nämlich 14. Hingegen wäre person.incrementAge(1) nicht idempotent. Wird diese Methode unterschiedlich oft hintereinander ausgeführt, gibt es verschiedene Ergebnisse, nämlich nach jeder Ausführung ein Jahr mehr. Genau diese Eigenschaft der Idempotenz ist der Schlüssel, um eine Exactly-once-Semantik zu etablieren. Angewandt auf die Systeme von zuvor bedeutet das, dass eine At-least-once-Semantik mit der Eigenschaft der Idempotenz zu einer Exactly-once-Verarbeitung führen kann. Wie eine At-least-once-Semantik umgesetzt werden kann, zeigt das zuvor beschriebene Bestätigungssystem. Was fehlt, ist also ein System von Idempotenz in der Verarbeitung. Aber wie kann eine Verarbeitung von Nachrichten idempotent gemacht werden? Um das zu erreichen, muss der Consumer die Möglichkeit haben, einen lokalen, synchronisierten Zustand zu erhalten. Um den Zustand einer Nachricht zu erhalten, muss diese eindeutig identifizierbar sein. Nur so werden das Aufsuchen und eine Deduplizierung der Nachricht ermöglicht. Abb. 6: Eine idempotente Verarbeitung Anders als zuvor speichert der Consumer mit jedem Aufruf in Schritt 4 der Abbildung 6 die Nachricht zunächst in einer lokalen Zustandshaltung. An dieser Stelle kann, sofern die Nachricht bereits lokal vorhanden ist, ein erneutes Speichern vernachlässigt werden. In Schritt 5 wird die Nachricht bestätigt. Schlägt die Bestätigung fehl und wird die Nachricht folglich erneut übertragen, ist das kein Problem, da in Schritt 4 das erneute Speichern der Nachricht verhindert werden kann. An dieser Stelle lebt also die Idempotenz. Beim Bearbeiten kann der Consumer nun selbst entscheiden, ob eine Verarbeitung notwendig ist, z. B. indem zu einer Nachricht ein Status eingeführt und dieser in Schritt 6 lokal abgefragt wird. Steht dieser bereits auf Processed, muss nichts getan werden. Umgekehrt muss eine verarbeitete Nachricht den Status korrekt aktualisieren. .nl-in-blog {background: url(https://jax.de/wp-content/uploads/2024/02/JAX24_Blog_Textblock.jpg); background-size:cover; color:#ffffff;} .wp-nl-header .col-xl-12.col-lg-12.col-md-12.nlform{height: 100px; background-color: #f2f2f2; border-radius: 25px 25px 25px 25px; padding: 0px 2px;} .body .mc4wp-form-fields input {border-radius: 25px !important;} .wp-nl-header input.custom-primary-button.gdlr-button.dark-button{padding: 6px 40px !important; height: 70% !important; border-radius: 25px 25px 25px 25px !important; align-self: center;} Stay tuned Regelmäßig News zur Konferenz und der Java-Community erhalten (function() { window.mc4wp = window.mc4wp || { listeners: [], forms: { on: function(evt, cb) { window.mc4wp.listeners.push( { event : evt, callback: cb } ); } } } })(); Leave this field empty if you're human: Fazit Verteilte Systeme haben ein grundsätzliches Problem, eine Exactly-once-Semantik herzustellen. Es kann auf Infrastrukturebene entweder zwischen at least once oder at most once gewählt werden. Erst durch die Eigenschaft der Idempotenz kann auf dem Applikationslevel sichergestellt werden, dass Nachrichten genau einmal von Ende zu Ende verarbeitet werden. Natürlich ist das nicht kostenlos. Es bedeutet, dass die Applikation selbst eine Verwaltung von Nachrichten übernehmen muss und deren Zustand verwaltet – wirklich exactly once ist das natürlich auch nicht, es kommt diesem durch die Eigenschaft der Idempotenz jedoch im Ergebnis sehr nahe. The post Exactly Once in verteilten Systemen: Realität oder Utopie? appeared first on JAX.

zum Artikel gehen

Veranstaltung: Mit .NET Aspire: Verteilte Anwendungen entwickeln

In der modernen Softwareentwicklung ist die Fhigkeit, verteilte Anwendungen zu entwickeln, ein entscheidender Erfolgsfaktor. In dieser Session tauchen wir tief in die Mglichkeiten ein, die .NET Aspire bietet, um robuste, skalierbare und performante vertei

zum Artikel gehen

Niklas Luhmanns Systemtheorie

Niklas Luhmann war ein deutscher Soziologe, der vor allem durch seine Arbeiten zur Systemtheorie bekannt geworden ist. Seine Systemtheorie ist eine interdisziplin re Theorie, die sich mit dem Verst ndnis von sozialen Systemen befasst. Luhmann unterscheide

zum Artikel gehen

Application Designer: Veröffentlichungsstrategien

Dieser Beitrag stellt eine Anleitung für die zeitsparende Umsetzung von kleineren Modellanpassungen zur Verfügung: mit dem Application Designer von Bissantz werden Routinetätigkeiten vereinfacht und auch bei Änderungen auf verteilten Systemen im Kundenumf

zum Artikel gehen

Altersarmut in der Rente: Panikmache oder Realität?

Ist Altersarmut in Deutschland Realität oder Panikmache? Wird die gesetzliche Rente im Ruhestand ausreichen? Mit welchen Maßnahmen kann ich gegensteuern?

zum Artikel gehen

Meinung zum Russland-Afrika-Gipfel: Die Kluft zwischen Ankündigungen und Realität ist abgrundtief

Vom 26. bis 29. Juli werden sich afrikanische und russische Entscheidungsträger in Sotschi am Schwarzen Meer zum zweiten Russland-Afrika-Wirtschafts- und Humanitären Forum treffen. Ein großes diplomatisches Treffen für ein Russland, das es gewohnt ist, zw

zum Artikel gehen