Der ursprüngliche Artikel [1] hat mehrere Gründe aufgeführt, warum Application Server keine zeitgemäße Plattform mehr darstellen. Kurz zusammengefasst:

Der Application Server ist speziell für die Anwendung konfiguriert – beispielsweise enthält er die passenden Datenbank-Verbindungen. Wenn aber zwei Software-Bestandteile wechselseitig voneinander abhängen, sind die sie eigentlich nicht mehr zu trennen. Eine Änderung an einem der Bestandteile beeinflusst wegen der Abhängigkeit auch jeweils den anderen. Ein weiteres Indiz für dieses Problem ist, dass oft ein Installationsskript für den Application Server direkt in der Versionskontrolle der Anwendung liegt.

Ein Application Server kann also eigentlich kaum mehrere Anwendungen beheimaten. Bleibt noch die Frage, ob für den professionellen Betrieb einer Anwendung ein Application Server notwendig ist. Schließlich bietet der Application Server eine Umgebung für den Betrieb und das Monitoring der Anwendungen. Es ist aber möglich, auch mehrere Instanzen einer Software in einem Cluster automatisiert zu deployen, zu monitoren und die Logs auszuwerten, ohne dabei einen Application Server zu nutzen. Mittlerweile haben sich viele Werkzeuge aus dem Continuous-Delivery-Kontext [2] dieser Probleme angenommen.

Abb. 1: Application Server und Anwendung hängen wechselseitig voneinander ab
Abb. 1: Application Server und Anwendung hängen wechselseitig voneinander ab

Bei dieser Kritik an den Application Servern geht es nicht um die APIs oder das Programmiermodell, sondern vor allem um Betrieb und Deployment. Die Frage ist also nicht, ob das Java-EE-Programmiermodell sinnvoll ist, sondern ob das Deployment einer Anwendung auf einem Application Server nützlich ist oder eher Nachteile mit sich bringt. Die Betrachtung betrifft also nicht nur Application Server, die das vollständige Java EE Profile implementieren, sondern auch Web Server wie Tomcat, die lediglich das Deployment von WAR-Dateien mit Servlets erlauben.

Alternativen?

Statt die Anwendung auf einem Application Server zu deployen, kann sie ihre gesamte Infrastruktur mitbringen. Man spricht von Uber-JAR, Fat-JAR-Deployment oder auch containerless Deployment. In einem einzigen JAR-File ist dann die gesamte Anwendung mit den notwendigen Bestandteilen eines Application Servers untergebracht. Diesen Ansatz verfolgen beispielsweise Spring Boot [3] aus dem Spring-Universum oder Play [4], Ratpack [5] oder Vert.x [6] als alternative Ansätze auf der JVM. Zum Zeitpunkt des ursprünglichen Artikels war das Angebot für geeignet Lösungen im Java-EE-Umfeld dünn. Spring Boot bietet einige Unterstützung [7]. Dropwizard [8] fokussiert vor allem auf JAX-RS-JSON-Web-Services und kann damit zumindest einen Teil der Java-EE-APIs anbieten.

Abb. 2: Fat JAR: Die Anwendung bringt die gesamte Infrastruktur mit – einschließlich des eingebetteten Application Servers
Abb. 2: Fat JAR: Die Anwendung bringt die gesamte Infrastruktur mit – einschließlich des eingebetteten Application Servers

Mittlerweile sind aber auch klassische Java-EE-Anbieter auf diesen Ansatz eingeschwenkt. JBoss bietet mit Wildfly Swarm [9] seinen Application Server jetzt auch in einer Form, die Deployment als Fat JAR erlaubt. Ähnliches erlaubt TomEE [10]. Somit kann also mittlerweile auch eine klassische Java-EE-Anwendung ohne Deployment auf einem Application Server in Produktion gebracht werden. Wie schon erwähnt, geht es eben nicht um das Programmiermodell, sondern das Deployment.

Der Java-EE-Standard selbst hat allerdings auf diese Ansätze nicht reagiert. Ansätze wie Wildfly Swarm oder TomEE sind keine Implementierungen des Java-EE-Standards, weil sie das Java-EE-Deployment-Modell nicht unterstützen. Eigentlich wäre es sinnvoll, den Standard in einen Deployment-Teil, der WAR- oder EAR-Deployment umfasst, und einen API-Teil aufzuteilen, der das Programmiermodell umfasst. Wildfly Swarm oder TomEE mit Far JARs würden dann den API-Teil implementieren, nicht aber den Deployment-Teil.

Neben dem Deployment als Fat JAR ist bei der Nutzung dieser Ansätze wichtig, dass die Anwendungen auch Metriken und sonstige Informationen für das Monitoring ausgeben, um so die Überwachung der Anwendungen zu ermöglichen.

Auswirkungen

Also bieten Application Server keine Vorteile und sind überflüssig – aber gibt es auch echte Nachteile? Das ist aber auch tatsächlich der Fall:

Kurz: Der Betrieb wird durch einen Application Server unnötig verkompliziert. Diese Probleme werden immer wichtiger, denn wegen Continuous Delivery müssen Anwendungen in den verschiedenen Test-Phasen installiert werden und sie werden auch viel öfter in Produktion deployt. Ebenso sind Microservices [11][12] ein Einflussfaktor: Sie teilen Anwendungen in kleine Module auf, die jeweils einzeln deployt werden. Statt also eine Anwendung einmal pro Quartal in Produktion zu bringen, werden nun wegen Microservices sehr viele Anwendungen deployt und das wegen Continuous Delivery auch viel öfter in verschiedenen Umgebungen deployt. Wenn der Aufwand für das Deployment und den Betrieb eines Application Servers eingespart werden kann, ist das gerade in diesen Szenarien hilfreich. Durch Microservices und Continuous Delivery setzten sich außerdem immer mehr Entwickler mit Werkzeugen auseinander, die für den Betrieb und das Deployment relevant sind. Dadurch realisieren sie, dass es neben Java Application Servern zahlreiche alternative Ansätze gibt, die für den Betrieb und das Monitoring ebenfalls nützlich sind. Deswegen betrachten sie auch zunehmend Ansätze ohne Application Server.

Obwohl Microservices und Continuous Delivery ihren Teil zu dem Abschied vom Application Server beitragen, sind sie nicht Voraussetzungen dafür: Natürlich kann eine monolithische, klassische Java-EE-Anwendung einmal pro Quartal ohne Application Server ausgeliefert werden. Selbst dann ergibt sich durch die niedrigere Komplexität beim Deployment in Produktion aber mehr noch während der Entwicklung erhebliche Vorteile.

Wo sind Application Server noch sinnvoll?

Nun stellt sich die Frage, ob Application Server nicht doch in bestimmten Situationen noch sinnvoll sind. Dieser Frage ist der ursprünglich Artikel nicht nachgegangen, weil er eine rein technische Diskussion geführt hat. Aus dieser Perspektive sollten Projekte eigentlich nicht mehr auf Application Server setzen.

Behäbigkeit des Betriebs

Zwar sind Deployment und Betrieb einfacher, aber in vielen Organisationen gibt es bereits etablierte Betriebs- und Deployment-Prozesse, die auf Application Server abgestimmt sind. Der technischen Vereinfachung steht dann der Aufwand zur Umstellung der Prozesse gegenüber. Die Prozesse müssen im Betrieb umgestellt werden, für den oft eher die Stabilität der Prozesse wichtig ist. Außerdem gibt es meistens mehr Deployments auf Test-Umgebungen, die unter der Kontrolle der Entwicklung stehen. Der Betrieb profitiert nur von den Vereinfachungen beim Deployment in Produktion und hat also nur einen Teil der Vorteile. Obwohl also der Verzicht auf Application Server in diesem Szenario technisch sinnvoll wäre, kann es aufgrund von organisatorischen Herausforderungen dazu kommen, dass dennoch weiter Application Server genutzt werden.

Wenn die technischen Vorteile einmal verstanden sind, sind die oft erzwungene Konstanz im Betrieb und die hohen Investitionen in vorhandene Application-Server-Infrastrukturen sicher der primäre Grund, warum Application Server immer noch im Einsatz sind.

Niedrige Anforderungen

Die Diskussion geht davon aus, dass es für jede Anwendung einen oder mehrere Application Server Instanzen gibt. Es gibt aber Fälle, in denen tatsächlich trotz aller technischen Nachteile mehrere Anwendungen auf einem Application Server deployt werden. Das kann sinnvoll sein, wenn die Anforderungen an die Skalierung und die Ausfallsicherheit nicht so hoch sind, so dass kein Betrieb im Cluster notwendig ist und auch die mangelnde Isolation kein Problem ist. Dann haben Application Server echte Vorteile: Eine Anwendung ist nur noch eine WAR-Datei, die in ein bestimmtes Verzeichnis kopiert werden muss und dann in die Betriebsprozesse integriert ist. Application Server sparen dann also Aufwände im Betrieb.

Diese Szenarien sind überraschend, denn Application Server sind ursprünglich für Enterprise-Szenarien entwickelt worden, in denen typischerweise die Ausfallsicherheit und Skalierbarkeit sehr wichtig sind. Nur wenn die Ansprüche in diesen Bereichen nicht sonderlich hoch sind, haben Application Server aber tatsächlich Vorteile und eine Vereinfachung zur Folge.

Micro-/Nanoservices

Es gibt aber auch andere Gründe für den Einsatz von Application Servern. Interessanterweise können Application Server sinnvoll dazu genutzt werden, um Microservices zu betreiben. Dazu werden mehrere Services auf einem Application Server betrieben – jeder als ein eigenständiges WAR. Im Gegensatz zu richtigen Microservices sind diese Services aber bezüglich Ausfall nicht richtig isoliert, weil bei einem Ausfall eines Application Server mehrere Services ausfallen. Das ist problematisch, weil in einer Microservice-Umgebung eine Vielzahl Services laufen. Wenn der Ausfall eines Service andere Services mitreist, kann es leicht zu Domino-Effekten kommen: Ein Service fällt aus. Das führt nach und nach zum Crash weiterer Services, so dass am Ende das gesamte System nicht mehr zur Verfügung steht. Üblicherweise vermeiden Microservices das Problem, indem sie beim Ausfall eines aufgerufenen Service Vorgabewerte oder Caches nutzen. Das ist aber bei einem gemeinsamen Deployment nicht ausreichend. Wenn ein Service ein Speicherleck hat, bringt er die JVM zum Absturz und damit alle Services, die auf demselben Application Server deployt sind. Vorgabewerte oder Caches nützen dann nichts mehr.

Im Gegensatz zu echten Microservices ist bei der Nutzung eines Application Server auch die Technologiefreiheit eingeschränkt. Wenn als Basis für die Microservices statt eine Application Servers Docker gewählt wird, können die Microservices beliebige Programmiersprachen und Plattformen nutzen. Selbst wenn die Technologien auf die JVM eingeschränkt werden, können Ansätze wie Play [4] oder Vert.x [6] genutzt werden, die andere Programmiersprachen und ein Reactive-Programmiermodell unterstützen. Application Server hingegen unterstützen nur das Java-EE-Programmiermodell.

Ein weiteres Problem bei diesem Vorgehen: Selbst ein unabhängiges Deployment ist nicht wirklich möglich, da in der Praxis beim Deployment eines einzelnen Service in einem WAR meistens der gesamte Application Server neu gestartet werden muss. Das beeinflusst die anderen Services, die dann für einige Zeit ausfallen. Das unabhängige Deployment ist aber eine zentrale Eigenschaft von Microservices. Dank dieser Möglichkeit kann ein Team neue Features ohne Abstimmung mit anderen Teams in Produktion bringen. Das ist kaum möglich, wenn die Services gemeinsam in einem Application Server laufen. Dann wird nämlich das Deployment eines Service die anderen Services zum Ausfall bringen und das macht vermutlich eine Koordination notwendig.

Das Deployment mehrerer Services auf einem Application Server hat also einige Charakteristika von Microservices, ist aber dennoch ein etwas anderer Ansatz. Insbesondere die Kompromisse bezüglich des unabhängigen Deployment sind schmerzhaft. Das unabhängige Deployment ist eine zentrale Eigenschaft von Microservices. Um diesen Ansatz klar von „richtigen“ Microservices zu trennen, kann für dieses Modell ein anderer Begriff wie „Nanoservices“ [11] sinnvoll sein.

Ein Beispiel für Nanoservices zeigt Abb. 3: Order, Customer und Catalog sind jeweils fachliche Nanoservices, die jeweils für den Nutzer über HTTP und HTML nutzbar sind. Untereinander nutzen sie REST zur Kommunikation. Sie sind alle gemeinsam auf einem Tomcat-Server deployt.

Abb. 3: Beispiel für Nanoservices
Abb. 3: Beispiel für Nanoservices

Docker?

Mit Docker [13] steht ein neuer Ansatz bereit, der zumindest von den Begriffen her etwas mit der Application-Server-Welt zu tun hat: Es gibt auch bei Docker Container, die eine weitgehend isolierte Linux-Umgebung mit eigenen Filesystemen und Netzwerkkonfigurationen bereitstellen. Ebenso gibt es ein Deployment-Modell, das jeweils ein vollständiges Filesystem-Image umfasst und damit eine komplette Installation einschließlich Betriebssystem. Es gibt ein ausgefeiltes System, um Basis-Images zu ermöglich. So kann eine Betriebssystem-Installation für mehrere Anwendungen wiederverwendet werden.

Dieser Ansatz lässt sich mit einem Application Server kombinieren: Es gibt ein Basis-Image, auf dem der Application Server deployt ist. Jede Anwendung verwendet dieses Basis-Image und fügt die Anwendung hinzu. Das scheint zunächst den betrieblichen Aufwand für einen Application Server zu reduzieren. In der Realität sind aber die zentralen Probleme nicht gelöst: Der Application Server muss nach wie vor auf die jeweilige Anwendung angepasst werden und damit ist das Deployment immer noch komplex. Also hilft Docker nicht dabei, den Einsatz von Application Servern zu vereinfachen.

Fazit

Application Server haben das Enterprise-Java-Umfeld lange dominiert. Es sind teilweise sehr hohe Investitionen in diese Technologien geflossen und sie sind tief in die Deployment- und Betriebsprozesse verwurzelt. Daher ist es nicht überraschend, dass immer noch viele Application Server in Produktion sind und dort wohl auch bleiben werden. Aus einer rein technischen Perspektive sind Application Server aber in den allermeisten Fällen nicht nur verzichtbar, sondern haben echte Nachteile. Ausnahmen bilden lediglich Szenarien mit recht niedrigen Anforderungen an Verfügbarkeit und Skalierbarkeit oder das beschriebene Nanoservices-Szenario.

Mittlerweile kommen auch immer mehr Technologien auf den Markt, die ohne Application Server auskommen und auf ein Fat-JAR-Deployment setzten. Dazu zählen auch immer mehr Vertreter der Java-EE-APIs, so dass auch mit diesen klassischen APIs ein Verzicht auf Application Server möglich ist.

Der ursprüngliche Artikel hat zu einigen Diskussionen geführt – für die ich mich an dieser Stelle bedanken möchte. Feedback ist immer hilfreich und das Feedback hat zu diesem Artikel beigetragen. Leider kann ich hier nicht alle namentlich aufführen. Ich freue mich auf das Feedback zu diesem Artikel!

Links & Literatur

  1. Eberhard Wolff: Der Tod der Java Application Server, JavaMagazin 7/2014  ↩

  2. Eberhard Wolff: Continuous Delivery: Der pragmatische Einstieg, 2. Auflage, dpunkt, 2016, ISBN 978–3864903717  ↩

  3. http://projects.spring.io/spring-boot/  ↩

  4. https://www.playframework.com/  ↩

  5. http://ratpack.io/  ↩

  6. http://vertx.io/  ↩

  7. https://spring.io/blog/2014/11/23/bootiful-java-ee-support-in-spring-boot-1-2/  ↩

  8. http://dropwizard.io/  ↩

  9. https://github.com/wildfly-swarm/wildfly-swarm/  ↩

  10. http://www.tomitribe.com/blog/2015/03/50-shades-of-tomee/  ↩

  11. Eberhard Wolff: Microservices: Grundlagen flexibler Software Architekturen, dpunkt, 2015, ISBN 978–3864903137  ↩

  12. http://microservices-book.com/primer.html/  ↩

  13. http://docker.com/  ↩