Boehrsi.de - Blog

Boehrsi.de Services - Ideen und die Basis-Architektur

Erstellt am event Uhr von account_circle Boehrsi in label Boehrsi
Boehrsi.de Services - Ideen und die Basis-Architektur Bild

Nachdem ich bereits ein paar Worte darüber verloren habe, warum ich meine Services selbstgeschrieben habe, geht es heute mit den Anforderungen und der generellen Architektur weiter. Als ich vor zwei Jahren meine Java Services schrieb, war das Thema Microservices natürlich auch in meinem Kopf sehr aktiv. Das Resultat damals waren zwei komplett unabhängige Services, für die Suche und die Kommentare. Alles unabhängig, was natürlich seine Vorteile hat, aber eben auch Nachteile.
Die Nachteile wollte ich mit meinen neuen Diensten eliminieren, denn wenn man schon erneut auf der grünen Wiese startet, soll das Ganze natürlich auch ordentliche Verbesserungen bringen. Insgesamt überlegte ich mir die folgenden Anforderungen, welche auf meinen Erfahrungen mit meinen bis dato aktiven Services beruhen.

Java / JVM basiertes Setup

Es gibt viele Alternativen (z.B. Go open_in_new oder Rust open_in_new), aber aufgrund meines Wissens im Bereich Java open_in_new und Kotlin open_in_new war es für mich einfach diese Entscheidung zu treffen. Der Hauptgrund dafür war meine allgemeine Zielsetzung. Ich wollte mit angemessenem Zeitaufwand produktiv nutzbare Services entwickeln. Ich lerne natürlich auch gerne neues, aber in diesem Fall war der Fokus auf die eigentliche Fertigstellung der Services gesetzt. Das konkret Kotlin statt Java genutzt wird, war ebenfalls eine einfache Entscheidung, denn Kotlin ist in meinen Augen ein besseres Java.

REST API

Auch wenn mit GraphQL open_in_new neue Ansätze das Feld betreten haben, wollte ich an REST open_in_new festhalten. Ich habe mich zwar mit GraphQL auseinandergesetzt, empfand aber das Kosten / Nutzen Verhältnis unpassend, um es in diesem Projekt einzusetzen. Abgesehen davon wirkte GraphQL eher passend für sehr große, komplexe oder agile APIs, während mein Setup zwar flexibel, aber durchaus stabil werden soll. In diesem Bereich werde ich aber versuchen auf dem Laufenden zu bleiben, denn neue grundlegende Techniken sollte man nicht aus den Augen verlieren.

Simples Framework als Basis

Java / Kotlin Frameworks für REST Services gibt es wie Sand am Meer, aber auch hier konnte ich mich recht leicht entscheiden. Grund dafür sind meine Erfahrungen mit Spark open_in_new und der Umstand das Javalin open_in_new das Beste aus Spark und anderen Frameworks nutzt und in Kotlin aufgefrischt zusammenführt. Insofern habe ich hier mit Javalin sehr bekannte Ansätze und Konzepte, aber in neuem Gewandt und modernisiert in Kotlin entwickelt. Diesen Ansatz habe ich z.B. Spring Boot open_in_new vorgezogen, da ich einen eher leichten Wrapper wollte, der mir grundlegende Dinge abnimmt, aber keine komplexe Konfiguration braucht oder mit Feature-Überfluss für Probleme sorgt.

Resource Sharing

Zu Beginn erwähnte ich Microservices, welche unabhängig voneinander laufen und somit einige Vorteile bieten. Ein Nachteil ist allerdings, dass meistens Ressourcen pro Service (Stichwort Arbeitsspeicher im Java Bereich) verbraucht werden, welche bei gemeinsamer Nutzung vermutlich geringer wären. Da ich nur einen relativ kleinen Server betreibe, welcher zwar die eine oder andere Lastspitze bewältigen muss, aber kein massiv skalierbares Setup braucht, wollte ich mich von diesem Ansatz etwas entfernen.
Die Lösung für mich ist ein Plug-And-Play System auf Implementierungsebene. Damit meine ich, dass ein Service, welcher in einer JVM läuft, eine beliebige Anzahl an eigentlichen Aufgaben (z.B. eine Suchfunktion, das Anzeigen von Kommentaren oder das bereitstellen eines Feedback-Systems) umsetzen kann. Die Benotung liegt hier auf “kann”, denn falls gewünscht kann ein Services natürlich auch nur eine Aufgabe erfüllen bzw. Implementierung bereitstellen und somit wieder mehr in Richtung Microservices gehen. Da dies eine der Kernideen für meine neuen Services ist, wird dieser Bereich noch einmal umfangreich in einem gesonderten Beitrag behandelt.

Multiple Services auf einem Server

Auch wenn dieser Punkt eigentlich klar ist und meist von Haus aus möglich ist, habe ich es trotzdem in meine List aufgenommen. Ich möchte für verschiedene Domains mitunter die gleichen oder unterschiedlichen Services laufen lassen können. Zusammengehörende Setups sollten dann natürlich via Resource Sharing den Server schonen. Getrennt wird hier wie gewohnt, einfach über konfigurierbare Ports für die Services.

Einfache Verwaltung der Services

Da ich nicht plane eine große Menge von Diensten gleichzeitig zu betreiben und ein unkomplizierter Betrieb für mich das A und O ist, möchte ich kein komplexes Management betreiben müssen. Ich brauche hier kein Docker open_in_new, Kubernetes open_in_new, umfangreiche Management-Tools oder ähnliches. Ich möchte mit wenigen Shell-Befehlen und menschen- und maschinenlesbaren Konfigurationsdateien alles betreiben können. Bei dieser Umsetzung helfen mir automatisch generierte Scripte, welche ich durch die Nutzung einiger Gradle Plugins open_in_new quasi frei Haus bekomme.

Flexible Entwicklung ohne unnötigen Overhead

Ein Konzept dieser Art, mit der erwähnten flexiblen Verbindung der Basis mit den eigentlichen Implementierungen der Funktionen, kann auf viele Arten erreicht werden. Man kann eine Library erstellen, welche dann importiert und genutzt werden kann oder man wirft einfach alles zusammen in eine Code-Base und dupliziert komplette Git Repositories.
Dies waren zwei extreme des Spektrums, welche mir beide nicht zusagten. Letzteres aus offensichtlichen Gründen, denn eine solche Codeverwaltung führt zur Duplizierung von Code und schlechter Wartbarkeit. Leider ist aber auch der erste Ansatz, alles als komplett autarke Library zu entwickeln, nicht passend für mich. Grund dafür ist der Overhead der entsteht, wenn man derartige Dinge tut. Eine Library muss auf einigen Stufen mehr gekapselt und teils anders entwickelt werden. Das Ganze will paketiert, versioniert und ausgeliefert werden, was alles weiteren Aufwand bedeutet. So gerne ich selbigen auf mich genommen hätte, der Overhead war in diesem Projekt zu viel, weswegen das Ganze aktuell auch nur intern verfügbar und nicht für jeden zugänglich ist.
Mein Ansatz basiert nun auf einem Core Repository, welches alle allgemeinen Funktionen bietet und diverse Basisklassen zur Verfügung stellt. Die eigentlichen Implementierungen sind in eigenen Repositories zu finden und werden direkt in einen Unterordner des ausgecheckten Core Repositories eingebunden. Selbiger wird im Core Repository ignoriert, sodass es keine Probleme gibt. Eine kleine Datei verbindet dann die Basis mit den Implementierungen. Da dies ebenfalls einer der Kernpunkte meines Konzepts ist, wird es auch dazu noch einen weiterführenden Beitrag geben.

So viel zu den Ansätzen, meinen Entscheidungen für oder gegen bestimmte Konzepte und Techniken. Weitere Beiträge werden das Ganze wie erwähnt ergänzend aufarbeiten. Falls ihr Fragen habt, meldet euch gerne in den Kommentaren.

Kommentare  
Kommentar erstellen
Mit dem Abschicken des Kommentars erklären sie sich mit der in der Datenschutzerklärung dargelegten Datenerhebung für Kommentare einverstanden. Spam, unangebrachte Werbung und andere unerwünschte Inhalte werden entfernt. Das Abonnieren via E-Mail ist nur für E-Mail Adressen erlaubt die Sie rechtmäßig administrieren. Widerrechtliche Abonnements werden entfernt.