RESTlos glücklich?

Herausgeber: Java Magazin

Ausgabe: Mai 2009

Autor: Mirko Novakovic

 

In letzter Zeit wird die Debatte, ob man für Web-Services-orientierte Anwendungen SOAP oder REST verwenden soll, zunehmend stärker. Mehr und mehr Stimmen behaupten, dass REST gegenüber SOAP zu bevorzugen sei. Der Konflikt entwickelt sich immer stärker zu einem Glaubenskrieg, bei dem die Fakten in den Hintergrund treten. Neben der Einfachheit wird oft auch die Effizienz als Grund für die Entwicklung von REST-basierten Services genannt. Alles in allem Grund genug, diese Frage auch einmal aus Performancesicht zu beleuchten.

Lesen Sie nun den kompletten Artikel oder laden Sie sich die kostenlose Ausgabe als Download herunter.

SOAP oder REST? Diese Frage stellt man sich in letzter Zeit immer öfter, wenn es um die Implementierung webbasierter Services geht. Neben Fragen der Komplexität geht es hierbei auch sehr stark um Architekturthemen und natürlich auch um die effiziente Implementierung von verteilten Services. Mit JAX-RS und dem JSR-311 ist nun auch ein Standard im Java-Umfeld verfügbar, der die Implementierung von REST-basierten Services vereinheitlicht und somit das Pendant zu JAX-WS darstellt. Ist nun REST die – wie so oft behauptet – leichtgewichtige Alternative zu SOAP? Bei näherer Betrachtung zeigt sich, dass sich hier zwei Architekturkonzepte gegenüberstehen. Welches für welchen Anwendungsfall besser passt und wie sich das Ganze auf die Skalierbarkeit und Performance von Softwaresystemen auswirkt, wollen wir in diesem Artikel näher betrachten.

Was bin ich?

Zuerst soll aber eine grundsätzliche Unterscheidung bei Services eingeführt werden, die uns im Weiteren bei der SOAP-vs.-REST-Diskussion unterstützen wird. Grundsätzlich können zwei Arten von Services unterschieden werden. Datenorientierte – oder ressourcenorientierte – Services zielen darauf ab, CRUD-(Create, Read, Update, Delete) Operationen auf Daten zu unterstützen. Diese Services sind mit Datenbanken zu vergleichen. Sie verfügen über limitierte Verarbeitungslogik, die sich meist auf Datenvalidierung beschränkt. Ein Beispiel hierfür ist ein Adressverwaltungssystem zur Personen- und Anschriftenverwaltung. Prozessorientierte Services andererseits zeichnen sich durch einen hohen Anteil an Verabeitungslogik aus, die deutlich über reines Lesen und Schreiben von Daten hinausgeht. Die höchste Ausprägung sind hier sicherlich Services, die ganze Workflows steuern. Ein Beispiel hierfür wäre ein Auftragssteuerungsservice, der die Disposition und Zahlung einer E-Business-Anwendung steuert. Prozessoriente Services sind im Vergleich zu datenorientierten langläufiger. Ihre Abarbeitung wird oft nicht unmittelbar abgewartet, was zu einer oft auch asynchronen Implementierung dieser Services führt.

REST für Daten – SOAP für Services

Betrachtet man nun SOAP und REST, so sieht man, dass REST – wie auch schon der Name Representational State Transfer andeutet – für datenorientierte Services ausgelegt wurde. Die durch das HTTP-Protokoll vordefinierten Operationen sind direkt auf CRUD-Operationen umlegbar. SOAP, oder besser WSDL-basierte Services, sind in ihrer Struktur prozessorientiert ausgelegt. Hierbei handelt es sich um eine plattformunabhängige Möglichkeit, verteilte Anwendungen – oft auch serviceorientiert – zu entwickeln. Die Definition der Operationen findet hier auf Anwendungs- und nicht auf Protokollebene statt. Ursprünglich wurde SOAP und WSDL auch als plattformunabhängige Alternative zu CORBA entwickelt, mit dem Ziel, ein leichtgewichtiges RPCProtokoll bereitzustellen.

Antipattern: REST für Prozessinterfaces

Immer wieder wird darauf verwiesen, dass sich auch mittels REST prozessorientierte Services realisieren lassen. So wird vorgeschlagen, ganze Prozesse und Verabeitungsroutinen auf URLs und PUT-Requests abzubilden und Resultate dann über GET-Requests wieder abzufragen. Da allerdings die Verabeitungsdauer nicht vordefiniert ist, muss hier zwangsweise ein Polling-basierter Ansatz implementiert werden. Dies führt zu wesentlich mehr HTTP-Anfragen als notwendig. Die Alternative, einen GET-Aufruf zu verwenden und auf das Ergebnis zu warten, führt sehr schnell zu Skalierbarkeitsproblemen. Für langläufige Services werden hier auf Clientseite unnötig lange Verbindungen offen gehalten, was zu erhöhtem Ressourcenbedarf führt und somit die Skalierbarkeit sowohl auf Client- als auch auf Serververseite einschränkt. Mittels Web Services ließe sich hier ein asynchrones Serviceinterface unter Zuhilfenahme von WS-Addressing realisieren. Ein weiteres Problem dieses Ansatzes ist der daraus resultierende Overhead für die Zustandsverwaltung am Server. Nehmen wir als Beispiel einen RESTService, der Versicherungstarife berechnet. Die Abfragedaten werden via HTTP POST auf dem Server abgelegt. Mittels GET wird das Ergebnis vom Server abgeholt – wie schon angesprochen, eventuell mittels mehrerer GET-Requests, bis eine erfolgreiche Antwort bereit steht. Dann müssen die Ergebnisdaten noch mittels eines DELETE-Requests wieder vom Server gelöscht werden. Neben dem Overhead an zusätzlichen Anfragen liegt nun das serverseitige Zustandsmanagement bei der Client-Anwendung. In einer WSDL/SOAP-Umgebung ist dies durch einen asynchronen Web-Service- Aufruf einfach zu realisieren. Um das Zustandsmanagement braucht man sich nicht explizit zu kümmern.

Abb. 1:  Überblick über Caching-Strategien

Caching, caching, caching …

Caching von unnötigen Abfragen ist ein zentrales Konzept zur Erhöhung von Performance und Skalierbarkeit. Je mehr Abfragen vermieden werden können, desto besser. Bei Caching muss unterschieden werden, wo gecacht wird. Wie Abbildung 1 zeigt, kann an mehreren Stellen eines Systems gecacht werden. Caches können auf der Clientseite implementiert werden, wobei Anfragen komplett vermieden und weder das Netzwerk noch der Server belastet werden. Bei serverseitigem Caching wird unnötiges Abarbeiten von Abfragen vermieden. Drittens besteht die Möglichkeit, zwischen Server und Client mittels eines eigenen Cache-Servers zu cachen. Dies macht speziell dann Sinn, wenn serverseitig nicht gecacht werden soll, bzw. kann, oder Anfragen von unterschiedlichen Clients kommen. Letzteres Verfahren wird durch Proxy-Server realisiert REST wird hier zugute gehalten, auf die ausgeklügelten Mechanismen von HTTP zurückgreifen zu können. Der Server hat die Möglichkeit, die Gültigkeit von Daten explizit mittels des EXPIRES Headers zu spezifieren. Dieser Ansatz ermöglicht den einfachen Aufbau eines clientseitigen Caches, der zusätzliche Requests vermeiden kann. Allerdings kann er nur in Situationen angewendet werden, wo die Gültigkeit von Daten auch tatsächlich bekannt ist. Ein hierfür oft gebrauchtes Beispiel sind in regelmäßigen Abständen upgedatete Informationsquellen wie Tickerservices.

Ist die Gültigkeitsdauer von Daten dem Server nicht bekannt, muss mit Conditional Requests – sprich MODIFIED- SINCE Headern oder ETAGs – gearbeitet werden. Damit wird das unnötige Verschicken von Daten vermieden, allerdings nicht zwangsweise eine rechenintensive Verarbeitung auf der Serverseite, um herauszufinden, ob Daten tatsächlich verändert worden sind. Insgesamt bietet sich das Caching bei REST-basierten Services aber an, um Performance und Skalierbarkeit zu verbessern. Die bestehende HTTPInfrastruktur bietet dafür auch schon sehr etablierte und funktionierende Mechanismen, die für ein erfolgreiches Caching genutzt werden können.

Bei SOAP-basierten Services sieht das etwas anders aus. Während es bei REST Services genügt, Bedingungen rein auf HTTP-Ebene zu überprüfen, muss bei SOAP Services auch der Con- Abb. 1: Überblick über Caching-Strategien Wer mehr über das Thema REST erfahren will, findet unter www.jaxenter.de/artikel/2158 einen ausführlichen Beitrag dazu. Mehr zum Thema tent der Nachricht verarbeitet werden. Dies erfordert dann spezielle Infrastruktur.

Caching bei Web Services spielt allerdings nur dann eine Rolle, wenn datenorientierte Services implementiert werden. Bei prozessorientierten Services wird Caching allerdings explizit nicht gewünscht, da hier Prozesse angestoßen werden sollen. Sollte man in seiner Anwendung viele cachebare SOAP Web Services verwenden, ist dies ein potenzielles Zeichen, dass besser eine andere Kommunikation verwendet werden soll.

Geschnitten oder im Ganzen?

REST wurde als Architekturkonzept speziell für das Verarbeiten von Ressourcen entwickelt. Was Abfragen betrifft, ähnelt das Schema hier dem Laden von Daten aus einer Datenbank. REST baut allerdings für die Definition von Operationen auf HTTP auf, das dafür entwickelt worden ist, einzelne Ressourcen zu laden und zu verknüpfen. Komplexere Abfragemodelle sind nicht vorgesehen. Sehr oft will man aber mehrere Ressourcen gleichzeitig laden; sei es über IDs oder komplexere Abfragen. Wollen wir also die Kunden 10, 50 und 200 laden, resultiert dies in drei HTTP-Abfragen.

Dies würde sich zwar auch über Query- Parameter realisieren lassen, allerdings löst man sich dann vom ressourcenorientierten Ansatz. Das Gleiche gilt, wenn man nicht die ganze Ressource, sondern nur Teile der Information laden möchte, z. B. nur Vor- und Nachnamen.

REST fehlt es also im Unterschied zu anderen datenorientierten Services an einer geeigneten Abfragesprache, um Daten effizient laden zu können. Das haben auch die Anbieter REST-basierter Datastores wie zum Beispiel Amazons SimpleDB erkannt. Hier hat man eine an SQL angelehnte Abfragesprache definiert, um effizient auf Daten zugreifen zu können. Die effiziente Möglichkeit, auf Verwendungsseite steuern zu können, welche Daten geladen werden sollen, ist Voraussetzung für performante und skalierbare Anwendungen, da nur so das unnötige Übertragen von Daten vermieden werden kann. Der SOAP-basierte Ansatz bietet hier allerdings auch keine Alternative. Sicherlich kann man eine generische Abfrageschnittstelle definieren, die dann einen generischen Datencontainer retourniert. Dies ist allerdings weder einfach verwendbar noch performant.

Fazit

Abschließend kann gesagt werden, dass es keine bessere Lösung gibt, sondern nur unterschiedliche Anwendungsfälle mit spezifischen Anforderungen. In prozessorientierten Umgebungen zeigt sich der REST-Ansatz als ungeeignet und auch oft inperformant. Für das einfache Anbieten von Datenstrukturen ohne die Anforderung, komplexe Abfragen zu unterstützen, eignet sich der REST-Ansatz sehr gut. Um die Vorteile von Caching verwenden zu können, müssen allerdings die Rahmenbedingungen bezüglich der Erkennung von Datenveränderungen, bzw. infrequente Datenänderungen gegeben sein. Die Anwendungsanforderungen sollten auf jeden Fall im Vordergrund stehen, anstatt eine Anwendung in Architekturkonzepte zu pressen, die nicht passen. Sehr schnell ist man sonst in der Situation, dass die „goldene“ Lösung sich in einem oder mehreren Antipatterns manifestiert. Implementierungen wie Amazons SimpleDB zeigen auch, dass man manchmal mit etwas aufgeweichten Architekturkonzepten passendere Lösungen realisieren kann. Diese liegen dann zwischen REST und SOAP. JAX-RS ist auch hier ein komfortables Framework und auf jeden Fall praktischer als das Java Servlet API. SOAP Web Services haben trotzdem weiterhin ihre Daseinsberechtigung. Für spezielle Anforderungen hat man mit REST allerdings eine gute Alternative.

Links & Literatur

[1] JAX-RS http://jcp.org/aboutJava/communityprocess/final/jsr311/index.html
[2] Das bessere Modell für Web Services und JAX-RS Ein REST-orientiertes API. Java
Magazin 1.09
[3] R. T. Fielding, Architectural Styles and the Design of Network-based Software
Architectures, http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
[4] REST API von Amazon SimpleDB http://docs.amazonwebservices.com/
AmazonSimpleDB/latest/DeveloperGuide/index.html?MakingRESTRequests.html

Zurück zu den Publikationen