Gute Plattformen entstehen nicht durch mehr Infrastruktur
Warum die eigentliche Herausforderung moderner Plattformen nicht in zusätzlichen Komponenten, sondern in klaren Verantwortlichkeiten liegt.
Betrachten wir für einen Moment, wie sich moderne Plattformen in den vergangenen fünfzehn Jahren entwickelt haben. Nahezu jede größere Innovation hatte dasselbe Ziel: Komplexität zu reduzieren. Virtuelle Maschinen entkoppelten Anwendungen von physischer Hardware. Container entkoppelten Anwendungen vom Betriebssystem. Kubernetes entkoppelte Workloads von einzelnen Hosts. GitOps entkoppelte Infrastruktur von manuellen Prozessen. Service Meshes abstrahierten Netzwerkkommunikation innerhalb eines Clusters, während Infrastructure as Code schließlich den Anspruch formulierte, selbst hochkomplexe Plattformen vollständig deklarativ beschreiben zu können. Rückblickend betrachtet lässt sich diese Entwicklung beinahe als fortlaufende Suche nach einer besseren Abstraktion verstehen. Interessanterweise beobachten wir auf der Netzwerkseite häufig genau das Gegenteil. Mit jeder neuen Anforderung entstand eine weitere Komponente. Ein DNS-System. Ein Layer-4-Loadbalancer. Ein Layer-7-Proxy. Eine Web Application Firewall. DDoS-Mitigation. Bot Protection. API Gateways. Rate Limiting. Traffic Analytics. Health Checks. TLS-Offloading. Keines dieser Systeme entstand aus Selbstzweck. Jedes löste ein reales Problem. Und genau deshalb existieren sie heute alle nebeneinander. Vielleicht liegt genau darin jedoch eine Entwicklung, die wir im Alltag erstaunlich selten hinterfragen.
Je größer eine Plattform wird, desto stärker entsteht die Versuchung, neue Anforderungen einfach durch weitere Komponenten zu lösen. Benötigen wir API-Authentifizierung? Dann stellen wir ein API Gateway davor. Benötigen wir Schutz vor Layer-7-Angriffen? Dann ergänzen wir eine Web Application Firewall. Müssen Zertifikate automatisch erneuert werden? Dann integrieren wir einen ACME-Client. Jede Entscheidung für sich erscheint vollkommen nachvollziehbar. Mit der Zeit entsteht daraus jedoch eine Architektur, deren eigentliche Komplexität längst nicht mehr in den einzelnen Komponenten liegt, sondern in ihren Übergängen. Vielleicht beschreibt genau dieser Gedanke eines der grundlegendsten Probleme moderner Plattformen. Nicht die Anzahl der Systeme wächst. Sondern die Anzahl ihrer gegenseitigen Abhängigkeiten.
Nehmen wir als Beispiel einen scheinbar einfachen Request.
Browser
│
▼
DNS
│
▼
Edge
│
▼
TLS
│
▼
WAF
│
▼
Layer 7
│
▼
Ingress
│
▼
Kubernetes
│
▼
Application
Dieses Diagramm wirkt auf den ersten Blick linear. Tatsächlich existieren zwischen nahezu allen Komponenten zusätzliche Informationsflüsse. Die Web Application Firewall benötigt Informationen darüber, welche Anwendungen überhaupt existieren. Der Layer-7-Proxy muss Zertifikate kennen. Health Checks benötigen Informationen über den Zustand von Backends. Das Routing muss wissen, welche Standorte produktiv sind. Monitoring wiederum möchte sämtliche dieser Informationen korrelieren, obwohl sie aus vollkommen unterschiedlichen Systemen stammen. Aus einer Kette entsteht damit schrittweise ein Graph. Und genau dort beginnt die eigentliche Komplexität.
Vielleicht lohnt sich deshalb ein Blick auf ein Prinzip, das sich nicht nur in der Softwareentwicklung, sondern auch in der Architektur verteilter Systeme immer wieder bewährt hat.
Gute Systeme entstehen selten dadurch, dass sie möglichst viele Probleme gleichzeitig lösen.
Gute Systeme entstehen dadurch, dass jedes Teilsystem genau ein Problem löst.
Diese Aussage klingt beinahe banal. Ihre Konsequenzen sind jedoch erheblich. Ein Routingprotokoll sollte Routingprobleme lösen. Nicht Authentifizierung. Eine Web Application Firewall sollte HTTP analysieren. Nicht Kubernetes orchestrieren. Ein Kubernetes-Cluster sollte Container planen. Nicht globale Netzwerkpfade berechnen. Sobald einzelne Komponenten beginnen, Verantwortlichkeiten anderer Systeme zu übernehmen, entstehen Abhängigkeiten, die häufig deutlich schwieriger zu verstehen sind als die ursprünglichen Probleme selbst.
Diese Überlegung lässt sich erstaunlich gut auf moderne Edge-Plattformen übertragen. Oft entsteht der Eindruck, Edge-Infrastruktur sei besonders komplex, weil sie besonders viele Funktionen bereitstellt. Tatsächlich entsteht ihre Komplexität häufig aus einem anderen Grund. Sie befindet sich an der Schnittstelle nahezu aller anderen Systeme. Sie kennt DNS. Sie kennt Routing. Sie terminiert TLS. Sie bewertet HTTP. Sie verteilt Traffic. Sie kennt den Gesundheitszustand von Backends. Und dennoch sollte sie möglichst wenig über die eigentliche Anwendung wissen. Gerade diese Trennung entscheidet darüber, ob eine Plattform langfristig beherrschbar bleibt.
Betrachten wir dieselbe Architektur deshalb einmal nicht aus Sicht einzelner Produkte, sondern aus Sicht ihrer Verantwortlichkeiten.
+--------------------------------------------------+
| Edge Platform |
+--------------------------------------------------+
- Verbindung annehmen
- Netzwerkpfad bestimmen
- TLS terminieren
- Requests validieren
- Traffic verteilen
- Gesunde Backends auswählen
│
▼
+--------------------------------------------------+
| Compute Platform |
+--------------------------------------------------+
- Container ausführen
- Anwendungen skalieren
- Services orchestrieren
- Daten verarbeiten
- Business Logic bereitstellen
Interessanterweise verschwindet in diesem Diagramm nahezu jede Produktbezeichnung. Nicht weil Produkte unwichtig wären. Sondern weil sie lediglich Implementierungen einer Verantwortung darstellen. Ob Layer-7-Routing durch HAProxy, Envoy oder NGINX erfolgt, verändert die Architektur kaum. Ob Kubernetes mit containerd oder CRI-O arbeitet, ebenfalls nicht. Architektur beginnt dort, wo Verantwortlichkeiten definiert werden. Nicht dort, wo Produkte ausgewählt werden.
Vielleicht erklärt genau das auch, weshalb sich Plattformen häufig deutlich langlebiger entwickeln als einzelne Technologien. Produkte ändern sich. Protokolle entwickeln sich weiter. Neue Software ersetzt alte. Verantwortlichkeiten bleiben dagegen erstaunlich konstant. Eine Plattform muss auch in zehn Jahren noch Verbindungen annehmen. Traffic verteilen. Anwendungen ausführen. Daten speichern. Beobachtbarkeit ermöglichen. Die konkrete Umsetzung mag sich verändern. Die Architektur dahinter dagegen erstaunlich selten.
Diese Erkenntnis verändert auch die Art und Weise, wie wir Infrastruktur bewerten. Nicht mehr die Frage, "Welche Software verwenden wir?" steht im Mittelpunkt. Sondern eine andere. "Welche Verantwortung besitzt dieses System – und verfügt es tatsächlich über alle Informationen, die notwendig sind, um genau diese Verantwortung zuverlässig wahrzunehmen?" Vielleicht ist genau das die eigentliche Definition guter Plattformarchitektur. Nicht möglichst viele Funktionen. Nicht möglichst viele Produkte. Sondern möglichst klare Grenzen. Denn Plattformen werden nicht dadurch wartbar, dass sie weniger Komponenten besitzen. Sie werden wartbar, weil jede Komponente genau weiß, welches Problem sie lösen soll. Und welches bewusst nicht.