Blog

Wie erstellt man zustandslose Anwendungen mit Containerisierung?

CoMakeIT

CoMakeIT

Aktualisiert Oktober 21, 2025
5 Minuten

Ich gehöre zu einem Team, das vor kurzem eine containerisierte zustandslose Anwendung implementiert hat, und ich dachte, es wäre gut, unsere Erkenntnisse zu teilen, die für andere nützlich sein könnten.

Unser Produkt basiert auf Event Sourcing und CQRS (Command Query Responsibility Segregation) mit Nanodiensten. Da unser Produkt eine komplexe Domäne behandelt, haben wir uns für Event Sourcing und CQRS entschieden. Nicht alle Produkte/Anwendungen sind so komplex, in solchen Fällen ist einfaches Spring Boot mit MongoDB oder PostgreSQL mehr als ausreichend.

In diesem Beitrag geht es nicht um Event Sourcing und CQRS, was an sich schon ein großes Thema ist.. Es geht eher darum, wie man in der realen Welt zustandslose Anwendungen und horizontale Skalierbarkeit schafft. und Probleme, die bei der Ausführung mehrerer Instanzen der Anwendung/des Produkts berücksichtigt werden müssen. Eine sorgfältige Prüfung der gleichzeitigen Verarbeitung ist erforderlich, um sie wirklich zustandslos zu machen. Einige davon mögen in einer einzelnen Instanz hervorragend funktionieren, aber sobald Sie sie in einem Cluster einsetzen, können sie sich seltsam verhalten, wenn Sie die gleichzeitige Ausführung der Prozesse nicht sorgfältig berücksichtigen.

Hier werde ich einige der Probleme aufzeigen, auf die man bei der Erstellung eines Anwendungs-Clusters stoßen kann, und einen Einblick in die Richtung geben, ohne zu sehr in die Details der Implementierung zu gehen.

Hier ist unsere Factory Generation, mit der Sie zustandslose Anwendungen von Grund auf neu starten können

Verwenden Sie separate Stacks und Bereitstellungen für Front-End- und Back-End-Logik

  • Ein Beispiel für ein Frontend könnte Nodejs mit Angular/Typescript/React/Vue sein, wo Sie die Dateien in einer einzigen Zip-Datei bündeln und einen statischen Server für die Bereitstellung der Dateien verwenden können.
  • Für das Backend verwenden wir hauptsächlich Java (basierend auf den Anforderungen und der Komplexität der Anwendung und der zukünftigen Wartung des Produkts) mit einem schönen Framework zur Verwaltung von Abhängigkeiten wie Spring Boot.

Nehmen wir an, unsere Beispielanwendung verwendet Spring Boot und hat einen externen Connector, der Nachrichtenwarteschlangen verwendet. Auf welche Probleme könnte man stoßen, wenn man versucht, die Anwendung zustandslos zu machen und sie auf mehreren Knoten laufen zu lassen (Clustering)?

Stellen Sie sicher, dass diese Backend-Anwendung zustandslos ist. Wenn nur ein minimaler Zustand beibehalten werden muss, verwenden Sie JWT (JSON Web Token).

Das Endziel der zustandslosen Anwendung ist die Ausführung mehrerer Instanzen zur horizontalen Skalierung (unter Verwendung von Containern wie Kubernetes). Es mag einfach erscheinen, eine Anwendung zustandslos zu machen, aber in Wirklichkeit ist es ein wenig knifflig und Sie müssen die gleichzeitige Verarbeitung berücksichtigen, wenn die Anwendung auf mehr als einem Knoten gestartet wird.

Probleme mit der Benutzeroberfläche von geclusterten Anwendungen:

Angenommen, mehrere Benutzer arbeiten an demselben Datensatz und versuchen, ihn gleichzeitig zu aktualisieren. Wenn wir die Datenbankdaten einfach mit den neuesten Daten überschreiben, könnten die Aktualisierungen einiger Benutzer verloren gehen. Denn ihre Änderungen wurden von anderen Benutzern überschrieben, ohne dass diese die Änderungen überhaupt überprüft haben. In einer einzelnen Instanz, in der Änderungen an dieser bestimmten Instanz an den entsprechenden Agenten weitergeleitet werden, lässt sich dies leicht lösen, aber in einer Cluster-Umgebung wird es etwas knifflig. Der einfachere Ansatz zur Lösung dieses Problems ist die Verwendung von Versions- oder Instant-Feldern. Wenn gleichzeitige Aktualisierungen stattfinden, wird nur eine erfolgreich sein und die andere wird fehlschlagen, da der Datensatz von einem anderen Benutzer aktualisiert wurde. Es ist ein einfaches CAS (Compare and Swap), das auf dem Versionsfeld basiert.

Dies ist eine ziemlich gute Lösung, wenn solche gleichzeitigen Aktualisierungen derselben Datensätze sehr selten sind. Wenn das Konkurrenzverhältnis bei der Aktualisierung desselben Datensatzes größer ist, besteht der andere Ansatz darin, eine Art von Pipes (wie Apache Kafka Topic Partitions) auf der Grundlage des Datensatzschlüssels zu implementieren und die REST-Endpunkte leiten die Anfragen einfach an sie weiter. Das ist ähnlich wie bei Akka-Akteuren, aber für die meisten Anwendungen ist das nicht erforderlich. Das Versionsfeld könnte ausreichend sein.

Cluster-Anwendung einzelne Instanz nur Teilprozesse:

Ein weiteres Problem, mit dem eine Anwendung konfrontiert sein könnte, ist, dass, wenn Ihre Anwendung auf eine Art Nachrichtenbus (Rabbit MQ, AMQP usw.) hört, um mit einem externen System zu kommunizieren, die Nachricht vom Bus nur von einem Knoten gleichzeitig konsumiert werden kann. Wenn Sie den Prozess parallelisieren möchten, müssen Sie sich wirklich mit den Nachrichtentypen befassen und die unabhängigen Nachrichtentypen finden, und für jeden unabhängigen Abschnitt können Sie einen Konsumentenknoten haben.

Wenn Sie nur eine Instanz der Anwendung benötigen, um diese Logik in einem Cluster zu verarbeiten, wird es komplizierter zu entscheiden, welche Instanz als Master fungieren soll. Wenn Sie mehrere Unterprozesse haben, wird es noch komplizierter. Für jeden Unterprozess wird ein Master benötigt. Und was, wenn diese Instanz stirbt? Wie können Sie dann eine andere Instanz als Master für diese Logik einrichten? Ja, es wird ziemlich kompliziert.

Wir haben die Java-API von etcd verwendet und für jeden einzelnen Unterprozess (z. B. den Verbrauch von Nachrichten des Typs 1) haben wir Uhren entwickelt, die die Java-API von etcd verwenden, um sicherzustellen, dass alle Instanzen denselben Kampf für den Master für diese Logik austragen, und Sie wissen jetzt, wie Sie das erreichen können :)

Es gibt ein Problem: Wenn nur eine Instanz Master für alle Subprozesse wird, wird diese Instanz zum Engpass. Dies lässt sich mit kubernetes configMaps oder Umgebungsvariablen einfach lösen. Sie fassen die verschiedenen Subprozesse in einer Gruppe zusammen und entscheiden mit Hilfe der Umgebungsvariablen, ob diese Instanz an dem Master-Race der Subprozesse teilnehmen soll oder nicht. Auf diese Weise können Sie pro Knoten nur einen Subprozess-Master erreichen, was in jedem Fall eine ideale Skalierung darstellt.

Dies ist keine vollständige Anleitung zur Erstellung zustandsloser Anwendungen, sondern eine Einführung in die Probleme, die bei der Ausführung eines Clusters zustandsloser Anwendungen auftreten können.

Bleiben Sie dran für weitere Updates...

Verfasst von

CoMakeIT

coMakeIT, a software product engineering company. We accelerate product innovation, modernize aging applications, and productize best practices into new software IP.

Contact

Let’s discuss how we can support your journey.