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.
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.
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.
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.
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.
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.
|