Microservices – Wozu?

Wie schon erwähnt gilt es eine ganze Menge Infrastruktur aufzusetzen, bevor man eine größere, Microservice basierte Anwendung bauen kann. Warum sollte man sich diesem Stress aussetzen? Ist ein Monolith nicht viel handlicher?

Die Sache mit der Skalierung

Eine der klassischen Antworten ist „Microservices skalieren viel besser“. Ist das so?

Ich hatte vor gut 16 Jahren schon einmal das Vergnügen mit einer Service basierten Architektur zu programmieren. Und wir haben enorm viel Zeit darauf verwendet, diese Architektur schnell zu machen. Letztendlich stellte sich heraus, dass unsere Services so feingranular waren, dass sie den größten Teil ihrer Rechenzeit mit der Kommunikation mit anderen Services verbrachten. Anders gesagt, wenn ich einen lokalen Funktionsaufruf durch einen Netzwerkaufruf ersetze, wird die Anwendung damit erst einmal nicht schneller. Also ist im Zweifelsfall ein Monolith, den ich als ganzen parallelisieren kann, gar nicht so doof.

Das kann bei rechenintensiven Aufgaben schon wieder ganz anders aussehen, wenn eben halt diese zeitaufwändige Service über mehrere Maschinen verteilt wird.

Dei Antwort ist also, wie meist, „es kommt drauf an“.

Das war nebenbei einer der Gründe, warum ich mich damals auf Java EE gestürzt habe: Ich mochte einfach die Möglichkeit mit einfacher Konfiguration zu entscheiden, ob ich EJBs lokal oder remote verteile. Und ich hatte keine Lust mehr unfassbar viel Infrastrukturcode zu schreiben.

Organisation

Ein wirklich guter Grund für Microservices ist Organisation. Wenn ich ein kleines Startup bin mit vielleicht 5 Entwicklern, ist die Aufteilung in Services und einzelnes Deployment dieser Services ein ziemlich bremsender Overhead. Wenn das Programm aber komplexer wird und wir mehrere Teams haben, die unterschiedliche Bereiche eines Programms parallel bearbeiten sollen, ist es enorm Hilfreich, wenn diese Bereiche tatsächlich voneinander getrennt sind.

„Ja, aber wir machen voll so Domain Driven Design und von daher haben wir ohnehin keine Überschneidungen im Code.“ Glückwunsch. Euer Code ist vorausschauend entwickelt worden und lässt sich prima schneiden und in einzelne Microservices aufteilen. Gesehen habe ich das allerdings noch nie.

Programmierer sind faul. Insbesondere gute Programmierer. Insbesondere in der Anfangsphase einer neuen Anwendung bedeutet fast jede Anforderung, dass man jeden Bereich des Programms anfassen muss. Alle Schnittstellen sind in permanenter Veränderung. Und bevor man für so eine kleine Änderung jetzt in 7 Dateien rumwerkelt, kann man doch die Funktionalität einfach mal eben schnell hier reinbauen.

Wenn man sich nicht ständig in den Codereviews gegenseitig mit der Nase darauf stößt und nicht ständig refactored, hat man innerhalb erstaunlich kurzer Zeit den unwartbarsten Codeknäul, den niemand mehr anfassen mag. Bei Microservices ist die Application physisch getrennt. Das kann – zumindest theoretisch – dafür sorgen, dass das Domainmodell stabiler bleibt und erhöht die Wartbarkeit des Codes.

Natürlich greifen die ganzen Vorteile von modularer oder komponentenorientierter oder domainorientierter Architektur auch bei Microservices: Bessere Testbarkeit der eizelnen Services, verständlicherer Code, da der sich nur mit einem Bereich beschäftigt.

Die Sache mit der Wolke

Ein anderer guter Grund für Microservices dürfte diese Cloud Sache sein. Große Cloudinstanzen sind ziemlich teuer. Was man für eine kosteneffiziente Nutzung von AWS und Konsorten möchte, sind relativ feingranulare, günstige Instanzen, die man je nach bedarf dynamisch hochskalieren kann, wenn sie gebraucht werden. Ein Batch Service, der monatlich Abrechnungen macht? Dieser wird monatlich hochgefahren und belegt außerhalb der Zeit keine Ressourcen. Durch irgendeinen Facebook Hype will plötzlich das ganze Internet eine bestimmte Funktionalität der Anwendung nutzen? Für die Dauer des Hypes werden automatisch entsprechende Instanzen hochgefahren.

Microservices sind DIE Architektur der Cloud. Wer das Cloud Modell wählt, wird um Microservices nicht herumkommen. Ist so. Der Erfolg der Cloud bedingt direkt den Erfolg von Microservices. Das ist an sich schon das Killerargument schlechthin: Da alle Cloud machen, machen auch alle Microservices.

Technik Firlefanz

Poliglott Programming irgendwer? Klar, das war auch zu Java EE Zeiten schon mal ein Thema. Es gibt unfassbar viele JVM Sprachen. Aber da die minimalisierte Systemumgebung mit Docker gleich mitdeployed wird, kann man tatsächlich in jeder Sprache Microservices bauen. Ein bestimmtes Problem lässt sich elegant in Haskell  lösen? Schreibt man halt einen Service in Haskell. Ich brauche was mit geteilten Datenstrukturen die idealerweise in den CPU Cache passen? Ok, schreibe ich halt was in C++. Irrsinnige, mathematische Geschichten? Ok, schreibe ich alt in R. Nie war „right tool for the job“ leichter umzusetzen als mit Microservices.

Außerdem braucht man prinzipiell keine Frameworks mehr – doch dazu mehr im dritten Artikel.

Ownership

Da ein Microservice üblicherweise klein (halt micro) ist und irgendetwas cooles den auf Knopfdruck in die Cloud schiebt (hoffentlich), gehört selbst in großen Firmen der Service dem Team. Das Team ist vollständig für den Service verantwortlich. Es gibt kein „ich baue eine Version und nach einem Jahr wird das Modul  mit dem nächsten großen Build veröffentlicht“ sondern es passiert gleich. In dem Augenblick, wo die Änderungen an dem Modul fertig sind, wird es live gestellt. Man kann also sofort sehen, wie sich die Änderungen im System auswirken. Continuous Delivery ist mit einem Monolithen, freundlich gesagt, etwas mühselig – bei Microservices ist es Teil der Philosophie. Wie oft continuous ist, darüber lässt sich trefflich streiten – darüber aber später mehr.

Es gibt also offensichtlich technische sowie organisatorische Aspekte zu  beachten. Welche das sind, dazu in den folgenden Artikeln mehr.

Ein bisschen Geschichte zu Microservices

Ja, ok, ist an sich ein alter Hut, aber hey, vielleicht kann ich ja noch ein paar interessante Punkte beisteuern. Ich fange erstmal mit dem klassischen „Pff, hab ich schon vor 100 Jahren gemacht“ Sprüchen des IT Opas an:

Microservices aus Sicht des Java EE Entwicklers

Für Java EE Entwickler ist das irgendwie alles erstmal total unspektakulär. Kleine, Domainorientierte Einheiten, die in sich geschlossen sind? Nannte man erst Components, die dann zu einer Applikation zusammengestöpselt wurde und später, als SOA aufkam, Services.

Die einzelnen Komponenten wurden in Einheiten (EARs) deployed. Die Registry heißt bei Java EE JNDI, worüber auch externe Services wie Datenbanken angebunden werden können. Monitoring, Verteilung auf mehrere Hardwarenodes, Paralellisierung, Messeging-Systeme, Log-Verwaltung – all das hat der Application Server geliefert. Jeder Hersteller hatte ein paar Extras eingebaut, die die Entwicklung vereinfacht und den Umstieg erschwert haben, bei einigen gab es das ganze auch gleich komplett mit Hardware.

Damals hatten Firmen noch Rechenzentren, in denen Tatsächlich etwas Stand und als Mitarbeiter von einem Startup war es normal, wenn man als Entwickler auch an Racks rumgeschraubt hat, was heute kein Mensch mehr nachvollziehen kann.

Die Kommunikation zwischen den Komponenten war üblicherweise Corba (IIOP) und später dann in der SOA Welt: SOAP.

Wolken

Die Unkalkulierbarkeit des Internets machte aber das Vorhalten von Rechnerressourcen für Peaks ziemlich unwirtschaftlich. Entweder man hatte schrecklich viel Hardware, die dann die meiste Zeit unnütz in der Gegend herumstand oder man konnte sprunghaften Anstieg der Nachfrage einfach nicht bedienen. Mit immer besser werdenden Virtualisierungen, und damit der Möglichkeit, Instanzen schnell zu Klonen, und zunehmend schnellerem Internet, war es somit nur logisch, dass die Internetriesen ihre überschüssigen Kapazitäten verkauften.

Ein Modell, ohne das es viele Startups nie gegeben hätte. Man konnte eine Idee implementieren ohne sich auf kostspielige Hardwarevorleistungen einzulassen.

Die Cloud Integration hat Java EE gehörig verschlafen – naja, nicht wirklich. Ambitionen in der Richtung gab es bereits bei Glassfish 3, ist aber bis heute nicht wirklich sinnhaft umgesetzt worden und steht damit erst wieder für Java EE 9 auf dem Plan. (Jaja, es gibt da Workarounds aber dazu ein anderes mal mehr.)

Microservice Infrastruktur

Statt eines EJB-Jars gibt es im Microservice Docker Container, das Pendant zu EAR wäre wohl ein POD, die Rolle das Java EE Containers übernimmt Kubernetes, Log Management macht meist Logstash, Metriken zB Prometheus, Security kann man mit Keycloak machen, WARs also das Frontend Beispielsweise mit Aglular2. Das ist für so ein bisschen WebShop schon mal ne ganze Menge Holz.

Wie soll man das denn vernünftig aufsetzen und verwalten? Ich meine, in der guten alten Zeit hab man sein Komponenten mit maven gebaut, in arAchiva veröffentlicht und dann im gleichen build, alle anderen Komponenten gealden, zu einem EAR verschnürt und gleich auf einen Testserver deployed. Für Microservices gibt es da natürlich auch was: zB. Fabric8. Und ja, das ist jetzt auch nicht so schlank für eine komplette Umgebung – aber zu Zeiten von J2EE (1.4)  war so ein AppServer auch ein ziemliches Dickschiff auf dem Notebook.

Also im Großen und Ganzen vom Konzept her erstmal nicht so revolutionär das alles. Statt IBM oder BEA hängt man halt jetzt an Amazon, Microsoft oder Google, statt für Rechenzentren zahlt man für Cloud Provider und statt Admin Abteilungen hat man halt DevOps. Bleiben zwei entscheidende Fragen: Warum sollte ich mir das antun? Und wenn ja, wie? Dazu dann im nächsten Beitrag mehr.