Microservices und Lasagne
Posted in tech with tags tech Microservices Java Software Lasagnacode Softwareschrott rant Quählkot Weniger ist Mehr Minimalismus Innovation -Es war einmal eine Internetseite mit zu viel Besuch oder zu komplexen Dingen die der Besuch von der Seite wollte. Jedenfalls entstand völlig Überraschend so viel Last auf der Kiste dass ein Rechner nicht mehr ausreichte um alle Anfragen zu beantworten.
Was macht man wenn ein Problem zu groß für einen Rechner wird? Man teilt das Problem auf!
Nur wie aufteilen?
Microservices to the rescue
Aus der Business/Java-Ecke kam die Idee sogenannte “Microservices” zu bauen, Module die sich per HTTP unterhalten und jeweils nur eine winzige Teilaufgabe übernehmen. Teilaufgaben wie “Login verwalten”, “Warenkorb” oder die Kommunikation mit der Datenbank.
Soweit klingt das noch sinnvoll und die Analogie zu UNIXoiden, kleinen Werkzeugen die austauschbar und leicht zu warten sind, macht Hoffnung auf Tools wie grep oder cat.
Aber wir reden über das Java-Umfeld. Also haben wir z.B. einen Java-Dienst der mal knapp ein Gigabyte RAM frisst um DB-Model-Layer zu spielen, SQL-Queries zu basteln und als XML oder JSON über HTTP an andere Dienste bereitzustellen. Damit dieser dies tun kann, muss natürlich noch irgendwo ein weiterer Dienst rumlaufen, wieder Java, wieder ein knappes Gigabyte RAM, der über HTTP Dienste registrieren lässt und verwaltet welcher Dienst wo zu erreichen ist.
Und wie gesagt, Java-Umfeld, da hat jeder Dienst hundert Abhängigkeiten und jede einzelne davon mehr Umfang als ein grep oder cat.
Klar, mit ein paar kleinen Optimierungen lässt sich der RAM-Verbrauch pro Dienst locker auf unter 256MB drücken …also zumindest so lange die Dienste nichts tun.
Aber gut, für den kleinen Preis von ein paar zusätzlichen GB RAM-verbrauch, etwas Netzwerk-Kommunikation, HTTP-Parsing, XML-Parsing, ein paar Schichten Java und ein paar hundert eingebundener Bibliotheken, erhalten wir den einfachen Zugriff auf einen Dienst der unsere gespeicherten Daten einfach zugreifbar zur Verfügung stellt und zu einer Datenbank weiterleitet die diese auf der Festplatte ablegt.
Manche Leute hätten gefragt wo der Unterschied zwischen sowas und dem was die Datenbank selbst tut sein sollte, aber wir sind nicht so Fortschrittsskeptisch!
Bauen und Installieren
Java ist kompliziert. Abhängigkeiten sind kompliziert. Installationen sind kompliziert.
Warum sich das Leben nicht viel leichter machen und das alles wegautomatisieren?
Also nehmen wir sowas wie Maven, schreiben ein paar dutzend Zeilen XML, integrieren uns ein paar dutzend Plugins in die Entwicklungsumgebung und schon braucht es nur noch einen Knopfdruck und die Tools laden die fehlenden Abhängigkeiten aus dem Internet (wer kontrolliert eigentlich die Qualität der Bibliotheken die da einfach unbesehen ins Endprodukt compiliert werden?), bauen uns eine Jar-Binärdatei, oder gleich ein ganzes Dutzend, und schon können wir jeden Dienst mit einem Shell-Aufruf starten.
Jetzt muss nur noch jemand losgehen, ein paar dutzend Rechner bespielen, Java installieren, Autostart-Scripte bauen die unsere Java-Services starten und schon sind wir fertig!
Wobei… wenn wir schonmal Maven haben, könnten wir doch mehr damit automagisieren?
Docker, Docker, Docker, lol!
Ein paar Zeilen mehr XML, ein paar hundert MB mehr ungeprüften Download von binären Inhalten und aus unserem Tool fällt keine Reihe Jar-Dateien mehr. Jetzt haben wir Docker-Images die aus unserem Script fallen und die automatisch installiert werden.
Jetzt braucht man sich endlich nicht mehr darum kümmern wie die Dienste installiert werden! Oder… doch, etwas schon noch. Immerhin müssten wir Docker jeweils noch sagen welchen Port für welche VM es auf den Host abbilden soll, müssten den Images selbst noch beibringen wie sie sich gegenseitig mitteilen sollen wie man sie erreicht, man müsste Maven auf jedem Host ausführen, …
Nein, wir brauchen Orchestration! Ein weiterer Layer der uns auch diese Probleme wegautomatisiert… gut, er bringt bestimmt weitere, kleine Probleme mit sich, aber das ist bestimmt irgendwie automatisierbar.
Vlt. wenn wir noch eine Schicht darum bauen?
Dann haben wir jedenfalls endlich unsere Eierlegende Wollmilchsau, die völlig Aufwandsfrei überall installiert wird, beliebig auf einem Rechner oder über tausende verteilt skaliert werden kann (vorrausgesetzt jemand beobachtet an welchem Flaschenhals die Performance gerade hängt und mehr von den entsprechenden Services startet - es sei denn Kommunikation ist der Flaschenhals oder so, dann hilft das natürlich nicht) und alle sind glücklich.
Aber ist das nicht der einzige Weg?
Wie sollte man sowas denn sonst machen?
Wie wäre es denn mit Microservices die wirklich “Micro” sind? Also jetzt nicht unbedingt vom Funktionsumfang her - Wir haben bereits gesehen dass jede zusätzliche Aufspaltung zu massiv mehr Zusatzaufwand führt. Wir wollen nur jede Aufgabe so klein bekommen dass sie von einem einzelnen Rechner schaffbar ist. Das geht bestimmt leichter wenn wir nutzlose Schichten weglassen.
Statt also Lasagne zu stapeln, hätt’ ich lieber möglichst flache Strukturen.
- Wenn ich Daten will, frag ich die Datenbank.
- Wenn ich alle Daten als Objekte haben will, sollte ich halt eine Datenbank suchen die die Daten so verwaltet und nicht 3x zwischendrin Umwandeln.
- Wenn ich wenig Aufwand beim Installieren will, linke ich mein Zeugs statisch in die Binary oder bau mir eine .deb/.rpm/wasauchimmer in der die Abhängigkeiten stehen
Und wenn ich dann ganz am Ende doch alles virtualisiert oder in Wolken verteilt haben will? Dann kann ich das noch immer machen!
Aber bis ich an der Stelle bin, habe ich vlt. statt eines “Technologiestacks” den ich nicht ohne 3 Baumdiagramme erklären kann, eine einfache Struktur. Die gesparte Zeit könnte ich vlt. sogar dazu verwenden ausnahmsweise mal Code zu schreiben.
PS: Nein, Microservices sind eigentlich keine neue Kategorie neben Lasagne/Spaghetti-Code - es ist genau der selbe Schichtkuchenmüll den die Java-Fraktion schon seit Jahrzehnten baut