Monolithen skalieren: Was Netflix und Prime Video wirklich zeigen

Horizontale Skalierung, modularer Monolith und Betrieb: wann eine einzelne Anwendung große Last trägt und wo ihre Grenzen liegen
Aktualisiert:
Abstract
- #Monolithen
- #Microservices
- #Skalierung
- #Softwarearchitektur
- #Netflix
- #Systemdesign
- #Performance
- #Architekturentscheidungen
- #DevOps
- #Cloud-Computing
- #Modularer Monolith
Ein Monolith skaliert besser als sein Ruf – solange Daten, Zustand und Releases im Griff sind
In Architekturrunden fällt der Satz immer wieder: „Ein Monolith skaliert nicht.“ Gemeint ist eine Anwendung, die als ein einziges Programm gebaut, getestet und ausgeliefert wird. Als Gegenmodell gelten Microservices, also viele kleine, getrennt betriebene Dienste, die über das Netzwerk miteinander sprechen. Und als Kronzeuge für dieses Gegenmodell wird fast immer Netflix genannt.
Gelegentlich kursiert auch die umgekehrte Lesart, Netflix setze im Kern heimlich auf Monolithen. Dafür gibt es keinen öffentlichen Beleg. Interessanter als die Frage, welches Unternehmen welches Lager stützt, ist eine andere: Unter welchen Bedingungen trägt eine einzelne Anwendung große Last – und wann stößt sie wirklich an Grenzen? Die Antwort fällt differenzierter aus, als beide Schlagworte vermuten lassen.
Wofür Netflix in der Architekturdebatte tatsächlich steht
Netflix gehört zu den bekanntesten Beispielen für eine Microservices-Architektur. Das Unternehmen hat seine Plattform ab etwa 2009 schrittweise aus dem eigenen Rechenzentrum in die Cloud von Amazon Web Services verlegt und dabei eine große monolithische Java-Anwendung in viele einzelne Dienste zerlegt. Anlass war laut Netflix ein schwerer Datenbankfehler im Jahr 2008, der den DVD-Versand tagelang lahmlegte. Den Abschluss der Cloud-Migration meldete das Unternehmen Anfang 2016.
Aus dieser Zeit stammen Werkzeuge, die die ganze Branche geprägt haben, etwa der Schutzschalter Hystrix oder der Dienstverzeichnis-Baustein Eureka. Hystrix wird seit 2018 nicht mehr aktiv weiterentwickelt; Netflix verwies damals auf neuere Ansätze wie Resilience4j. Auch das gehört zur Geschichte: Selbst ein Vorreiter baut seine Werkzeuge um, wenn sich die Anforderungen ändern.
Wichtig für die Einordnung ist der Kontext. Netflix bedient weltweit eine sehr große Zahl von Abonnenten und betreibt eine eigene Plattformorganisation. Microservices lösen dort vor allem ein Organisationsproblem: Viele Teams sollen unabhängig voneinander ausliefern können. Daraus abzuleiten, dass ein Webshop mit drei Entwicklern dieselbe Architektur braucht, ist ein Kurzschluss – ebenso wie der Umkehrschluss, Netflix beweise die Überlegenheit von Monolithen.
Was der Fall Prime Video zeigt – und was nicht
Ein tatsächlich dokumentierter Rückweg stammt von Amazon Prime Video. Im März 2023 beschrieb ein Team im Technikblog des Dienstes, wie es ein Werkzeug zur Überwachung der Audio- und Videoqualität umgebaut hatte. Die erste Fassung bestand aus verteilten Serverless-Komponenten, orchestriert mit AWS Step Functions; Zwischenergebnisse wurden in einem Objektspeicher abgelegt. Diese Konstruktion stieß bei vielen parallelen Videoströmen an Skalierungsgrenzen und verursachte hohe Kosten. Das Team führte die Komponenten in einem einzigen Prozess zusammen und gab an, die Infrastrukturkosten um über 90 Prozent gesenkt zu haben.
Der Bericht wurde vielfach als „Amazon kehrt zum Monolithen zurück“ zitiert. Das ist zu weit gegriffen. Betroffen war ein einzelnes Werkzeug, nicht die gesamte Plattform. Die neue Fassung lief außerdem weiterhin auf mehreren Instanzen in der Cloud. Die eigentliche Lehre ist eine andere: Wenn Komponenten große Datenmengen untereinander austauschen und ohnehin immer gemeinsam arbeiten, ist die Netzwerkgrenze zwischen ihnen teurer als ihr Nutzen.
Der ältere Fall des Datenintegrationsanbieters Segment, der 2018 eine Vielzahl kleiner Dienste wieder zusammenführte, weist in dieselbe Richtung. Wie sich solche Rückwege in die grundsätzliche Entscheidung zwischen beiden Architekturen einfügen, beschreibt der Beitrag Vom Monolithen zu Microservices: Wann sich der Umbau lohnt.
Warum ein Funktionsaufruf billiger ist als ein Netzwerkaufruf
Um zu verstehen, warum ein Monolith unter Last oft gut abschneidet, lohnt ein Blick auf die Kosten einer Dienstgrenze. Ruft ein Modul innerhalb derselben Anwendung ein anderes auf, ist das ein gewöhnlicher Funktionsaufruf im Arbeitsspeicher. Ruft ein Dienst einen anderen über das Netzwerk auf, kommen mehrere Schritte hinzu:
- Die Daten werden serialisiert, also etwa in JSON oder ein Binärformat umgewandelt, und auf der Gegenseite wieder eingelesen.
- Die Anfrage durchläuft Netzwerk, gegebenenfalls Verschlüsselung per TLS, Load Balancer und Proxy.
- Der Aufrufer braucht Zeitlimits, Wiederholungsversuche und eine Antwort auf die Frage, was bei einem Teilausfall passiert.
Jeder dieser Schritte ist für sich klein. Problematisch wird es, wenn eine einzige Nutzeranfrage eine Kette von Aufrufen auslöst. Angenommen, ein Onlineshop zeigt eine Produktseite an und fragt dafür nacheinander Preis-, Lager-, Bewertungs- und Empfehlungsdienst ab. Die Wartezeiten addieren sich, und die langsamste Antwort bestimmt die Gesamtdauer. In einem Monolithen erledigen dieselben Module ihre Arbeit im selben Prozess, oft mit einer einzigen Datenbankabfrage.
Hinzu kommt die Fehleranfälligkeit. Je mehr Dienste an einer Anfrage beteiligt sind, desto wahrscheinlicher ist, dass einer davon gerade langsam ist oder neu startet. Typische Fehler beim Schnitt solcher Dienste, darunter zu feingranulare und gesprächige Schnittstellen, behandelt der Beitrag Fünf typische Fehler bei der Einführung von Microservices.
Wie ein Monolith horizontal skaliert
Ein verbreiteter Irrtum ist, ein Monolith lasse sich nur vertikal skalieren, also durch einen größeren Server. Tatsächlich lässt sich auch eine einzelne Anwendung horizontal skalieren: Mehrere identische Kopien laufen parallel, ein Load Balancer verteilt die Anfragen.
┌──────────────┐
Anfragen ──────▶│ Load Balancer│
└──────┬───────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
[Instanz 1] [Instanz 2] [Instanz 3] (gleicher Code)
│ │ │
└──────┬───────┴──────┬───────┘
▼ ▼
[Datenbank] [Cache / Sitzungen]
Damit das funktioniert, muss die Anwendung zustandslos sein. Keine Instanz darf sich etwas merken, das eine andere Instanz bei der nächsten Anfrage braucht. Sitzungsdaten, hochgeladene Dateien und Zwischenergebnisse gehören in gemeinsam genutzte Dienste wie eine Datenbank, einen Cache oder einen Objektspeicher. Wer heute noch Sitzungen im Arbeitsspeicher des Servers hält, sollte das als Erstes ändern.
In Container-Umgebungen wie Kubernetes übernimmt die Plattform das Hoch- und Herunterfahren der Instanzen automatisch. Ein Beispiel für eine solche Regel, die bei hoher Prozessorlast weitere Kopien startet:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: shop-monolith
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: shop-monolith
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Die Regel unterscheidet nicht zwischen Monolith und Microservice. Wie Container und Orchestrierung grundsätzlich funktionieren, erklärt der Beitrag Kubernetes erklärt: Container-Orchestrierung für Einsteiger.
Ein weiterer, oft übersehener Kniff: Derselbe Code kann in verschiedenen Rollen starten. Angenommen, ein Onlineshop verschickt nachts Tausende Rechnungen. Statt dafür einen eigenen Dienst zu bauen, startet dieselbe Anwendung zusätzlich als Hintergrundarbeiter, der nur Aufträge aus einer Warteschlange abarbeitet. Webinstanzen und Arbeiter lassen sich dann getrennt skalieren, obwohl es nur eine Codebasis und ein Build-Artefakt gibt.
Wo die Grenzen eines Monolithen wirklich liegen
Horizontale Skalierung verschiebt den Engpass, sie beseitigt ihn nicht. In der Praxis stößt ein Monolith meist an drei Stellen an Grenzen.
Die gemeinsame Datenbank
Zwanzig Instanzen der Anwendung teilen sich in der Regel eine Datenbank. Irgendwann sind es nicht mehr die Anwendungsserver, sondern Abfragen, Sperren und Verbindungen, die bremsen. Die üblichen Gegenmittel sind Indizes und optimierte Abfragen, ein Cache für häufig gelesene Daten, Lesereplikate für Auswertungen und ein Verbindungspool, der die Zahl offener Verbindungen begrenzt. Erst wenn das ausgereizt ist, wird eine Aufteilung der Daten nötig. Microservices lösen dieses Problem übrigens nicht automatisch: Teilen sich mehrere Dienste dieselbe Datenbank, besteht derselbe Engpass weiter.
Sehr unterschiedliche Lastprofile
Benötigt ein kleiner Teil der Anwendung ein Vielfaches an Rechenleistung oder Speicher, etwa eine Bildverarbeitung oder ein Modell für Produktempfehlungen, muss bei einem Monolithen jede Instanz entsprechend groß dimensioniert werden. Hier kann es sich lohnen, genau diesen Teil herauszulösen. Das ist ein klassischer, gut begründeter Fall für einen eigenen Dienst.
Der gemeinsame Release-Takt
Je mehr Teams am selben Code arbeiten, desto häufiger warten sie aufeinander. Ein Fehler in einem Modul blockiert die Auslieferung aller anderen. Diese Grenze ist organisatorisch, nicht technisch, und sie ist der häufigste ernsthafte Grund für eine Aufteilung.
Der modulare Monolith: Struktur ohne Netzwerkgrenze
Viele Probleme, die man klassischen Monolithen zuschreibt, haben weniger mit der Auslieferung als Ganzes zu tun als mit fehlender innerer Ordnung. Ein modularer Monolith setzt genau dort an: Die Anwendung bleibt ein Programm, ist aber in fachliche Module gegliedert, die nur über definierte Schnittstellen miteinander sprechen und ihre Daten nicht teilen.
Für die Skalierung hat das zwei Vorteile. Erstens bleiben Aufrufe zwischen Modulen schnell, weil sie im selben Prozess stattfinden. Zweitens lässt sich ein Modul, das später tatsächlich eigene Ressourcen braucht, mit vertretbarem Aufwand herauslösen, weil seine Grenze schon gezogen ist. Für einige Plattformen gibt es Hilfsmittel, die solche Grenzen prüfen, etwa Spring Modulith für Java-Anwendungen mit Spring Boot oder Packwerk, ein Werkzeug von Shopify für Ruby-on-Rails-Projekte. Shopify hat öffentlich beschrieben, dass es seine große Rails-Anwendung als modularen Monolithen weiterentwickelt.
Ein verwandter Ansatz sind Self-Contained Systems, bei denen jedes Teilsystem eine eigene Oberfläche mitbringt. Den Vergleich zieht der Beitrag Self-Contained Systems vs. Microservices.
Betrieb: Ausliefern, Beobachten, Ausfälle begrenzen
Auch beim Betrieb unterscheidet sich ein gut gebauter Monolith weniger von einer Dienstlandschaft, als oft angenommen wird. Die bewährten Verfahren gelten für beide.
- Risikoarme Auslieferung: Bei Blue-Green-Deployments läuft die neue Version parallel zur alten, und der Verkehr wird erst nach erfolgreichen Tests umgeschaltet. Bei Canary-Releases erhält zunächst nur ein kleiner Teil der Nutzer die neue Version.
- Feature Flags: Neue Funktionen werden zwar ausgeliefert, aber erst per Schalter aktiviert. So können mehrere Teams Code zusammenführen, ohne dass unfertige Funktionen sichtbar werden.
- Observability: Metriken, Logs und Traces zeigen, welcher Teil einer Anfrage Zeit kostet. Im Monolithen ist das einfacher, weil weniger Netzwerkgrenzen zu verfolgen sind. Der herstellerneutrale Standard OpenTelemetry lässt sich ebenso gut für eine einzelne Anwendung nutzen.
- Ausfälle begrenzen: Ein Speicherleck oder eine Endlosschleife in einem Modul kann die ganze Instanz treffen. Gegenmittel sind Zeitlimits, getrennte Thread-Pools für riskante Aufgaben und genug Instanzen, damit ein Absturz nicht auffällt.
Gerade beim letzten Punkt haben Microservices einen echten Vorteil: Ein abstürzender Dienst reißt die anderen nicht zwangsläufig mit. Dieser Vorteil zeigt sich allerdings nur, wenn die Dienste sauber voneinander entkoppelt sind und Ausfälle gezielt abfangen.
Was das für Ihr Team bedeutet
Die Frage „Monolith oder Microservices?“ ist für die Skalierung meist die falsche Einstiegsfrage. Wichtiger ist, ob die Anwendung zustandslos läuft, ob die Datenbank im Griff ist und ob der Code eine klare innere Ordnung hat. Ein sauber gebauter Monolith auf mehreren Instanzen kann erhebliche Last tragen, und das mit deutlich weniger Betriebsaufwand als eine verteilte Dienstlandschaft. Ob die eigene Anwendung dabei an Grenzen stößt, zeigen Lasttests und Messwerte, nicht die Architekturwahl allein.
Unsere Einschätzung: Überschätzt wird die technische Skalierbarkeit von Microservices, unterschätzt wird ihr Preis bei Latenz, Fehlersuche und Betrieb. Einen eigenen Dienst sollten Sie dann herauslösen, wenn ein Teil der Anwendung ein deutlich anderes Lastprofil hat oder wenn mehrere Teams sich beim Ausliefern dauerhaft gegenseitig blockieren. Die Fälle Prime Video und Segment zeigen zudem, dass der Weg auch zurück führen darf, sobald Dienste ohnehin nur gemeinsam funktionieren.
Wer die Skalierung einer bestehenden Anwendung untersuchen oder eine Architekturentscheidung vorbereiten möchte, findet auf der Themenseite zu Microservices: Beratung, Coaching und Seminare passende Formate, vom Architektur-Review bis zur Schulung für Entwicklungsteams.
Häufige Fragen zur Skalierung von Monolithen
Kann ein Monolith in der Cloud automatisch skalieren?
Ja. Läuft die Anwendung zustandslos in Containern oder auf virtuellen Maschinen, startet die Plattform bei steigender Last weitere Instanzen und fährt sie danach wieder herunter. Voraussetzung ist, dass Sitzungen, Dateien und Zwischenstände außerhalb der einzelnen Instanz liegen.
Woran lässt sich erkennen, dass ein Monolith an seine Grenzen kommt?
Typische Anzeichen sind eine Datenbank, die trotz optimierter Abfragen dauerhaft ausgelastet ist, einzelne Funktionen, die ein Vielfaches an Ressourcen benötigen, und Teams, die regelmäßig aufeinander warten müssen, bevor sie ausliefern können. Langsame Seiten allein sind dagegen meist ein Hinweis auf fehlende Indizes, Caches oder ineffiziente Abfragen.
Sind Microservices automatisch schneller, weil sie parallel arbeiten?
Nein. Parallelität entsteht durch mehrere Instanzen, nicht durch die Aufteilung in Dienste. Jeder zusätzliche Netzwerkaufruf kostet Zeit. Microservices können schneller sein, wenn ein rechenintensiver Teil gezielt mehr Ressourcen erhält oder wenn Aufgaben asynchron im Hintergrund laufen.
Ist ein modularer Monolith nur eine Übergangslösung?
Nicht zwingend. Für viele Anwendungen ist er die dauerhaft passende Form. Er hält aber die Option offen, später einzelne Module als eigene Dienste auszugliedern, wenn es dafür einen messbaren Grund gibt.