Als ich angefangen habe, war unser System ein dicker, fetter Monolith. So ein richtig schwerfälliger Koloss, der sich nur mit viel Mühe bewegen liess. Klar, einige mutige Seelen hatten schon versucht, ein paar Teile herauszulösen, aber so richtig durchgezogen wurde das nicht.
Schöne neue Welt – oder doch nicht? Link zu Überschrift
Ein halbes Jahr nach meinem Start kam die Idee auf, viele Teile der Entwicklung nach Indien auszulagern. Und mit “viele Teile” meinte man auch gleich die gesamte Architektur. Spoiler: Das ging ordentlich schief.
Als Plan B wurde mir dann die Aufgabe übertragen, zwei grosse Bestandteile aus der Applikation herauszulösen. Damit das “einfach” bleibt, entschieden wir uns, die bestehende Layered Architecture horizontal zu spalten. Ja, im Nachhinein eine eher dämliche Idee, aber man lernt ja dazu.
So sah das Ganze dann aus: Link zu Überschrift
Cockpit:
- Service
- Web (Frontend)
- Web & App (Gateway)
- Security
- Error Handling
- Config (Security & Web)
Algo-v3:
- Service
- “Microservice” für alle Planungsaufgaben
- Simulation
Core-lib:
- Java Library
- Services-Layer
- Default Config
- Externe Schnittstellen (Twilio, Stream, GCP, etc.)
- Utils/Helper
Domain:
- Java Library
- Mapping eines Modells auf eine Datenquelle
- Datenabfragen
- Durchsetzen von Regeln (String-Länge, Pflichtfelder, Standardwerte, etc.)
Skalierung & Resilienz Link zu Überschrift
Ein Hauptgrund für die Auftrennung war natürlich die Skalierung. Denn einfach nur mehr RAM und CPU draufzuhauen war nicht die eleganteste Lösung. Also: Horizontal skalieren!
Problem: Die Applikation hatte ein internes Scheduling. Heisst: Mehr Instanzen führten nicht zu Lastverteilung, sondern nur zu mehr Chaos.
Lösung: Scheduling raus und in den GCP Cloud Scheduler packen. Jetzt konnte die Applikation mehrfach laufen, aber trotzdem landete die gesamte Last nur auf einer Instanz – dumm gelaufen. Nächster Schritt: Geschedulte Jobs pro Tenant in eine Queue (GCP PubSub) packen und von den Instanzen abonnieren lassen. Zack, Last verteilt.
Nice Job! Einfach, pragmatisch, funktioniert.
Microservices? Link zu Überschrift
Yeah, wir haben jetzt eine Microservice-Architektur! Oder? Naja, schnell kamen noch ein paar weitere Services dazu – einer für Notifications, einer für IoT-Daten… Und was passierte? Microservices-Explosion!
- Kaum managebar für unser kleines Team
- Wildwuchs an Services, die keiner mehr überblicken könnte
Microservices 2.0 – Regeln müssen her Link zu Überschrift
Also: Wann sollten wir einen Service splitten?
Allgemeine Gründe: Link zu Überschrift
- Technologie-Heterogenität
- Resilienz
- Skalierung
- Deployment-Erleichterung
- Organisatorische Ausrichtung
- Ersetzbarkeit
Unsere Gründe: Link zu Überschrift
- Skalierbarkeit: Grosse Services sind schwer zu managen und zu skalieren. Kleinere Services können gezielt optimiert werden.
- Resilienz: Kritische Services müssen robust und ausfallsicher sein.
- Wartung: Kleinere Services sind einfacher zu warten und weiterzuentwickeln.
Domain-Driven Design (DDD) – Struktur, aber mit Hirn Link zu Überschrift
Wir wollen sauberen Code mit klaren Grenzen. Aber nicht alles muss ein eigener Service sein. Also: DDD!
Ein Service sollte klar definierte Inhalte haben, und diese sollten gut gekapselt sein.
Also: Brainstorming! Welche Domains gibt es? Wie passen sie zusammen? Wo ziehen wir die Grenzen?
Wunscharchitecture Link zu Überschrift
Aus diesem Prozess entstand eine neue Architektur mit zwei Hauptservices:
- EconomicEntityService: Enthält Themen wie IoT, Billing, Dokumente und weitere allgemeine Domains.
- CleaningService: Beinhaltet Touren, Kalender, Flächentypen und alles, was reinigungsspezifisch ist.
Zusätzlich gibt es einige Applikationen, die über den Gateway auf diese Services zugreifen, einen Auth-Service, einige kleinere Helfer-Services sowie die Planungs- und Simulationsservices, die als Worker laufen sollen.
Umsetzung – Theorie vs. Praxis Link zu Überschrift
So einfach das Zeichnen von schönen Diagrammen war, so schwierig wurde die Umsetzung.
Kaum begannen wir, die ersten Domains zu verschieben, wurde klar: Der Code war Chaos.
- Domain Layer & Service Layer? Wild verknüpft.
- Entities? Reihenweise ineinander verschachtelt.
Also: Viel Arbeit, viel Frust – und ein ernüchterndes Ergebnis.
Dann kam noch die Teamverschlankung (Indien wieder raus). Und das Thema? Erstmal auf Eis gelegt…