URL dieses Artikels:

zu Ausgabe: 6.2003
Erfolgskontrolle
Asynchrone Web Services
von Dave Chappell
Mit Web Services ist ein neues Konzept für die Architektur von Enterprise-Infrastrukturen entstanden, mit dem das Ziel einer auf Standards basierenden Integration in greifbare Nähe rückt. Eine Reihe neuer, universell vereinbarter Standards steht zur Verfügung, mit denen die Lücken zwischen plattformspezifischen Insellösungen geschlossen werden können. Damit sich dieses Konzept in Unternehmen durchsetzt, ist ein lose gekoppeltes, zuverlässiges und asynchrones Modell für Web Services erforderlich. In diesem Artikel werden wir uns mit der Frage beschäftigen, wie vorhandene Standards mit realen Implementierungen zusammengefügt werden können, um dieser Forderung gerecht zu werden.

Asynchron oder synchron?
Synchrones RPC (Remote Procedure Call) bietet den Vorteil, dass man sofort weiß, ob eine Operation erfolgreich war. Wenn sich eine synchrone Operation jedoch über mehrere Prozesse erstreckt, heißt es Alles oder Nichts. Wenn nämlich einer der Prozesse nicht verfügbar ist, muss die Applikation, von der die Anforderung ausgeht, diesen Ausfall in irgendeiner Weise registrieren, um es später nochmals zu probieren oder auch drastischere Maßnahmen zu ergreifen - ähnlich, wie einem Menschen mitgeteilt wird, dass er einfach kein Glück hat. Ein weiteres Problem ist die Anzahl der Applikationen und Services, die miteinander kommunizieren müssen. Angenommen, es handelt sich dabei um nahezu 100 Applikationen und Services, die jeweils zu 99 Prozent verfügbar sind, so bedeutet dies gleichzeitig, dass sie für ein Prozent der Zeit nicht verfügbar sind. Es ist einfach, sich auszumalen, welche Auswirkungen dies hat.

Lose gekoppelte Interaktionen
Demgegenüber kann bei der asynchronen Nachrichtenübermittlung jeder Kommunikationsvorgang zwischen zwei Prozessen eine getrennte, in sich abgeschlossene Angelegenheit sein. Bei einer Kommunikation, die sich über mehrere Prozesse erstreckt, kann jedes Zwischenglied völlig selbstständig mit seinem jeweiligen Sender und Empfänger kommunizieren. Der Prozess, von dem die ursprüngliche Anforderung ausgeht, muss sich nur um die Initiierung des Aufrufs kümmern - in der Erwartung, letzten Endes auf asynchronem Wege eine Antwort zu erhalten. Bei einer komplexen Interaktion, die sich über mehrere Prozesse und Services erstreckt, gelangt die Antwort möglicherweise niemals zum ursprünglich Anfordernden. Jede Antwort kann die Form einer neu generierten Nachricht annehmen, die an eine Weiterleitungsadresse geschickt wird. Dabei können mehrere Weiterleitungsadressen miteinander verknüpft werden, um so einen Transportweg festzulegen. Ein weiterer Vorteil der asynchronen Verarbeitung besteht darin, dass wichtige Ausfälle über ein administratives Alarmsystem zentral gemeldet werden, von wo aus entsprechende Nachrichten versandt werden.

Lose gekoppelte Schnittstellen
Asynchrone nachrichtenbasierte Interaktionen erfordern gewöhnlich Schnittstellen, die sehr lose gekoppelt sind. In einer Umgebung, in der mehrere Applikationen und Services in Interaktion treten, ist es nicht sinnvoll, dass jede Applikation alle Details der Methodenaufrufe und Parameter der anderen Applikation kennt. In einer Umgebung mit eng gekoppelten Schnittstellen wird die Anzahl der Schnittstellen, die aufgebaut und gepflegt werden müssen, sehr schnell unübersichtlich. Mit steigender Zahl der Applikationen und Services wächst schließlich auch die Zahl der Schnittstellen; die entsprechende Formel lautet: n(n - 1)/2. Dies bedeutet, dass bei fünf Applikationen bzw. Services zehn Schnittstellen erforderlich sind - auf den ersten Blick kein schlechter Wert. Hat man jedoch 100 Applikationen bzw. Services, so steigt die Anzahl der benötigten Schnittstellen bereits auf beträchtliche 4.950 an. Diese Zahl ist in Wirklichkeit jedoch eher zu niedrig angesetzt, da man voraussetzt, dass jedem Applikationsendpunkt nur eine Schnittstelle zugeordnet ist. In der Praxis können dies weitaus mehr sein.


Deshalb ist es sinnvoller, wenn eine asynchrone Nachricht eine autonome Einheit ist, die die Daten und den entsprechenden Kontext mit sich führt, sodass jeder Knoten, der die Nachricht verarbeitet, dafür verantwortlich ist, den Inhalt der Nachricht zu durchleuchten, um die jeweils benötigten Daten zu erhalten und zu entscheiden, was als nächstes zu tun ist.

Zuverlässigkeit der asynchronen Verarbeitung
Die asynchrone Verarbeitung macht es jedoch auch erforderlich, für Zuverlässigkeit zu sorgen. In der Welt der Web Services kann dies auf mehreren Wegen erreicht werden.


Eine Möglichkeit, mit der die asynchrone Zuverlässigkeit zwischen Web Services sichergestellt werden kann, besteht darin, auf der SOAP-Ebene ein zuverlässiges Protokoll einzusetzen. Bei diesem Ansatz werden Nachrichten- und Empfangsbestätigungen in vordefinierten SOAP-Envelope-Header-Konstrukten kodiert. Aktuelle Beispiele hierfür sind WS-ReliableMessaging von Microsoft/IBM/Bea und WS-Reliability von OASIS.

Java Message Service
Der Java Message Service (JMS) verfügt über semantische Funktionen für die Bildung von Message Destinations (Queues oder Topics) und für die garantierte Zustellung von Nachrichten. Damit wird sichergestellt, dass Daten, die an unverfügbare Applikationen gerichtet sind, in eine Warteschlange gestellt und zu einem späteren Zeitpunkt zugestellt werden. Erreicht wird dies über ein strenges Regelwerk für die Aufbewahrung und Bestätigung von Nachrichten, welches in der JMS Spezifikation über Anforderungen definiert wird. Abbildung 1 zeigt die Schritte der Aufbewahrung und Bestätigung von Nachrichten beim Kommunikationsverhalten eines Subscribers, der bei seiner Kommunikation die Rolle eines durable Subscribers übernimmt. Alle Nachrichten müssen diesem Subscriber zugestellt werden, auch wenn die Verbindung zeitweise nicht besteht. Dabei könnte die Trennung und der Wiederaufbau der Verbindung beispielsweise durch den Ausfall und die Wiederherstellung einer empfangenden Applikation bzw. eines empfangenden Services verursacht werden. Ein ähnliches Modell gibt es auch für Point-to-Point-Messaging unter Benutzung von Queues. Mit JMS werden XML-Daten bereits seit einigen Jahren asynchron und zuverlässig zwischen Applikationen transportiert.


Abb. 1: Asynchroner und zuverlässiger Transport von SOAP- und XML-Daten über JMS.

Enterprise Connectivity
Einige Lösungen von JMS-Anbietern können über die Grenzen von Firewalls hinaus erweitert werden, indem eine Art von HTTP-Tunnel genutzt wird. Bei JMS wird die Interoperabilität jedoch nicht auf der Ebene des Wire-Protokolls definiert. Um JMS für die Kommunikation zwischen geografisch verteilten Standorten, d.h. über das Internet, zu nutzen, muss daher an jedem entfernten Standort ein Teil der Software des jeweiligen JMS-Anbieters installiert sein. Dies ist eine perfekt funktionierende Lösung, wenn man wirklich eine so umfangreiche Kontrolle über alle entfernten Knoten hat, mit denen man kommunizieren will.


Unterschiedliche Arten von Geschäftsbeziehungen erfordern jedoch auch unterschiedliche Herangehensweisen in punkto Connectivity. Bei einigen Geschäftspartnern, mit denen man Fernkommunikation betreiben will, handelt es sich möglicherweise um Kunden oder Unternehmen, mit denen man nur gelegentlich zu tun hat. Dabei kann man einem Geschäftspartner unmöglich vorschreiben, eine bestimmte Software zu installieren, damit er hin und wieder einmal einen Auftrag elektronisch verschicken kann. Wie in Abbildung 2 dargestellt, lässt sich dieses Problem besser mit dem HTTP-Protokoll lösen.


Abb. 2. Geografisch verteilte Connectivity. Das jeweils geeignete Protokoll hängt von der Art der Geschäftsbeziehung und dem Umfang der Kontrolle über entfernte Standorte ab.

SOAP-über-HTTP, SOAP-über-JMS
Die eindeutig beste Lösung ist eine Implementierung von Web Services, die weitgehend auf Messaging basiert und die Möglichkeit bietet, SOAP-über-HTTP durch SOAP-über-JMS zu erweitern bzw. zu verfeinern. Um diese beiden Welten miteinander zu verbinden, wird eine Architektur benötigt, die einen einheitlichen Satz von SOAP-Envelope-Schnittstellen zur Verfügung stellt und die es erlaubt, die Details der Transportprotokolle in Form einer Deployment-Option zu abstrahieren. Dabei müssen zwei wesentliche Anforderungen erfüllt werden:
  • Ein nahtloses bidirektionales Mapping zwischen dem HTTP-Protokoll bzw. dem JMS Topic und den Zieladressen der Warteschlange.
  • Eine JMS-Client-API mit Erweiterungen, die es ermöglichen, die Nachrichteninhalte mithilfe gängiger SOAP-Envelope-APIs - wie Apache SOAP-, Apache Axis-, oder JAX-RPC-APIs - zusammenzufügen und auseinanderzunehmen.

Lücken zwischen den Protokollen schließen
Um das bidirektionale Mapping zwischen SOAP-über-HTTP und SOAP-über-JMS zu erreichen, wird die Idee eines Mapping-Layers eingeführt. Wer mit dem J2EE-Webcontainer-Konzept vertraut ist, würde dieses Mapping konzeptionell auf der Ebene der Servlet/JSP-Container realisieren (vgl. Abb. 3). Bei .NET-Umgebungen hingegen würde dies konzeptionell auf der IIS/ASP-Ebene umgesetzt werden. Das Wort konzeptionell wird verwendet, da man diese Schicht auf der Programmierebene tatsächlich niemals sehen würde. In der Implementierung eines Anbieters sollte sie versteckt realisiert und administrativ konfiguriert werden.


Abb. 3: Ein SOAP Protocol Handler schließt die Lücken zwischen SOAP-über-HTTP und SOAP-über-JMS


Dies ist logischerweise die Stelle, an der WS-Reliability und WS-ReliableMessaging im Laufe der Zeit eingeführt werden sollen.


Obwohl der Java Message Service in erster Linie für die asynchrone Verarbeitung gedacht ist, verfügt er auch über ein eingebautes Request-Reply-Modell, das bei Bedarf genutzt werden kann. Hierzu generiert der Sender eine Zieladresse, die für die Response-Message verwendet wird, bettet diese Zieladresse in die Request-Message ein und wartet anschließend, bis an dieser Zieladresse die Antwort eintrifft. Diese Adresse wird als replyTo-Zieladresse bezeichnet. Darüber hinaus enthält der Java Message Service sowohl ein synchrones als auch ein asynchrones Request-Reply-Modell. Bei der synchronen Variante blockiert der Sender und wartet, bis er eine Antwort erhält. Im asynchronen Modell verwenden sowohl der Sender als auch der Antwortende eine Zuordnungs-ID, die in die Reponse-Message eingebettet ist, um eine asynchrone Antwort einer Nachricht zuzuordnen, die zu einem früheren Zeitpunkt verschickt wurde.


Dabei ist es nicht zwingend erforderlich, dass es sich bei der replyTo-Adresse unbedingt um den ursprünglichen Anfordernden handeln muss. Vielmehr könnte dies auch einfach eine Weiterleitungsadresse sein. Auf diese Weise können Message-Aufrufe miteinander verknüpft werden, um eine Transportroute festzulegen, die auf dem Weg von einem Prozess zum nächsten zusammen mit der Nachricht mitgeführt wird.

Zustellung zur Zieladresse
Wenn eine eingehende SOAP-über-HTTP-Nachricht auf der Protocol Handler-Ebene ankommt, gibt es mehrere Möglichkeiten, mit denen festgelegt werden kann, an welches JMS-Topic oder an welche JMS-Queue die SOAP-Nachricht geschickt werden soll:
  • Definition durch WSDL-Erweiterungen.
  • SOAPAction oder andere im HTTP-Header definierte Elemente.
  • SOAP-Header. Der Versandmechanismus analysiert möglicherweise das
    -Element.
  • Content-basiertes Routing. Alle Nachrichten für einen bestimmten HTTP-Adressaten können in unverändertem Zustand in eine Queue gestellt werden, von der aus die Nachrichten an einen Content-basierenden Routingdienst weitergeleitet werden, der mithilfe von XPath-Ausdrücken oder durch direkte Analyse der SOAP-Envelope-Elemente
    und festlegt, wohin die Nachricht als nächstes zu schicken ist.

Auch der Umfang der erforderlichen Konvertierung kann unterschiedlich sein. So kann die Protokollkonvertierungsschicht den gesamten SOAP Envelope unverändert in eine JMS TextMessage oder BytesMessage einfügen. Hierbei muss der Empfänger der Nachricht in der Lage sein, SOAP-Envelope-Konstrukte zu durchsuchen und zu verstehen. Alternativ können auf der Protokollkonvertierungsschicht einige Konvertierungen vorgenommen werden. Dabei können beispielsweise die Inhalte der HTTP-Header oder die SOAP Header in Header-Felder der JMS-Nachricht eingefügt werden, wobei das SOAP-Element <Body> den Rumpf der erzeugten JMS-Nachricht ausmacht. Im Extremfall wird der SOAP-Envelope komplett in eine einfache JMS-Nachricht umgewandelt, sodass der für die Antwort zuständige JMS-Reply-Client nichts über SOAP wissen muss.

Der JMS-SOAP Replier
Der Replier verwendet eine Kombination von JMS-APIs und SOAP-Envelope-APIs. Die SOAP-Envelope-APIs könnten dabei auf Apache SOAP, Apache Axis, JAX-RPC oder einer anderen API basieren. In diesem Beispiel wird davon ausgegangen, dass ein spezieller JMS-Message-Typ vorhanden ist, der die JMS-APIs mit den Apache SOAP-APIs kombiniert. Listing 1 zeigt, wie dies aussieht:



Listing 1

public void onMessage(javax.jms.Message aMessage)
{
if (aMessage instanceof JMSSoapMessage){
JMSSoapMessage sMsg = (JMSSoapMessage)aMessage;

org.w3c.dom.Document doc = sMsg.getDocument();

org.apache.soap.Envelope msgEnv = org.apache.soap.Envelope.unmarshall doc.getDocumentElement());

//... Do SOAP Envelope things.... get the <Header>...
org.apache.soap.Header header = msgEnv.getHeader();
java.util.Vector headerEntries = header.getHeaderEntries();

// Look into the SOAP envelop header and get some
// destination information
for (java.util.Enumeration e = headerEntries.elements();
e.hasMoreElements();)
{
org.w3c.dom.Element el = (org.w3c.dom.Element)e.nextElement();
String tagName = el.getTagName();
if(tagName.equalsIgnoreCase("ns1:From"))
System.out.println(Found the <From> address!);
else if(tagName.equalsIgnoreCase("ns1:To"))
System.out.println(Found the <To> address!);
}

// Use JMS API to check for a ReplyTo Destination and send
// one if necessary
javax.jms.Queue replyQueue =
(javax.jms.Queue) aMessage.getJMSReplyTo();

if (replyQueue != null){
// create reply message and send it.
}else{
// create a new SOAP message to go to
// another destination
String urlEndpoint =
sMsg.getNextURLEndpoint();
...
}
}
}

Die J2EE Connector Architektur
Durch die J2EE Connector Architecture (JCA) wird ein Component/Container-Vertrag zwischen einer Applikation und einem JCA-Container geschlossen. Der JCA-Container kann entweder zu einem Applikationsserver oder zu einem EAI-Framework gehören. Vereinfachend gesprochen stellt die JCA für Applikationen das bereit, was JDBC für Datenbanken bereitstellt. Eine EIS-Applikation (Enterprise Information System) implementiert den Component-Anteil der JCA-Spezifikation, indem ein JCA-konformer Ressourcenadapter implementiert wird, der in den JCA-Container eingebettet werden kann. Das EIS tritt als Provider im Sinne der JCA-Spezifikation auf. Die mit der JCA-Architektur verfolgte Absicht besteht darin, dass Applikationsanbieter wie SAP oder PeopleSoft ihre eigenen Ressourcenadapter bereitstellen werden, sodass kostspielige Adapter von Fremdanbietern überflüssig werden.

Brücken bauen: J2EE,.NET, Legacy
Wie in Abbildung 4 dargestellt können Remote-Clients durch JAX-RPC, Apache SOAP, Axis oder .NET implementiert werden. Diese Clients sind dann in der Lage, SOAP-Nachrichten mithilfe von HTTP über das Internet zu verschicken und zu empfangen. Die Protokollkonvertierungsebene verbindet SOAP-Nachrichten mit dem JMS Enterprise Message Bus. Mit JCA wird die Verbindung zu EIS-Applikationen bzw. Legacy-Applikationen hergestellt. JCA und MessageDrivenBeans werden darüber hinaus bei Bedarf verwendet, um die Kommunikation mit einem EJB-Server herzustellen.


Abb. 4: Schließen der Kluft zwischen Applikationen auf Basis von J2EE und .NET sowie Legacy-Applikationen

Endpunkte von Web Services werden völlig abstrakt
Wie ebenfalls aus Abbildung 4 zu entnehmen ist, sind die Interaktionen zwischen den Enterprise-Clients und den externen Internet-Clients birektional. Die externen SOAP-Clients können selbst Endpunkte von Web Services sein, die über eine ausgehende HTTP-Anforderung aufgerufen werden können. Ob es sich bei den Endpunkten um externe Aufrufe über HTTP, Reliable SOAP (WS-Rel*) oder interne Zieladressen handelt, die über JMS-Zieladressen ausfindig gemacht werden, ist lediglich eine Frage der Implementierung.


Eine umfangreiche Implementierung von Web Services, die sich über mehrere Applikationen und Services erstreckt, erfordert eine zuverlässige asynchrone Kommunikation. Die Mittel, die für die Implementierung großer, asynchroner und zuverlässiger serviceorientierter Architekturen erforderlich sind, stehen bereits heute zur Verfügung; wichtig ist die richtige Kombination von Technologien, die auf Standards basieren.

© 2004 Software & Support Verlag GmbH. Vervielfältigung nur mit Genehmigung des Verlags. Fragen?