Grundlagen

Microservices und Monolith

Ein großes Programm oder viele kleine? Was Microservices wirklich versprechen, was sie kosten, warum der Schnitt wichtiger ist als die Größe – und warum der modulare Monolith für die meisten Teams der bessere Anfang ist.

Lesestand

Ein Monolith ist eine Anwendung, die als Ganzes gebaut und ausgeliefert wird – ein Prozess, eine Datenbank. Microservices zerlegen sie in viele kleine Dienste, die jeweils einen fachlichen Bereich verantworten, ihre eigenen Daten besitzen, unabhängig ausgeliefert werden und über das Netz miteinander reden.

Der eigentliche Nutzen ist organisatorisch: Viele Teams können unabhängig voneinander arbeiten und ausliefern. Der Preis ist technisch: Aus Methodenaufrufen werden Netzwerkaufrufe, aus Transaktionen verteilte Abläufe, aus einem Prozess Dutzende, die überwacht werden müssen. Für kleine Teams überwiegt meist der Preis. Ein gut gegliederter modularer Monolith bietet viel vom Nutzen ohne die Kosten – und lässt sich später entlang seiner Module aufteilen.

Was ein Aufruf über das Netz kostet

Im Monolithen ruft der Bestellcode den Lagercode einfach auf – ein Methodenaufruf, ein paar Nanosekunden, und er schlägt nie fehl, weil das Netz hakt. Bei Microservices wird daraus ein HTTP- oder gRPC-Aufruf. Stell eine Aufrufkette zusammen:

Eine Anfrage durch die Architektur
Dienste in der Aufrufkette

Annahmen: Ein Aufruf innerhalb des Rechenzentrums kostet samt Serialisierung etwa 2 ms; jeder Dienst ist zu 99,9 % verfügbar. Methodenaufrufe im selben Prozess: Nanosekunden, praktisch immer verfügbar.

Daraus folgt eine Grundregel: Dienste sollten so geschnitten sein, dass eine typische Anfrage wenige von ihnen braucht – idealerweise einen. Und lange synchrone Ketten löst man, wo es geht, durch Ereignisse auf.

Was man gewinnt, was man bezahlt

MonolithMicroservices
Ausliefernalles zusammen; eine Änderung, ein Releasejeder Dienst einzeln, ohne die anderen
Skalierendas Ganze mehrfach startennur die Teile, die Last haben
Teamsalle im selben Code, Abstimmung nötigjedes Team besitzt seine Dienste
Fehlerein Speicherleck reißt alles mitAusfälle bleiben eher lokal – wenn man sie abfängt
Konsistenzeine Datenbank, echte Transaktionenverteilte Daten, Sagas, Eventual Consistency
Fehlersucheein Stacktrace, ein Logverteiltes Tracing über viele Dienste nötig
Betriebein Prozess, eine PipelineDutzende Pipelines, Container-Orchestrierung, Service-Netz
UmbauenRefactoring mit der IDE über alles hinwegSchnittstellen zwischen Teams verhandeln und versionieren

Zwei Regeln trennen gute von schlechten Microservice-Architekturen. Erstens: Jeder Dienst besitzt seine Daten. Teilen sich zwei Dienste eine Datenbanktabelle, sind sie nicht unabhängig – eine Spaltenänderung bricht beide. Zweitens: Der Schnitt folgt der Fachlichkeit, nicht der Technik. Was das bedeutet, zeigt das nächste Beispiel.

Wo schneidet man?

Ein Online-Shop soll in drei Dienste zerlegt werden. Zwei Vorschläge liegen auf dem Tisch. Wähle einen – und dann eine typische Änderung, wie sie jede Woche vorkommt:

Zwei Schnitte, dieselbe Änderung
Schnitt
Änderung

Der technische Schnitt erzeugt einen verteilten Monolithen: alle Nachteile verteilter Systeme, aber keiner der Vorteile – denn jede Änderung erfordert, dass alle Dienste gemeinsam geändert und ausgeliefert werden. Der fachliche Schnitt folgt dem, was im Domain-Driven Design Bounded Context heißt: ein Bereich, in dem Begriffe eine eindeutige Bedeutung haben. „Kunde“ bedeutet im Versand eine Lieferadresse, in der Buchhaltung eine Zahlungshistorie – das sind zwei verschiedene Modelle, und sie dürfen in zwei Diensten verschieden aussehen.

Conways Gesetz

Schon 1968 formulierte Melvin Conway eine Beobachtung, die heute ein Gesetz heißt: Organisationen bauen Systeme, deren Struktur ihre Kommunikationsstruktur abbildet. Drei Teams bauen drei Komponenten – ob die Fachlichkeit das hergibt oder nicht. Daraus folgt umgekehrt: Wer eine bestimmte Architektur will, muss die Teams passend zuschneiden. Microservices ohne Teams, die jeweils einen Dienst wirklich besitzen, liefern selten ihr Versprechen.

Der Mittelweg: modularer Monolith

Ein modularer Monolith wird als ein Programm ausgeliefert, ist innen aber in klar getrennte Module gegliedert – nach denselben fachlichen Grenzen, die man Microservices geben würde. Module greifen nicht in die Interna der anderen, kommunizieren über definierte Schnittstellen oder Ereignisse und besitzen ihre eigenen Tabellen. Man bekommt klare Struktur, unabhängiges Arbeiten im Code und eine spätere Aufteilung ohne große Umbauten – aber Methodenaufrufe, eine Transaktion und einen Prozess.

Viele bekannte Architekten raten deshalb: erst Monolith, dann aufteilen – wenn die fachlichen Grenzen sich bewährt haben und ein konkreter Grund vorliegt. Für den Weg dahin gibt es das Strangler-Fig-Muster, benannt nach einer Würgefeige: Neue Funktionen entstehen als eigener Dienst neben dem Monolithen, ein Proxy leitet Schritt für Schritt Anfragen um, bis der alte Teil abgeschaltet werden kann.

Braucht ihr Microservices?

Eine grobe Faustregel, keine Entscheidung.

Für Entwickler übersetzt

// Spring Modulith: Pakete direkt unter der Hauptklasse sind Module –
// dieser Test schlägt fehl, sobald ein Modul in die Interna eines anderen greift
@Test
void modulgrenzenEingehalten() {
    ApplicationModules.of(ShopApplication.class).verify();
}

// Module reden über Ereignisse statt über direkte Aufrufe
@Service
class BestellService {
    private final ApplicationEventPublisher events;
    @Transactional
    void aufgeben(Bestellung b) {
        repo.save(b);
        events.publishEvent(new BestellungAufgegeben(b.id()));
    }
}

// im Modul "lager" – läuft nach dem Commit, eigene Transaktion
@ApplicationModuleListener
void beiBestellung(BestellungAufgegeben e) { reservierung.reserviere(e.bestellId()); }
WerkzeugWofür
Spring ModulithModule im Monolithen prüfen, dokumentieren, mit Ereignissen verbinden – und später leicht herauslösen
ArchUnitArchitekturregeln als Tests, auch ohne Spring
Java-Module (JPMS)Grenzen auf Sprachebene: exports legt fest, was ein Modul nach außen zeigt
VertragstestsPact oder Spring Cloud Contract: prüfen, dass Dienste die Erwartungen ihrer Aufrufer erfüllen – ohne alles gemeinsam zu starten
OpenTelemetryverteiltes Tracing – ohne das sind Fehler in Microservices kaum zu finden (siehe Observability)

Häufige Irrtümer

„Microservices sind die moderne Architektur, Monolithen sind veraltet.“ – Beides sind Werkzeuge mit Kosten. Viele erfolgreiche Produkte laufen als gut gegliederter Monolith, und manche Firmen sind von Microservices bewusst zurückgegangen.
„Micro heißt: wenige Zeilen Code.“ – Die Größe ist zweitrangig. Entscheidend ist, dass ein Dienst einen fachlichen Bereich vollständig abdeckt und unabhängig geändert werden kann.
„Die Dienste können sich ruhig eine Datenbank teilen.“ – Dann sind sie über das Schema gekoppelt und nicht mehr unabhängig. Geteilte Datenbanken sind das häufigste Merkmal eines verteilten Monolithen.
„Aufteilen können wir später immer noch.“ – Stimmt nur, wenn der Monolith innen sauber gegliedert ist. Ein verflochtener Monolith lässt sich kaum zerlegen – deshalb lohnen sich Modulgrenzen von Anfang an.
„Jeder Dienst sollte die beste Technik für sein Problem wählen.“ – Theoretisch. Praktisch bedeuten fünf Sprachen und vier Datenbanken fünfmal so viel Betriebswissen. Die meisten Organisationen beschränken sich bewusst.

Verwandte Begriffe