Zwei Verkehrsrichtungen, eine Box
Willkommen
Die meisten Architekturdiagramme zeigen Verkehr in eine Richtung: Client oben, Server unten, Pfeil zeigt nach unten. In der Realität fließt der Verkehr in beide Richtungen.
Ingress: Externe Clients erreichen Ihre Dienste über diesen Pfad. Ein Reverse-Proxy am Rand Ihres Netzwerks beendet TLS, leitet Anfragen weiter und durchsetzt die Zugriffsrichtlinie.
Egress: Ihre Dienste erreichen externe Dienste über diesen Pfad. Aufruf der API eines Zahlungsanbieters, Abruf eines Webhook-Ziels, Senden einer Anfrage an einen Partner. Oft über einen Forward-Proxy oder ein NAT-Gateway mit einer Erlaubnisliste.
Viele Architekturen beginnen mit einer einzigen Instanz, die beide Richtungen abwickelt. Das funktioniert, bis der Tag kommt, an dem es nicht mehr funktioniert. Das Fehlerbild ist subtil, zeigt sich erst, wenn genügend interne Dienste vorhanden sind, & vermittelt eine wichtige Lektion zur Trennung der Zuständigkeiten.
Am Ende dieser Lektion werden Sie verstehen:
- Warum Ingress & Egress grundlegend unterschiedliche Verkehrsmuster mit unterschiedlichen Skalierungsachsen & unterschiedlichen Fehlerbildern darstellen
- Hairpin NAT & warum ein Proxy, der versucht, sich selbst zu verbinden, fehlschlägt
- Die architektonische Gabelung: Aus einer Instanz werden zwei, & was jede davon dann ausschließlich übernimmt
- Gewinne durch Sicherheitsisolierung: Jede Seite kann sich auf ihre tatsächlich erlaubten Peers beschränken
- Wie Sie erkennen, wann Ihr Design mit einer einzelnen Instanz die Schwelle überschritten hat, ab der die Aufteilung notwendig ist
Warum die Richtungen unterschiedliche Werkzeuge erfordern
Zwei unterschiedliche Arbeitslasten an einer Netzwerk-Grenze
Eigenschaften des eingehenden Verkehrs (Ingress):
- Initiiert durch externe Parteien (das Internet im Allgemeinen)
- Das Volumen skaliert mit Ihrer Benutzerbasis
- TLS-Terminierung, Anfrage-Routing, Ratenbegrenzung pro Quelle
- Belange der Verteidigung in mehreren Ebenen: DDoS, Missbrauch, Scraping
- Die öffentliche IP-Adresse muss Verbindungen von jedermann akzeptieren
Eigenschaften des ausgehenden Verkehrs (Egress):
- Ausgelöst durch Ihre eigenen Dienste (eine bekannte, kleine Menge an Clients)
- Das Volumen skaliert mit Ihren Service-zu-Service- & externen API-Aufrufmustern
- Quell-IP-Whitelisting an den Remote-Endpunkten (Sie haben eine feste ausgehende IP, der Partner vertrauen)
- Bedenken zur Verteidigung in der Tiefe: Datenexfiltration, kompromittierte interne Dienste, die ausgehende Aufrufe tätigen
- Sollte Verbindungen von allen außer Ihren eigenen Diensten ablehnen
Die zentrale Asymmetrie: Ingress akzeptiert Traffic aus der ganzen Welt; Egress akzeptiert Traffic nur von Ihren eigenen Diensten. Wenn beide auf derselben Maschine laufen, muss diese Maschine gleichzeitig aus der ganzen Welt erreichbar sein (für Ingress) & nur von Ihren Diensten erreichbar sein (für Egress). Die Firewall-Regeln, die die eine Anforderung erfüllen, widersprechen der anderen.
Der Wachstumspfad: Ein kleines Projekt kann beide hinter einer IP & einem Tool verbergen, da das Volumen gering ist & die Partner-IP-Whitelist kurz ist. Wenn das Projekt wächst, nimmt die Reibung zwischen den beiden Rollen zu, & eines Tages erzwingt ein spezifisches Fehlerbild (Hairpin NAT) die Trennung.
Der Bug, der die Trennung erzwingt
Eine bereinigte Ausfallgeschichte
Stellen Sie sich eine reale architektonische Verzweigung vor, die in Produktivumgebungen auftritt. Die unten genannten Namen wurden geändert; die Struktur ist jedoch identisch mit dem, was Teams in der Praxis erleben.
Eine Organisation betreibt einen einzelnen Proxy-Server unter 203.0.113.5. Er verarbeitet den eingehenden Verkehr (Port 443 für Benutzer) und den ausgehenden Verkehr (Port 1080 SOCKS5 für interne Dienste, die ausgehende Aufrufe tätigen). Interne Dienste befinden sich in privaten Subnetzen und leiten den gesamten ausgehenden Verkehr über diesen SOCKS5-Proxy auf 203.0.113.5:1080 weiter.
Einer der Dienste, die hinter derselben IP 203.0.113.5 gehostet werden, ist api.example.com. Die öffentliche DNS-Auflösung weist api.example.com auf 203.0.113.5 hin.
Nun muss ein anderer interner Dienst api.example.com aufrufen. Sein ausgehender Pfad:
1. Der interne Dienst löst api.example.com auf → 203.0.113.5
2. Der interne Dienst sendet die Anfrage über den SOCKS5-Egress-Proxy auf 203.0.113.5:1080
3. Der Proxy versucht, eine Verbindung von sich selbst zu 203.0.113.5:443 herzustellen
4. Verbindung abgelehnt. Das Paket müsste das gleiche NAT verlassen und wieder betreten, was die meisten Netzwerk-Stacks ablehnen. Der Proxy kann nicht über seine eigene öffentliche IP-Adresse mit sich selbst verbinden.
Dies ist Hairpin-NAT: ein Paket, das ein NAT verlässt und dasselbe NAT erneut betreten muss, um sein Ziel zu erreichen. Ohne spezielle Hairpin-Unterstützung in der Routing-Ebene wird das Paket verworfen.
Warum es spät auftritt
In der frühen Phase des Projekts kommunizierte jeder interne Dienst entweder mit anderen internen Diensten über private Hostnamen (internal-api.local) oder rief nicht in die eigenen öffentlichen Dienste der Organisation zurück. Der Hairpin-Pfad existierte schlicht nicht.
Dann erforderte eine neue Funktion, dass Dienst A api.example.com (einen öffentlichen Hostnamen) aufruft. Der Hairpin-Pfad wurde aktiviert. Verbindung abgelehnt. Ausfall.
Die Korrektur behandelte das Symptom (der Resolver wurde erzwungen, die private IP-Adresse von api.example.com anstelle der öffentlichen zu liefern). Die Ursache: Eine einzelne Maschine übernahm zu viele Aufgaben.
Die architektonische Gabelung
Ein Server wird zu zwei
Die saubere Lösung: Trennen Sie den Proxy in zwei Maschinen auf.
Ingress-Server (öffentliche IP 203.0.113.5):
- Caddy / Reverse Proxy auf den Ports 80, 443
- Öffentliche DNS-Einträge zeigen hierher
- Hostet api.example.com, app.example.com usw.
Egress-Server (andere öffentliche IP 203.0.113.99):
- SOCKS5 / Forward Proxy auf Port 1080
- Die Firewall beschränkt eingehende Verbindungen auf interne Subnetz-IPs
- Interne Dienste leiten alle ausgehenden Verbindungen über diese Adresse
Was man davon hat:
1. Hairpin gelöst. Ein interner Dienst, der api.example.com aufruft, leitet den ausgehenden Verkehr über 203.0.113.99 (Egress) um, der dann normal mit 203.0.113.5 (Ingress, eine andere IP) verbindet. Der NAT-Loop verschwindet, weil die beiden IPs auf verschiedenen Maschinen liegen.
2. Sicherheitsisolierung. Die Firewall des Egress-Servers kann auf eine kleine Menge interner IPs beschränkt werden. Die Firewall des Ingress-Servers bleibt für die Welt offen. Zwei separate Regelwerke, die jeweils eine Rolle klar ausdrücken.
3. Unabhängiges Skalieren. Ingress-Bandbreite skaliert mit Benutzern; Egress-Bandbreite skaliert mit der Aktivität interner Dienste. Man kann das eine hochskalieren, ohne das andere anzufassen.
4. Fehlerisolierung. Eine fehlerhafte Egress-Konfiguration bricht die öffentliche Website nicht mehr. Ein DDoS gegen die öffentliche Website erschöpft die Egress-Bandbreite nicht mehr.
5. Klareser mentales Modell. Jede Maschine hat eine Aufgabe. Ingenieure denken über Ingress-Belange nach, ohne an Egress zu denken, und umgekehrt.
Zwei Achsen, zwei Dimensionierungsentscheidungen
Unabhängige Skalierung
Vor der Trennung belastete das Wachstum in beide Richtungen dieselbe Maschine. Nach der Trennung verfügt jede Richtung über eine eigene Bereitstellung.
Größenbestimmung des Eingangs (Ingress): skaliert mit der Nutzerzahl. Kapazitätsentscheidungen liegen in der öffentlich zugänglichen Ebene (mehr Reverse-Proxy-Replikate, größere VMs, CDN im Frontend). Das Bandbreitenbudget wird auf Basis des Nutzerverkehrs zur Spitzenlast berechnet.
Größenbestimmung des Ausgangs (Egress): skaliert mit dem internen Volumen an Aufrufen externer APIs. Häufig dominiert durch die Zustellung von Webhooks, Aufrufe an Zahlungsanbieter oder das Abrufen von Daten von Drittanbietern. Das Bandbreitenbudget wird auf Basis der internen Aufrufmuster berechnet.
Isolierung von Ausfällen: Ein DDoS-Angriff auf den öffentlichen Eingang verbraucht nicht mehr die Ausgangsbandbreite (die Aufrufe an den Zahlungsanbieter werden ohnehin durchgeführt). Ein Absturz des Ausgangs-Proxys bringt die öffentliche Website nicht mehr zum Erliegen (Nutzer erreichen die Website weiterhin; nur interne ausgehende Aufrufe schlagen fehl).
Unterschiedliche SLOs: Die Verfügbarkeit des Eingangs ist für Nutzer relevant (sichtbarer Website-Ausfall); die Verfügbarkeit des Ausgangs ist für Betreiber relevant (Hintergrundausfälle, die möglicherweise länger dauern, bis sie erkannt werden). Jede Seite kann ihre eigenen SLOs tragen.
Mehrere Ausgangsserver
Sobald die Ausgangsrolle eine eigene Maschine ist, ist der nächste naheliegende Schritt, mehrere Ausgangsmaschinen hinter einem Lastausgleich für HA (High Availability) zu betreiben. Jeder neue interne Dienst zeigt auf den Ausgangs-Hostnamen (der auf den lastausgeglichenen Pool aufgelöst wird), anstatt auf eine einzelne IP-Adresse.
Gleiche Lektion wie bei verteilten Systemen: Sobald eine Ebene zustandslos ist und eine eigene Rolle hat, lässt sie sich kostengünstig skalieren.
Eine neue Partnerintegration
Deine Organisation betreibt die Ingress-/Egress-Trennung wie vorgesehen. Der Egress-Server hat eine feste öffentliche IP-Adresse (203.0.113.99), die du bei drei bestehenden Partner-APIs (einem Zahlungsprocessor, einem SMS-Gateway und einem E-Mail-Anbieter) auf der Whitelist eingetragen hast.
Ein Produktteam möchte eine vierte Integration hinzufügen: ein Webhook-Liefersystem, das Rückrufe an Endpunkte von Kunden weltweit auslöst. Prognose zum Datenvolumen: 10.000 Aufrufe pro Minute, mit Spitzenlasten bis zu 30.000.
Gestalten Sie eine Netzwerk-Grenze für einen wachsenden Dienst
Synthese
Sie haben gelernt, warum Ingress und Egress unterschiedliche Werkzeuge erfordern, den Hairpin-NAT-Ausfall, der die Trennung in realen Flotten erzwingt, und wie unabhängiges Skalieren, Sicherheitsisolierung und Fehlerisolierung erst mit der Umsetzung der Trennung eintreten.
Wenden Sie alle vier Punkte an.
Ein mittelgroßes SaaS-Unternehmen betreibt drei Produkt-Subdomains (app, api, admin) für seine Nutzer sowie vier ausgehende Integrationen (Stripe, Twilio, SendGrid, ein Kunden-Webhook-System). Aktuell befindet sich alles hinter einer einzelnen Proxy-Maschine mit einer öffentlichen IP-Adresse. Es gibt zunehmend Berichte über intermittierende Hairpin-Ausfälle, wenn interne Dienste versuchen, api.example.com aufzurufen. Sie möchten eine dauerhafte Lösung entwerfen.
Wohin dieser Kurs weiterführt
Wohin dieser Kurs weiterführt
Sie haben nun eine der saubersten Refactorings zur Trennung der Zuständigkeiten in verteilten Systemen gesehen: Aus einer Box werden zwei, jede mit einer klaren Rolle, und das System erbt dabei Vorteile in Bezug auf Skalierung, Sicherheit und Fehlerisolierung.
Die nächste Lektion (cs_distsys_failure_modes_and_blast_radius) erweitert die Überlegungen zur Fehlerisolierung. Du wirst einen bereinigten Postmortem-Bericht zu DNS-SERVFAIL-Fehlern lesen, das Muster der kaskadierenden Fehleridentifizierung erkennen und schuldzuweisungsfreie Maßnahmenpunkte formulieren, die sich auf Systeme statt auf Personen beziehen.
Begleitende Lektion: geometry_of_ingress_egress_separation betrachtet die Trennung als einen bipartiten Graphen und untersucht Schnittknoten, Netzwerkpartitionen sowie, was die Graphentheorie über eine Netzwerk-Grenze aussagt.
Gut gemacht. Weiter geht's.