Richtlinie: Zustandsmanagement für Services
In dieser Richtlinie werden Fragen im Zusammenhang mit der Verwendung zustandsabhängiger und zustandsunabhängiger Services erörtert, im Hinblick auf ihre Auswirkungen auf Leistung und Zuverlässigkeit sowie auf Interaktionen, die einen transaktionsorientierten Ansatz erfordern. In einer SOA-Umgebung wird das Zustandsmanagement auf drei Hauptkategorien angewendet, den Transaktionszustand, den Sicherheitszustand und den funktionalen Zustand.
Beziehungen
Zugehörige Elemente
Hauptbeschreibung

Einführung

Der Begriff zustandsabhängiger und zustandsunabhängiger Komponenten ist besonders wichtig bei der Entwicklung verteilter Anwendungen und Systeme, obwohl er erst seit kurzer Zeit Teil des allgemeinen Vokabulars ist. Im Wesentlichen gilt Folgendes: Wenn zwei Komponenten oder Services miteinander kommunizieren und die Serverkomponente für die Dauer der Kommunikation mit dem Client ein Zustandsmanagement durchführt, besteht das Risiko, dass die Serverkomponente (oder das Netz) ausfällt, so dass der Client seinen Arbeitsvorgang nicht abschließen kann neu beginnen muss. Dadurch wird auch das Umleiten von Clientanfragen an eine Komponente aus einer Komponentengruppe schwerer, es sei denn, die Komponentengruppe nutzt einen gemeinsamen Speicher für den Kommunikationszustand. Das ist ein bekanntes Problem bei der Entwicklung von Webanwendungen, das man durch ein sorgfältiges Zustandsmanagement möglichst zu vermeiden sucht. Das Management erfolgt über den Client, die Kommunikation selbst (Übergabe des Zustands in jeder einzelnen Nachricht) oder sorgfältig konzipierte zustandsabhängige serverseitige Komponenten. Ein allgemein gebräuchliches Beispiel für die zustandsabhängige Webinteraktion ist der Einkaufswagen. Die Erwartungshaltung der Benutzer ist, dass der Einkaufswagen bestehen bleibt, wenn sie sich kurzzeitig vom Computer entfernen. Wie ist das jedoch mit 100.000 parallelen Benutzern zu bewerkstelligen?

Das bedeutet nicht, dass zustandsabhängige Komponenten an sich schlecht sind, sie stellen lediglich einen Bereich dar, in dem Leistungs- und Verfügbarkeitsausfälle auftreten können, wenn sie nicht sorgfältig verwaltet und nach strengeren Standards entwickelt werden. Tatsächlich enthalten alle Anwendungen Services, die Entitäten verwalten bzw. darstellen, die per se zustandsabhängig sind oder wiederum Services enthalten, auf die über bestimmte logische Sequenzen zugegriffen werden muss. Die J2EE-Architektur definiert separate zustandsunabhängige und zustandsabhängige Session-Beans, um diese Probleme explizit zu bezeichnen, und definiert bestimmte Einschränkungen für zustandsabhängige Komponenten. Das führt zu einer einfachen Klassifikation für zustandsabhängige Services und insbesondere zu den Gründen, aus denen sie nicht vermieden werden können. Ein Service kann aus einem der folgenden Gründe zustandsabhängig sein:

Der Service hält den Zustand für den Client, siehe Beispiel mit Einkaufswagen. Bestimmte Daten müssen bei Aufrufen zwischen Client und Service persistent gespeichert werden, da sie Teil der Kommunikation sind. Es kann also leicht geschehen, dass ein Client an eine bestimmte Serverressource gebunden wird.

Der Service verwaltet eine zustandsabhängige Ressource. In diesem Fall verwaltet der Service oft eine Gruppe von Ressourcen oder Entitäten, von denen jede einen bestimmten Zustand hat. Beispiel hat ein Kundauftrag einen Zustand, ein Netzschalter hat einen Zustand usw. Daher ändert die Schnittstelle für einen Service, der dieses Objekt durch Schließen bzw. Verzögern eines Auftrags oder durch Neustart eines Schalters steuert, den Zustand einer bestimmten Entität.

Der Status hat ein zustandsabhängiges Protokoll. In diesem Fall hat der Service eine logische Ordnung der bereitgestellten Operationen. Beispielsweise hat der Service Operationen des Typs login(), dostuff() und logoff(), woraus man schließen kann, dass die Operationen des Typ dostuff() oder logoff() nur aufgerufen werden können, wenn die Operation login() aufgerufen wird.

Eine andere Form des Zustands, der in vielen Komponentenarchitekturen gefunden werden kann, jedoch nicht in der Welt der Services anwendbar ist, ist der Begriff des Transaktionszustands. In der Welt der Komponenten besteht die Möglichkeit anzugeben, dass eine Methode des Typs get() und eine Methode des Typs update() für eine Komponente von einem Client im Bereich einer vom Client erstellten und verwalteten Transaktion aufgerufen werden soll. Die Methode update() soll einen zugrunde liegenden Transaktionsspeicher ändern. Dazu muss die Middlewareplattform quasi die Transaktionen koordinieren und sicherstellen, dass Methoden, die Transaktionen erfordern, von einem Client mit einer offenen Transaktionen aufgerufen werden. Bei Services ist es nicht angemessen, einem Modell zu folgen, in dem Transaktionen im klassischen zweiphasigen Commit bei einer Reihe von Serviceaufrufen offen gehalten werden. Jetzt werden Standards für Transaktionen entwickelt, die über Serviceaufrufe hinausgehen, die jedoch einem grundsätzlich anderen Paradigma folgen (Kompensation) und von Middlewareplattformen auf andere Weise unterstützt werden.

Das offensichtlichste Verfahren, auf das oben hingewiesen wurde, besteht darin, den Servicezustand zu externalisieren und damit nicht nur deutlich zu machen, dass der Service einen Zustand hat, sondern dass dieser Zustand als Teil der Servicespezifikation identifiziert werden kann. Das wird für die zwei Klassen von statusabhängigen Services unten erläutert.

Da die meisten Softwareservices auf einer vorhandenen Middlewareplattform wie J2EE oder Microsoft .NET entwickelt werden, gibt es in diesen Plattformarchitekturen Implementierungsverfahren, die beim Zustandsmanagement helfen. Daher konzentriert sich diese Richtlinie für bestimmte Klassen zustandsabhängiger Services. Es sei darauf hingewiesen, dass das keinesfalls ein neuer Problembereich ist. In der Mainframe-Entwicklung war die Entwicklung von interaktiven und nicht interaktiven Transaktionen in CICS-Clients (IBM Customer Information Control System) mit grüner Anzeige (Terminal des Typs IBM 3270) bekannt und wurde von Entwicklern, Designern und Architekten über viele Jahre hinweg beschrieben.

Persistenter Kommunikationsstatus

Das ist ein Fall, in dem der einfachste Rat darin besteht, die Situation möglichst zu vermeiden. Wenn ein Design während der Kommunikation zwischen einem Service und seinen Konsumenten das Zustandsmanagement aufruft, wäre es am besten, den Versuch zu unternehmen, festzustellen, ob ein anderer Ansatz ausgewählt werden kann. Wenn nicht, sollten Sie diesen Zustand externalisieren, indem sie alle erforderlichen Zustandsdaten zwischen Service und Konsument mit allen Nachrichten, die die gesamte Kommunikation ausmachen, externalisieren. Dieser Ansatz kann bedeuten, dass die Nachrichtengröße deutlich zugenommen hat, der Service selbst jetzt allerdings vollkommen statusunabhängig ist. Ein anderer Ansatz besteht darin, in jeder Nachricht eine Kommunikationskennung zu übertragen und alle Kommunikationszustände in einem permanenten Speicher, z. B. einer Datenbank, persistent zu speichern. Diese Vorgehensweise hat zwar erhebliche Auswirkungen auf das serverseitige Leistungsverhalten, ermöglicht wegen der kleineren Nachrichten jedoch Einsparungen bei der Netz- und Clientleistung.

Diese Services statusunabhängig zu gestalten, hat primär den Sinn, eine Gruppe identischer Services bereitzustellen, die alle Anfragen mit Lastverteilungsverfahren bedienen kann, um Clients zu verteilen. Diese Lastverteilung ist möglich, wenn alle Zustände vollständig externalisiert oder in einem allgemeinen Speicher persistent gespeichert sind.

Statusabhängige Ressourcen verwalten

In diesem Fall wird das Management von Ressourcen selbst untersucht, die einen expliziten Zustand haben. Tatsächlich ist dieser Status ein wichtiger Aspekt der Ressource selbst. Möglicherweise können der Zustand der Ressource, der Kundenauftrag oder der oben erwähnte Netzschalter mit einer Zustandsmaschine beschrieben werden. Dabei werden nicht nur die gültigen Zustände beschrieben, sondern es wird auch erläutert, wie die vom Service bereitgestellten Operationen den Zustand der zugrunde liegenden Ressource(n) beeinflussen.

Wie auch immer diese Beschreibung fertig gestellt wird, es muss festgehalten werden, dass dieser Zustand einen wesentlich Teil der Ressource darstellt. Möglicherweise ist er im Informationsmodell, von dem er repräsentiert wird, nicht explizit ausgedrückt. Es muss auch festgehalten werden, dass man dort, wo Entitätengruppen aller Art verwaltet werden, in der Lage sein muss, alle einzelnen Ressourcen, für die wir agieren, zu identifizieren, unabhängig davon, ob diese eine explizite Kennung haben.

Beachten Sie, dass dort, wo ein Service den Zugriff auf den Zustand bzw. die Abfrage des Zustands einer physischen Entität, wie z. B. eines Netzschalters oder eines Prozesssteuerungselements repräsentiert, keine Möglichkeit besteht, den Zustand der Entität zu externalisieren. Der Zustand eines Ventils kann nur durch Abfrage des Ventils festgestellt werden. Es ist zwar möglich, Konstruktionsvorgänge auszuführen und mit einer Nachricht zu antworten, die den aktuellen Zustand des Ventils beschreibt, aber das ist nicht permanent so. Der Zustand des Ventils kann sich während der Übertragung oder Verarbeitung dieser Nachricht ändern.

Im Bereich der Web-Services gibt es eine Gruppe neuer Standards, die als Web Services Resource Framework (WSRF) bezeichnet werden und Muster zustandsabhängiger Services und Ansätze für die Zustandscodierung erläutern, insbesondere im Falle von Services, die das Management zustandsabhängiger Ressourcen repräsentieren. Weitere Informationen finden Sie auf der Website von IBM WS-ResourceFramework.

Statusabhängige Servicespezifikationen

Das oben genannte Beispiel beinhaltet einen Service, der die Operationen, die er bereitstellt, logisch sortiert. Viele Services stellen Schnittstellen dieser Form bereit. In einigen Fällen bezieht sich das auf zustandsabhängige Ressourcen, nur dass dann die Sortierung der Operationen ausgehend vom Zustand der verwalteten Ressource erfolgt. In diesem Fall basiert die Sortierung auf der Kommunikation selbst. Das folgende Beispiel veranschaulicht eine Servicespezifikation, die ein zugeordnetes Protokoll hat. Zuerst wird die Strukturspezifikation und dann eine Zustandsmaschine gezeigt, die die Verhaltensspezifikation beschreibt.

Im Kontext beschriebene Abbildung

Die Bestellung (PurchaseOrder) kann einen der Zustände {Offen, Storniert, Ausgeführt, Ende} haben und ändert seinen Zustand basierend auf der obigen Spezifikation. Im Falle des Übergangs in den Status "Offen" wird die Operation "Bestellung geändert" ausgeführt, die Benachrichtigungen über die Änderung sendet.

Im Kontext beschriebene Abbildung

In vielen Fällen, in denen alle Services in einem einzigen technischen und Geschäftsbereich entwickelt werden, können keine detaillierten Spezifikationen entwickelt werden, oder sie werden weniger formal in Textform beschrieben. Wenn Services außerhalb eines solchen Bereichs, z. B. zwischen Partitionen, verfügbar gemacht werden, repräsentieren sie eine logische Spezifikation für die Interaktion zwischen Partitionen und sollten wesentlich detaillierter entwickelt werden. Außerdem ermöglichen detaillierte Spezifikationen eine effizientere und effektivere Wiederverwendung durch Konsumenten, wenn Services häufig wiederverwendet werden sollen.