Kapitel 4. Service Mesh:Dienst-zu-Dienst-Verkehrsmanagement

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Im vorangegangenen Kapitel hast du erfahren, wie du deine APIs offenlegst und den damit verbundenen Ingress-Verkehr von Endnutzern und anderen externen Systemen mithilfe eines API-Gateways zuverlässig, nachvollziehbar und sicher verwaltest. Jetzt lernst du, wie du den Verkehr für interne APIs, d. h. die Kommunikation von Dienst zu Dienst, mit ähnlichen Zielen verwalten kannst.

Grundsätzlich bieten Service-Mesh-Implementierungen Funktionen für das Routing, die Beobachtung und die Sicherung des Datenverkehrs für die Kommunikation zwischen den Diensten. Wie bei allen architektonischen Entscheidungen gibt es Kompromisse; es gibt kein kostenloses Mittagessen, wenn du die Rolle des Architekten spielst!

In diesem Kapitel wirst du die Fallstudie weiterentwickeln, indem du die Sitzungsverwaltungsfunktionalität aus dem alten Konferenzsystem in einen neuen, intern zugänglichen Sitzungsdienst extrahierst. Dabei lernst du die Kommunikationsherausforderungen kennen, die durch die Erstellung oder Extraktion neuer Dienste und APIs entstehen, die neben dem bestehenden monolithischen Konferenzsystem eingesetzt und ausgeführt werden. Alle API- und Verkehrsmanagementtechniken, die du im vorigen Kapitel kennengelernt hast, kommen hier zum Einsatz. Daher ist es naheliegend, ein API-Gateway zu verwenden, um den neuen Sitzungsdienst bereitzustellen. Angesichts der Anforderungen würde dies jedoch höchstwahrscheinlich zu einer suboptimalen Lösung führen. An dieser Stelle können das Service-Mesh-Pattern und die damit verbundenen Technologien eine Alternative darstellen.

Ist Service Mesh die einzige Lösung?

Praktisch muss jede webbasierte Softwareanwendung Service-zu-Service-ähnliche Aufrufe tätigen, selbst wenn es sich nur um eine monolithische Anwendung handelt, die mit einer Datenbank interagiert. Daher gibt es schon seit langem Lösungen, um diese Art der Kommunikation zu verwalten. Der gängigste Ansatz ist die Verwendung einer sprachspezifischen Bibliothek, z. B. einer Software Development Kit (SDK)-Bibliothek oder eines Datenbanktreibers. Diese Bibliotheken bilden anwendungsbasierte Aufrufe auf Service-API-Anfragen ab und verwalten auch den entsprechenden Datenverkehr, in der Regel über die Verwendung von HTTP- oder TCP/IP-Protokollen. Mit der Umstellung moderner Anwendungen auf serviceorientierte Architekturen hat sich der Problembereich der Service-to-Service-Aufrufe vergrößert. Es kommt häufig vor, dass ein Dienst die API eines anderen Dienstes aufrufen muss, um die Anfrage eines Benutzers zu erfüllen. Neben der Bereitstellung eines Mechanismus zur Weiterleitung des Datenverkehrs sind in der Regel auch Zuverlässigkeit, Beobachtbarkeit und Sicherheit erforderlich.

Wie du im Laufe dieses Kapitels lernen wirst, kann sowohl eine bibliotheks- als auch eine service-mesh-basierte Lösung deine Anforderungen an die Service-to-Service-Kommunikation erfüllen. Service-Meshes haben sich vor allem im Unternehmenskontext schnell durchgesetzt und sind bei einer steigenden Anzahl von Consumern und Providern oft die skalierbarste, wartungsfreundlichste und sicherste Option. Aus diesem Grund haben wir uns in diesem Kapitel hauptsächlich auf das Service-Mesh-Muster konzentriert.

Leitfaden: Solltest du Service Mesh einführen?

Tabelle 4-1 enthält eine Reihe von ADR-Richtlinien, die dir bei der Entscheidung helfen sollen, ob du die Service-Mesh-Technologie in deinem Unternehmen einführen solltest.

Tabelle 4-1. ADR-Richtlinie: Richtlinien für Dienstleistungsnetze oder Bibliotheken

Entscheidung

Solltest du ein Dienstnetz oder eine Bibliothek für das Routing des Dienstverkehrs verwenden?

Diskussionspunkte

Verwendet ihr in eurem Unternehmen eine einzige Programmiersprache?

Benötigst du nur einfaches Service-to-Service-Routing für REST- oder RPC-ähnliche Kommunikation?

Hast du funktionsübergreifende Anforderungen, die erweiterte Funktionen wie Authentifizierung, Autorisierung oder Ratenbegrenzung erfordern?

Hast du bereits eine Lösung, oder gibt es eine unternehmensweite Vorgabe, dass der gesamte Datenverkehr über bestimmte Komponenten in deinem Netzwerk geleitet werden muss?

Empfehlungen

Wenn dein Unternehmen die Verwendung einer einzigen Programmiersprache oder eines einzigen Frameworks vorschreibt, kannst du in der Regel die sprachspezifischen Bibliotheken oder Mechanismen für die Service-to-Service-Kommunikation nutzen.

Verwende immer die einfachste Lösung für deine Anforderungen, mit Blick auf die unmittelbare Zukunft und bekannte Anforderungen.

Wenn du erweiterte funktionsübergreifende Anforderungen hast, insbesondere bei Diensten, die unterschiedliche Programmiersprachen oder Technologie-Stacks verwenden, ist ein Service Mesh vielleicht die beste Wahl.

Führe innerhalb deiner Organisation immer eine Due-Diligence-Prüfung für bestehende Mandate, Lösungen und Komponenten durch.

Fallstudie: Extrahieren von Sitzungsfunktionalität in einen Dienst

Für die Fallstudie next evolution of our conference system konzentrierst du dich auf die Wünsche der Konferenzinhaber, eine zentrale neue Funktion zu unterstützen: Die Ansicht und Verwaltung der Konferenzsitzungen eines Teilnehmers über die mobile Anwendung.

Dies ist eine wichtige Änderung, die die Erstellung eines ADR rechtfertigen würde. Tabelle 4-2 ist ein Beispiel für ein ADR, das von dem technischen Team, dem das Konferenzsystem gehört, vorgeschlagen werden könnte.

Tabelle 4-2. ADR501 Trennen von Sitzungen vom alten Konferenzsystem
Status Vorgeschlagene

Kontext

Die Betreiber der Konferenz haben sich eine weitere neue Funktion für das aktuelle Konferenzsystem gewünscht. Das Marketingteam ist der Meinung, dass das Engagement der Konferenzteilnehmer/innen zunehmen wird, wenn sie über die mobile Anwendung Details zu den Konferenzsitzungen einsehen und ihr Interesse daran bekunden können. Das Marketingteam möchte auch sehen können, wie viele Teilnehmer/innen an den einzelnen Sitzungen interessiert sind.

Entscheidung

In einem weiteren Schritt werden wir die Sitzungskomponente in einen eigenständigen Dienst aufspalten. Dies ermöglicht eine API-First-Entwicklung für den Sitzungsdienst und den Aufruf der API aus dem bestehenden Konferenzdienst. Außerdem kann der Teilnehmerdienst die API des Sitzungsdienstes direkt aufrufen, um Sitzungsinformationen für die mobile Anwendung bereitzustellen.

Konsequenzen

Die Legacy-Anwendung wird den neuen Sitzungsdienst aufrufen, wenn sie alle sitzungsbezogenen Abfragen bearbeitet, sowohl für bestehende als auch für neue Funktionen. Wenn ein Nutzer die Sitzungen, für die er sich bei einer Konferenz interessiert, anzeigen, hinzufügen oder entfernen möchte, muss der Teilnehmerdienst den Sitzungsdienst aufrufen. Wenn ein Konferenzadministrator sehen möchte, wer an den einzelnen Sitzungen teilnimmt, muss der Sitzungsdienst den Teilnehmerdienst aufrufen, um festzustellen, wer an den einzelnen Sitzungen teilnimmt. Der Sitzungsdienst könnte zu einem Single Point of Failure in der Architektur werden und wir müssen Maßnahmen ergreifen, um die möglichen Auswirkungen eines einzelnen Sitzungsdienstes abzumildern. Da die Anzeige und Verwaltung der Sitzungen durch die Teilnehmer während einer Live-Konferenz stark zunimmt, müssen wir auch mit großen Datenverkehrsspitzen rechnen und damit, dass einer oder mehrere Sitzungsdienste überlastet werden oder nicht mehr einwandfrei funktionieren.

Das C4-Modell, das die vorgeschlagene architektonische Änderung zeigt, ist in Abbildung 4-1 dargestellt.

maar 0401
Abbildung 4-1. C4-Modell, das die Extraktion des Sitzungsdienstes aus dem Konferenzsystem zeigt

Obwohl der neue Sitzungsdienst nicht extern zugänglich gemacht werden muss, könntest du die in der vorangegangenen ADR genannten Anforderungen an Routing und Zuverlässigkeit leicht erfüllen, indem du diesen Dienst über das API-Gateway zugänglich machst und sowohl das Altsystem als auch den Teilnehmerdienst so konfigurierst, dass sie diesen neuen Dienst über die externe Adresse des Gateways aufrufen. Dies wäre jedoch ein Beispiel für das "API-Gateway-Loopback"-Problem, das du in "Häufige API-Gateway-Implementierungsfehler" kennengelernt hast . Dieses Problem kann dazu führen, dass interner Datenverkehr dein Netzwerk verlässt, was sich auf die Leistung, die Sicherheit und die Kosten (des Cloud-Anbieters) auswirkt. Sehen wir uns nun an, wie ein Service-Mesh dir helfen kann, deine neuen Anforderungen zu erfüllen und gleichzeitig dieses Problem zu vermeiden.

Was ist Service Mesh?

Grundsätzlich ist "Service Mesh" ein Muster für die Verwaltung der gesamten Service-zu-Service-Kommunikation (oder Anwendung-zu-Anwendung) innerhalb eines verteilten Softwaresystems. Es gibt viele Überschneidungen zwischen dem Service Mesh- und dem API-Gateway-Muster, wobei es zwei Hauptunterschiede gibt: Erstens sind Service Mesh-Implementierungen für die Abwicklung des Service-zu-Service- oder Ost-West-Verkehrs innerhalb eines Clusters oder Rechenzentrums optimiert. Zweitens ist der Absender der Kommunikation in der Regel ein (einigermaßen) bekannter interner Dienst und nicht das Gerät eines Benutzers oder ein System, das außerhalb deiner Anwendungen läuft.

Service Mesh ist nicht Mesh Networking

Service Mesh ( ) ist nicht zu verwechseln mit Mesh Networking, das eine untergeordnete Netzwerktopologie darstellt. Mesh Networking wird im Zusammenhang mit dem Internet der Dinge (IoT) und für die Implementierung mobiler Kommunikationsinfrastrukturen in abgelegenen oder schwierigen Szenarien (z. B. bei der Katastrophenhilfe) immer häufiger eingesetzt. Service Mesh-Implementierungen bauen auf bestehenden Netzwerkprotokollen und -topologien auf.

Das Service-Mesh-Muster konzentriert sich auf das Verkehrsmanagement (Routing), die Ausfallsicherheit, die Beobachtbarkeit und die Sicherheit der Service-to-Service-Kommunikation. Mach dir keine Sorgen, wenn du noch nicht viel von diesem Muster gehört hast, denn erst 2016 hat das Buoyant-Team den Begriff geprägt, um die Funktionalität seiner Linkerd-Technologie zu erklären.1 In Kombination mit der Einführung anderer verwandter Technologien, wie der von Google gesponserten Istio, führte dies dazu, dass der Begriff "Service Mesh" in den Bereichen Cloud Computing, DevOps und Architektur schnell Verbreitung fand.

Ähnlich wie ein API-Gateway wird ein Service Mesh mit zwei grundlegenden Komponenten implementiert: einer Steuerebene und einer Datenebene. In einem Service Mesh werden diese Komponenten immer getrennt voneinander eingesetzt. Auf der Steuerebene interagieren die Betreiber mit dem Service Mesh und legen Routen, Richtlinien und erforderliche Telemetrie fest. Die Datenebene ist der Ort, an dem die gesamte in der Steuerebene festgelegte Arbeit stattfindet und an dem die Netzwerkpakete geroutet, die Richtlinien durchgesetzt und die Telemetrie gesendet werden.

Nehmen wir die Konfiguration des Datenverkehrs zwischen den Diensten innerhalb eines Kubernetes-Clusters als Beispiel: Ein menschlicher Operator legt zunächst das Routing und die Richtlinien mithilfe der benutzerdefinierten Ressourcenkonfiguration fest - in unserem Fall zum Beispiel, dass der Dienst Attendee den Dienst Session aufrufen kann - und "wendet" diese dann über ein Befehlszeilentool wie kubectl oder eine Continuous Delivery Pipeline auf den Cluster an. Eine Service-Mesh-Controller-Anwendung, die innerhalb des Kubernetes-Clusters läuft, fungiert als Steuerebene, die diese Konfiguration analysiert und die Datenebene - in der Regel eine Reihe von "Sidecar"-Proxys, die neben den Diensten Attendee und Session laufen - anweist, dies zu tun.

Der gesamte Dienst-zu-Dienst-Verkehr innerhalb des Kubernetes-Clusters wird über die Sidecar-Proxys geleitet, in der Regel transparent (ohne dass die zugrundeliegenden Anwendungen erkennen, dass ein Proxy involviert ist). Eine Beispieltopologie der Dienste und des Service Mesh Control Plane und Data Plane ist in Abbildung 4-2 dargestellt.

maar 0402
Abbildung 4-2. Topologie der Dienste und der Kontroll- und Datenebene eines Service Mesh (am Beispiel von Istio)

Welche Funktionen bietet ein Service Mesh?

Auf der Netzwerkebene fungiert ein Service-Mesh-Proxy als vollständiger Proxy, der den gesamten eingehenden Datenverkehr von anderen Diensten entgegennimmt und auch alle ausgehenden Anfragen an andere Dienste initiiert. Dazu gehören alle API-Aufrufe und andere Anfragen und Antworten. Im Gegensatz zu einem API-Gateway ist die Zuordnung von einer Service-Mesh-Datenebene zu einem Dienst in der Regel eins-zu-eins, d.h. ein Service-Mesh-Proxy aggregiert keine Aufrufe über mehrere Dienste hinweg. Ein Service Mesh bietet übergreifende Funktionen wie Benutzerüberprüfung, Begrenzung der Anfragerate und Timeouts/Wiederholungen und kann Metriken, Protokolle und Trace-Daten bereitstellen, um die Implementierung der Beobachtbarkeit innerhalb des Systems zu unterstützen. Dies ist genau die Funktionalität, die wir für die Entwicklung unserer Fallstudie benötigen, indem wir den Session-Dienst extrahieren und ihn sowohl vom Legacy-Konferenzsystem als auch vom Attendee-Dienst aufrufen.

Obwohl sie im Vergleich zu einem API-Gateway weniger verbreitet sind, bieten einige Service Meshes zusätzliche Funktionen, die es Entwicklern ermöglichen, den Lebenszyklus einer API zu verwalten. Beispielsweise kann ein zugehöriger Servicekatalog das Onboarding und die Verwaltung von Entwicklern, die die Service-APIs nutzen, unterstützen, oder ein Entwicklerportal ermöglicht die Kontoverwaltung und Zugriffskontrolle. Einige Service Meshes bieten auch die Prüfung von Richtlinien und die Verwaltung des Datenverkehrs, um die Anforderungen der Unternehmensführung zu erfüllen.

Wo wird ein Service Mesh eingesetzt?

Ein Service Mesh wird innerhalb eines internen Netzwerks oder Clusters eingesetzt. Große Systeme oder Netzwerke werden in der Regel durch den Einsatz mehrerer Instanzen eines Service Mesh verwaltet, wobei jedes einzelne Mesh oft ein Netzwerksegment oder eine Geschäftsdomäne abdeckt.

Ein Beispiel für eine Service-Mesh-Netzwerktopologie ist in Abbildung 4-3 dargestellt.

maar 0403
Abbildung 4-3. Eine typische Service-Mesh-Topologie, die auf zwei Cluster verteilt ist (die durchgezogenen Pfeile zeigen den Service-Mesh-Verkehr)

Wie lässt sich ein Service Mesh mit anderen Netzwerktechnologien integrieren?

Ein moderner Netzwerkstack kann aus vielen Schichten bestehen, insbesondere bei der Arbeit mit Cloud-Technologien, bei denen Virtualisierung und Sandboxing auf mehreren Ebenen stattfinden. Ein Service Mesh sollte mit diesen anderen Netzwerkschichten harmonieren, aber Entwickler und Betreiber müssen sich auch über mögliche Interaktionen und Konflikte im Klaren sein.Abbildung 4-4 zeigt die Interaktion zwischen der physischen (und virtualisierten) Netzwerkinfrastruktur, einem typischen Netzwerkstack und einem Service Mesh.

maar 0404
Abbildung 4-4. OSI-Modell, das zeigt, dass ein Dienstnetz zwischen den Schichten 3 und 7 arbeitet

Wenn du zum Beispiel Anwendungen in einem Kubernetes-Cluster einsetzt, kann ein Dienst einen anderen Dienst innerhalb desselben Clusters über einen vorgeschriebenen Namen, der einer IP-Adresse entspricht, finden und ansprechen. Grundlegende Sicherheitsrichtlinien für die Verkehrskontrolle können mit NetworkPolicies umgesetzt werden, die den Verkehr auf der Ebene der IP-Adresse und des Ports (OSI-Schicht 3 oder 4) kontrollieren, und zusätzliche Richtlinienkontrollen werden oft vom Container Networking Interface (CNI) Plug-in eines Clusters bereitgestellt.2

Service Meshes können die standardmäßige CNI-Service-zu-IP-Adresse-Auflösung und das Routing außer Kraft setzen und bieten darüber hinaus zusätzliche Funktionen. Dazu gehören transparentes Routing über Cluster hinweg, die Durchsetzung von Layer-3/4- und 7-Sicherheit (z. B. Benutzeridentität und -autorisierung), Layer-7-Lastausgleich (was nützlich ist, wenn du ein Multiplex-Keepalive-Protokoll wie gRPC oder HTTP/2 verwendest) und Beobachtbarkeit auf Service-zu-Service-Ebene und im gesamten Netzwerk Stack.

Warum ein Servicenetz nutzen?

Ähnlich wie die Entscheidung, warum du ein API-Gateway in deine bestehende Architektur einbauen solltest, ist auch die Entscheidung, warum du ein Service Mesh einführen solltest, ein vielschichtiges Thema. Du musst sowohl die kurzfristigen Vorteile und Kosten der Implementierung als auch die langfristigen Anforderungen an die Wartbarkeit abwägen. Es gibt viele API-bezogene, übergreifende Bedenken, die du für jeden oder alle deiner internen Dienste haben könntest, wie z.B. Product Lifecycle Management (schrittweise Freigabe neuer Versionen eines Dienstes), Zuverlässigkeit, Unterstützung für mehrsprachige Kommunikation, Beobachtbarkeit, Sicherheit, Wartbarkeit und Erweiterbarkeit. Ein Service Mesh kann bei all diesen Punkten helfen.

In diesem Abschnitt des Kapitels erhältst du einen Überblick über die wichtigsten Probleme, die ein Servicenetz lösen kann, wie zum Beispiel:

  • Ermöglicht eine fein abgestufte Steuerung von Service-Routing, Zuverlässigkeit und Verkehrsmanagement

  • Verbesserung der Beobachtbarkeit von Interservice-Aufrufen

  • Sicherheit durchsetzen, einschließlich Transportverschlüsselung, Authentifizierung undAutorisierung

  • Unterstützung von funktionsübergreifenden Kommunikationsanforderungen in einer Vielzahl vonSprachen

  • Getrennte Verwaltung des Ingress- und Service-to-Service-Verkehrs

Feinkörnige Steuerung von Routing, Zuverlässigkeit und Verkehrsmanagement

Das Routing des Datenverkehrs in einem verteilten, auf Microservices basierenden System kann eine größere Herausforderung sein, als es auf den ersten Blick scheint. In der Regel werden mehrere Instanzen eines Dienstes in einer Umgebung eingesetzt, um sowohl die Leistung (Lastverteilung zwischen den Diensten) als auch die Zuverlässigkeit (Redundanz) zu verbessern. Außerdem basieren viele moderne Infrastrukturplattformen auf "Commodity-Hardware", die sich als flüchtige Rechenressourcen manifestiert, die jederzeit heruntergefahren, neu gestartet oder verschwinden können. Das bedeutet, dass sich der Standort eines Dienstes von Tag zu Tag (oder von Minute zu Minute!) ändern kann.

Du kannst natürlich die Routing-Technologien und die damit verbundenen Techniken einsetzen, die du in Kapitel 3 kennengelernt hast. Die Herausforderung dabei ist, dass es in der Regel viel mehr interne Dienste und APIs gibt als externe APIs, die von deinen Anwendungen genutzt werden, und dass sich die internen Systeme und die dazugehörigen APIs und Funktionen oft viel schneller ändern. Dementsprechend würden die Betriebskosten drastisch ansteigen, wenn du vor jedem internen Dienst ein API-Gateway einrichten würdest, sowohl in Bezug auf die benötigten Rechenressourcen als auch auf die Personalkosten.

Transparentes Routing und Normalisierung der Dienstnamen

Grundsätzlich ist Routing der Prozess der Auswahl eines Pfades für den Datenverkehr in einem Netzwerk oder zwischen bzw. über mehrere Netzwerke hinweg. Bei Webanwendungen wird das Routing auf Netzwerkebene normalerweise innerhalb des TCP/IP-Stacks und der zugehörigen Netzwerkinfrastruktur (auf Schicht 3/4 des OSI-Modells) abgewickelt. Das bedeutet, dass nur die IP-Adresse und der Port des Ziels und des Absenders der Verbindung benötigt werden. In der Zeit vor der Cloud und in den Rechenzentren vor Ort sind die IP-Adressen interner Dienste oft fest und bekannt. Obwohl DNS weit verbreitet ist, um Domänennamen auf IP-Adressen abzubilden, ist es immer noch so, dass alte Anwendungen und Dienste fest kodierte IP-Adressen verwenden. Das bedeutet, dass jede Änderung des Standorts eines Dienstes eine Neuverteilung aller Dienste erfordert, die diesen Dienst aufrufen.

Mit der Einführung der Cloud und der damit einhergehenden Vergänglichkeit unserer Infrastruktur ändern sich die IP-Adressen von Computing-Instanzen und den dazugehörigen Diensten regelmäßig. Das wiederum bedeutet, dass IP- und Port-Adressen, die fest kodiert sind, häufig geändert werden müssen. Als Microservice-basierte Architekturen immer beliebter wurden, stieg der Aufwand für die Neuverteilung im Verhältnis zur Anzahl der Dienste innerhalb einer Anwendung. Frühe Microservice-Anwender schufen Lösungen, um dieses Problem zu lösen, indem sie externe "Service Discovery"-Verzeichnisse oder -Registries implementierten, die eine dynamische Zuordnung von Dienstnamen zu IP-Adressen und Ports enthalten.3

Service Meshes können diesen dynamischen Abgleich zwischen Dienstname und Standort außerhalb des Dienstes und transparent durchführen, ohne dass der Code geändert, neu implementiert oder neu gestartet werden muss. Ein weiterer Vorteil eines Service Meshes ist, dass es die Namensgebung über verschiedene Umgebungen hinweg normalisieren kann, indem es "Umgebungsbewusstsein" in Kombination mit der außerhalb der Anwendung gespeicherten Konfiguration nutzt. Ein Service Mesh, das in der Umgebung "Produktion" eingesetzt wird, erkennt beispielsweise, dass es in dieser Umgebung läuft. Das Service-Mesh ordnet dann den Servicenamen sessions-service auf Code-Ebene transparent dem umgebungsspezifischen Ort AWS-us-east-1a/prod/sessions/v2 zu, indem es den Ort in einer Service-Registry nachschlägt (die in das Mesh integriert sein oder extern ausgeführt werden kann). Derselbe Code, der in der Staging-Umgebung mit einem entsprechend konfigurierten Service-Mesh eingesetzt wird, leitet sessions-service an internal-staging-server-a/stage/sessions/v3 weiter.

Verlässlichkeit

Die ephemere Natur moderner Computing- und Cluster-Umgebungen bringt neben den Standortwechseln auch Herausforderungen in Bezug auf die Zuverlässigkeit mit sich. So muss zum Beispiel jeder Dienst Kommunikationsprobleme mit einem anderen Dienst, mit dem er interagiert, korrekt behandeln. Du wirst in Kürze mehr über "Die 8 Irrtümer des verteilten Rechnens" erfahren, aber zu den Problemen, auf die du in diesem Zusammenhang achten solltest, gehören die Unterbrechung der Verbindung eines Dienstes, die vorübergehende Nichtverfügbarkeit eines Dienstes oder die langsame Reaktion eines Dienstes. Diese Herausforderungen können im Code mit bekannten Zuverlässigkeitsmustern wie Wiederholungen, Timeouts, Unterbrechern, Bulkheads und Fallbacks gemeistert werden. Michael Nygards Buch Release It! Design and Deploy Production-Ready Software, das jetzt in der zweiten Auflage erschienen ist, bietet einen umfassenden Leitfaden zur Erforschung und Umsetzung. Wie du jedoch im Abschnitt "Funktionsübergreifende Kommunikation über verschiedene Sprachen hinweg unterstützen" genauer erfahren wirst , führt der Versuch, diese Funktionen in Code zu implementieren, in der Regel zu einem inkonsistenten Verhalten, insbesondere bei verschiedenen Sprachen und Plattformen.

Da ein Service Mesh an der Initiierung und Verwaltung jeder Service-zu-Service-Kommunikation beteiligt ist, bietet es den perfekten Ort, um diese Zuverlässigkeitsmuster konsistent zu implementieren und so Fehlertoleranz und Graceful Degradation zu gewährleisten. Je nach Implementierung kann ein Service Mesh auch Probleme erkennen und diese Informationen innerhalb des Meshs weitergeben, sodass jeder Service innerhalb des Meshs angemessene Entscheidungen über die Weiterleitung des Datenverkehrs treffen kann - wenn z. B. die Antwortlatenz eines Services zunimmt, können alle Services, die den Zieldienst aufrufen, angewiesen werden, stattdessen ihre Fallback-Aktionen einzuleiten.

Für die Fallstudie kannst du mit einem Dienstnetz festlegen, wie du mit Fehlern bei der Kommunikation mit dem neuen Sitzungsdienst umgehst. Stell dir vor, mehrere Tausend Teilnehmer einer Veranstaltung haben gerade die morgendliche Keynote gesehen und wollen ihren Tagesplan einsehen. Dieser plötzliche Anstieg des Datenverkehrs für den Sitzungsdienst kann zu einem gestörten Verhalten führen. Für die meisten Anwendungsfälle würdest du entsprechende Timeouts und Wiederholungsversuche definieren, aber du kannst auch eine Unterbrechungsaktion festlegen, die ein Anwendungsverhalten auslöst. Wenn z. B. ein API-Aufruf vom Attendee-Dienst an den Session-Dienst, um den täglichen Sitzungsplan eines Teilnehmers abzurufen, wiederholt fehlschlägt, kannst du einen Circuit Breaker im Dienstnetz auslösen, der alle Aufrufe an diesen Dienst schnell fehlschlägt (damit sich der Dienst erholen kann). Wahrscheinlich würdest du in der mobilen Anwendung mit diesem Fehler umgehen, indem du auf die Darstellung des gesamten Konferenzsitzungsplans zurückgreifst und nicht auf den persönlichen Zeitplan.

Fortschrittliches Traffic Routing: Shaping, Policing, Splitting und Mirroring

Seit dem Dot-Com-Boom Ende der 90er Jahre haben die Webanwendungen für Verbraucher immer mehr Nutzer und mehr Datenverkehr bewältigt. Die Nutzer sind auch anspruchsvoller geworden, sowohl was die Leistung als auch die angebotenen Funktionen angeht. Dementsprechend ist die Notwendigkeit, den Datenverkehr so zu verwalten, dass die Anforderungen an Sicherheit, Leistung und die Freigabe von Funktionen erfüllt werden, immer wichtiger geworden. Wie du in "Wie lässt sich ein API-Gateway mit anderen Technologien am Rande integrieren?"erfahren hast, wurden am Rand des Netzwerks spezielle Appliances entwickelt, um diese Anforderungen zu erfüllen, aber diese Infrastruktur war nicht geeignet, um vor jedem internen Dienst eingesetzt zu werden. In diesem Abschnitt des Kapitels erfährst du mehr über die Anforderungen, die für eine Microservices-basierte Anwendung im Hinblick auf die interne Verkehrssteuerung und -überwachung typisch geworden sind.

Traffic Shaping

Traffic Shaping ist eine Technik zur Verwaltung der Bandbreite, bei der ein Teil oder der gesamte Netzwerkverkehr verzögert wird, um einem gewünschten Verkehrsprofil zu entsprechen. Traffic Shaping wird eingesetzt, um die Leistung zu optimieren oder zu garantieren, die Latenzzeit zu verbessern oder die nutzbare Bandbreite für bestimmte Arten von Verkehr durch Verzögerung anderer Arten zu erhöhen. Die gebräuchlichste Art des Traffic Shaping ist das anwendungsbasierte Traffic Shaping, bei dem zunächst Fingerprinting-Tools eingesetzt werden, um interessante Anwendungen zu identifizieren, für die dann Shaping-Richtlinien gelten. Beim Ost-West-Verkehr kann ein Service-Mesh die Fingerprints erzeugen oder überwachen, z. B. die Service-Identität oder einen anderen Proxy dafür oder einen Request-Header, der relevante Metadaten enthält, z. B. ob eine Anfrage von einem Free-Tier-Nutzer einer Konferenzanwendung oder einem zahlenden Kunden stammt.

Verkehrspolizei

Traffic Policing ist die Überwachung des Netzwerkverkehrs auf die Einhaltung einer Verkehrsrichtlinie oder eines Vertrages und die Ergreifung von Maßnahmen zur Durchsetzung dieses Vertrages. Verkehr, der gegen eine Richtlinie verstößt, kann je nach Verwaltungsrichtlinie sofort verworfen, als nicht konform markiert oder belassen werden. Diese Technik ist nützlich, um zu verhindern, dass ein schlecht funktionierender interner Dienst einen Denial-of-Service (DoS)-Angriff durchführt oder um zu verhindern, dass eine kritische oder anfällige interne Ressource (z. B. ein Datenspeicher) übermäßig mit Verkehr belastet wird, Vor dem Aufkommen von Cloud-Technologien und Service-Meshes wurde die Überwachung des Datenverkehrs in internen Netzwerken in der Regel nur im Unternehmenskontext mit Hilfe spezieller Hardware- oder Software-Appliances wie einem Enterprise Service Bus (ESB) umgesetzt. Cloud Computing und Software-definierte Netzwerke (SDN) haben die Einführung von Techniken zur Überwachung des Datenverkehrs durch den Einsatz von Sicherheitsgruppen (SGs) und Netzwerk-Zugriffskontrolllisten (NACLs) erleichtert.

Bei der Verwaltung der Ost-West-Kommunikation kennen die Dienste innerhalb des Netzwerks oder der Clustergrenze möglicherweise einen Datenverkehrsvertrag und wenden intern eine Datenverkehrskontrolle an, um sicherzustellen, dass ihr Output innerhalb des Vertrags bleibt. So kann dein Teilnehmerdienst beispielsweise einen internen Ratenbegrenzer implementieren, der übermäßige Aufrufe der Sitzungsdienst-API innerhalb eines bestimmten Zeitraums verhindert.

Service Mesh ermöglicht eine granulare Steuerung von Traffic Shaping, Splitting und Mirroring, so dass der Datenverkehr schrittweise von einer Version eines Zieldienstes zu einer anderen verlagert oder migriert werden kann. In "Release-Strategien" werden wir uns ansehen, wie dieser Ansatz genutzt werden kann, um die Trennung von Build und Release für verkehrsbasierte Release-Strategien zu erleichtern.

Für transparente Beobachtbarkeit sorgen

Wenn ein verteiltes System wie eine Microservices-basierte Anwendung betreibt, ist die Fähigkeit, sowohl die Endnutzererfahrung als auch beliebige interne Komponenten zu beobachten, von entscheidender Bedeutung für die Fehlererkennung und die Behebung entsprechender Probleme. In der Vergangenheit erforderte die Einführung einer systemweiten Überwachung die Integration von hochgradig gekoppelten Laufzeitagenten oder Bibliotheken in die Anwendungen, was ein Deployment aller Anwendungen während des ersten Rollouts und aller zukünftigen Upgrades erforderte.

Ein Service Mesh kann einen Teil der erforderlichen Beobachtungsmöglichkeiten bieten, insbesondere Anwendungs- (L7) und Netzwerkmetriken (L4), und zwar auf transparente Weise. Eine entsprechende Aktualisierung der Telemetrie-Sammelkomponenten oder des Service Mesh selbst sollte keine Neuinstallation aller Anwendungen erfordern. Natürlich gibt es Grenzen für die Beobachtbarkeit, die ein Service Mesh bieten kann, und du solltest deine Dienste auch mit sprachspezifischen Metriken und protokollierenden Bibliotheken instrumentieren. In unserer Fallstudie würde das Service Mesh beispielsweise Metriken über die Anzahl, Latenz und Fehlerrate der API-Aufrufe des Sitzungsdienstes liefern, und du würdest dich normalerweise auch dafür entscheiden, geschäftsspezifische Metriken und KPIs der API-Aufrufe zu protokollieren.

Sicherheit durchsetzen: Transportsicherheit, Authentifizierungund Autorisierung

In ähnlicher Weise wie die Beobachtbarkeit wurde die Sicherheit der Service-to-Service-Kommunikation in der Vergangenheit mit sprachspezifischen Bibliotheken implementiert. Diese stark gekoppelten Ansätze weisen die gleichen Nachteile und Nuancen auf. Die Implementierung von Verschlüsselung auf Transportebene innerhalb eines internen Netzwerks ist beispielsweise eine relativ häufige Anforderung, aber die verschiedenen Sprachbibliotheken handhaben die Zertifikatsverwaltung unterschiedlich, was den operativen Aufwand für die Bereitstellung und Rotation von Zertifikaten erhöhte. Die Verwaltung der Identität von Diensten (Maschinen) und Nutzern (Menschen) für die Authentifizierung und Autorisierung war in den verschiedenen Sprachen ebenfalls schwierig. Außerdem war es oft einfach, versehentlich (oder absichtlich) jede Sicherheitsimplementierung zu umgehen, indem die erforderlichen Bibliotheken nicht eingebunden wurden.

Da die Datenebene eines Servicemeshs in den Pfad des Datenverkehrs innerhalb des Systems eingebunden ist, ist es relativ trivial, das erforderliche Sicherheitsprofil durchzusetzen. Die Datenebene des Servicemeshs kann zum Beispiel Service-Identitäten (z. B. mithilfe von SPIFFE) und kryptografische Zertifikate verwalten und so mTLS sowie Authentifizierung und Autorisierung auf Service-Ebene ermöglichen. So können wir mTLS in unserer Fallstudie leicht implementieren, ohne dass Codeänderungen erforderlich sind.

Unterstützung der funktionsübergreifenden Kommunikation in verschiedenen Sprachen

Wenn du Dienste innerhalb einer Microservice-basierten Anwendung erstellst oder extrahierst und von prozessinterner zu prozessexterner Kommunikation übergehst, musst du über Änderungen beim Routing, der Zuverlässigkeit, der Beobachtbarkeit und der Sicherheit nachdenken. Die dafür erforderliche Funktionalität kann im Anwendungscode implementiert werden, z. B. als Bibliothek. Wenn deine Anwendung oder dein System jedoch mehrere Programmiersprachen verwendet - und ein polyglotter Ansatz ist bei Microservice-basierten Systemen durchaus üblich - bedeutet dies, dass du jede Bibliothek für jede verwendete Sprache implementieren musst. Da ein Service-Mesh in der Regel nach dem Sidecar-Pattern implementiert wird, bei dem die gesamte Service-Kommunikation über einen Netzwerk-Proxy geleitet wird, der sich außerhalb des Service, aber im selben Netzwerk-Namensraum befindet, kann die benötigte Funktionalität einmal im Proxy implementiert und in allen Services wiederverwendet werden. Du kannst dir das als "Infrastruktur-Abhängigkeitsinjektion" vorstellen. In unserem Fallbeispiel würde uns das ermöglichen, unseren Attendee-Service in einer anderen Sprache neu zu schreiben (vielleicht um neue Leistungsanforderungen zu erfüllen) und uns trotzdem darauf zu verlassen, dass die funktionsübergreifenden Aspekte der Service-zu-Service-Kommunikation einheitlich gehandhabt werden.

Trennung von Ingress- und Service-to-Service-Verkehrsmanagement

Erinnere dich an in "Fallstudie": Ein Entwicklungsschritt" haben wir kurz die Schlüsselbegriffe Nord-Süd- und Ost-West-Verkehr vorgestellt. Allgemein gesprochen ist Nord-Süd-Verkehr der Verkehr, der von einem externen Standort in dein System eindringt. Ost-West-Verkehr ist der Verkehr, der intern von System zu System oder von Dienst zu Dienst fließt. Die Definitionen können kompliziert werden, wenn du dich näher mit der Definition von "deinen Systemen" befasst; erstreckt sich diese Definition zum Beispiel auf Systeme, die nur von deinem Team, deiner Abteilung, deiner Organisation oder deinen vertrauenswürdigen Dritten entwickelt und betrieben werden, usw.

Mehrere Beiträge im API-Bereich, darunter Marco Palladino von Kong, haben argumentiert, dass die Verwendung von Nord-Süd und Ost-West weitgehend irrelevant ist und eher ein Überbleibsel aus der früheren Generation der Computernetzwerke ist, als die Grenzen zwischen den Systemen noch klarer waren. Wir werden dieses Argument in Kapitel 9 genauer untersuchen, da es die Idee der API als Produkt (einschließlich des API-Lebenszyklusmanagements) und die Dienstkonnektivität der Schichten 7 und 4 (aus dem OSI-Modell) berührt. Die Unterschiede zwischen den Kerneigenschaften und Merkmalen des Ingress- und des Service-to-Service-Verkehrs sind in Tabelle 4-3 dargestellt.

Tabelle 4-3. Unterschiede zwischen Ingress- und Service-to-Service-Eigenschaften
Ingress (n/s) Dienst-zu-Dienst (E/W)

Quelle des Verkehrs

Extern (Benutzer, Dritte, Internet)

Intern (innerhalb der Grenzen des Trusts)

Verkehr Ziel

Öffentliche oder geschäftsorientierte API oder Website

Dienst oder Domänen-API

Authentifizierung

"Nutzer" (reale Welt) fokussiert

"Dienst" (maschinelle Entität) und "Nutzer" (realweltliche Entität) fokussiert

Autorisierung

"Benutzer"-Rollen oder Fähigkeitslevel

"Dienst"-Identität oder Netzwerksegment fokussiert, und "Nutzer"-Rollen oder Fähigkeitslevel

TLS

Einseitig, oft erzwungen (z. B. Protokoll-Upgrade)

Gegenseitig, kann verpflichtend gemacht werden (strict mTLS)

Primäre Umsetzungen

API-Gateway, Reverse Proxy

Dienstnetz, Anwendungsbibliotheken

Haupteigentümer

Gateway/Netzwerke/Operations-Team

Plattform/Cluster/Operations-Team

Organisatorische Benutzer

Architekten, API-Manager, Entwickler

Entwickler

Wie gezeigt, sind die Eigenschaften und die damit verbundenen Anforderungen für die Verwaltung der beiden Verkehrsarten oft recht unterschiedlich. So hat die Verarbeitung von externem Endnutzerverkehr, der für eine Produkt-API bestimmt ist, grundlegend andere Anforderungen als die Verarbeitung von internem Service-to-Service-Verkehr, der für eine interne Unternehmens-, Domänen- oder Komponenten-API bestimmt ist. In der Praxis bedeutet dies, dass die Kontrollschichten für ein API-Gateway und ein Service-Mesh unterschiedliche Fähigkeiten bieten müssen, um die Konfiguration der jeweiligen Datenschichten zu unterstützen. In unserer Fallstudie möchte das Entwicklungsteam des Sitzungsdienstes beispielsweise festlegen, dass der Dienst nur von der bestehenden Konferenzanwendung und dem Teilnehmerdienst aufgerufen werden kann, während das Team des Teilnehmerdienstes in der Regel nicht festlegen würde, welche externen Systeme die öffentliche API aufrufen können und welche nicht - dafür wäre das entsprechende Gateway- oder Netzwerkteam zuständig.

Dieser Unterschied zwischen der Verwaltung von Ingress- und Service-to-Service-API-Aufrufen lässt sich besser verstehen, wenn du die Entwicklung und Nutzung der API-Gateway-Technologie, wie sie in "Eine moderne Geschichte der API-Gateways" untersucht wird , mit der Entwicklung der Service-Mesh-Technologie vergleichst, wie sie im folgenden Abschnitt beschrieben wird.

Entwicklung des Service Mesh

Obwohl der Begriff "Service Mesh" erst 2016 geprägt wurde, haben einige der frühen "Einhorn"-Organisationen wie Twitter, Netflix, Google und Amazon bereits in den späten 2000er und frühen 2010er Jahren ähnliche Technologien entwickelt und in ihren internen Plattformen eingesetzt. Twitter hat zum Beispiel sein Scala-basiertes Finagle RPC-Framework entwickelt, das 2011 als Open Source veröffentlicht wurde. Netflix hat 2012 seine "OSS"-Bibliotheken für Java-basierte Microservices entwickelt und veröffentlicht, darunter Ribbon, Eureka und Hystrix.4 Später veröffentlichte das Netflix-Team den Prana-Sidecar, damit auch nicht-JVM-basierte Dienste die Vorteile dieser Bibliotheken nutzen konnten. Aus der Entwicklung der Finagle-Bibliotheken und der Einführung von Sidecars ging schließlich Linkerd hervor, das wohl erste Sidecar-basierte Service-Mesh, das bei der Gründung der CNCF ebenfalls ein Anfangsprojekt war. Google zog schnell nach und veröffentlichte das Istio-Service-Mesh, das auf dem Envoy-Proxy-Projekt aufbaute, das aus dem Lyft-Engineering-Team hervorgegangen war.

Es sieht so aus, als würde sich der Kreis schließen: Service-Mesh-Fähigkeiten werden in Shared Libraries zurückgedrängt, wie bei gRPC, oder dem Betriebssystemkern hinzugefügt. Diese Entwicklung ist in Abbildung 4-5 zu sehen. Obwohl die Entwicklung und Nutzung vieler dieser früheren Komponenten und Plattformen inzwischen veraltet ist, ist es sinnvoll, einen kurzen Überblick über ihre Entwicklung zu geben, da dies einige Herausforderungen und Einschränkungen bei der Verwendung des Service-Mesh-Musters aufzeigt, von denen einige immer noch bestehen.

maar 0405
Abbildung 4-5. Entwicklung der Service-Mesh-Technologie

Frühgeschichte und Beweggründe

In den 90er Jahren haben Peter Deutsch und andere bei Sun Microsystems "The 8 Fallacies of Distributed Computing" (Die 8 Irrtümer des verteilten Rechnens) zusammengestellt , in denen sie die Annahmen auflisten, die Ingenieure bei der Arbeit mit verteilten Systemen machen. Sie wiesen darauf hin, dass diese Annahmen zwar in primitiveren Netzwerkarchitekturen oder theoretischen Modellen richtig gewesen sein mögen, aber in modernen Netzwerken nicht mehr zutreffen:

  • Das Netzwerk ist zuverlässig

  • Latenz ist null

  • Die Bandbreite ist unendlich

  • Das Netzwerk ist sicher

  • Die Topologie ändert sich nicht

  • Es gibt einen Verwalter

  • Die Transportkosten sind gleich null

  • Das Netzwerk ist homogen

Peter und sein Team stellen fest, dass sich diese Trugschlüsse "alle langfristig als falsch erweisen und zu großen Schwierigkeiten und schmerzhaften Lernerfahrungen führen". Ingenieure können diese Probleme nicht einfach ignorieren; sie müssen sich explizit mit ihnen auseinandersetzen.

Ignoriere die Irrtümer des verteilten Rechnens auf eigene Gefahr!

Da die "8 Fallacies of Distributing Computing" in den 90er Jahren geprägt wurden, ist es verlockend, sie für ein Relikt aus der Computerwelt zu halten. Das wäre jedoch ein Fehler! Ähnlich wie bei vielen anderen zeitlosen Computergesetzen und -mustern aus den 70er und 80er Jahren bleiben die Probleme dieselben, auch wenn sich die Technologie ändert. Wenn du als Architekt arbeitest, musst du deine Teams ständig daran erinnern, dass viele der in diesen Irrtümern beschriebenen Netzwerkherausforderungen auch heute noch gültig sind und du deine Systeme entsprechend gestalten musst!

Als verteilte Systeme und Microservice-Architekturen in den 2010er Jahren populär wurden, erkannten viele Innovatoren in diesem Bereich wie James Lewis, Sam Newman und Phil Calçado, wie wichtig es ist, Systeme zu entwickeln, die diese Irrtümer anerkennen und ausgleichen, und zwar über die Funktionen hinaus, die in den Standard-Networking-Stacks enthalten sind. Aufbauend auf Martin Fowlers ursprünglicher Reihe von "Microservice Prerequisites" schuf Phil Calçado die "Calçado's Microservices Prerequisites" und fügte "standardisierte RPC" als Schlüsselvoraussetzung hinzu, die viele der praktischen Lektionen, die er aus den Irrtümern des verteilten Computings gelernt hatte, zusammenfasst. In einem späteren Blogbeitrag aus dem Jahr 2017 erklärte Phil: "Während der TCP/IP-Stack und das allgemeine Netzwerkmodell, die vor vielen Jahrzehnten entwickelt wurden, immer noch ein leistungsfähiges Werkzeug sind, um Computer miteinander kommunizieren zu lassen, haben die anspruchsvolleren [Microservice-basierten] Architekturen eine weitere Ebene von Anforderungen eingeführt, die von den Ingenieuren, die in solchen Architekturen arbeiten, erneut erfüllt werden müssen ."5

Muster für die Umsetzung

Auch wenn die heute am weitesten verbreitete Implementierung von Servicemeshes das proxy-basierte "Sidecar"-Modell der Bereitstellung nutzt, war dies nicht immer der Fall und wird es auch in Zukunft nicht sein. In diesem Abschnitt des Kapitels erfährst du, wie sich die Implementierungsmuster von Servicemeshes bisher entwickelt haben und was die Zukunft bringen könnte.

Bibliotheken

Obwohl viele technische Führungskräfte den Bedarf an einer neuen Schicht von Netzwerkfunktionen in Microservice-basierten Systemen erkannten, war ihnen klar, dass die Implementierung dieser Technologien nicht trivial sein würde. Sie erkannten auch, dass sich der Aufwand sowohl innerhalb eines Unternehmens als auch unternehmensübergreifend wiederholen würde. Dies führte zur Entwicklung von Microservice-fokussierten Netzwerk-Frameworks und gemeinsam genutzten Bibliotheken, die einmal erstellt und wiederverwendet werden können, zunächst innerhalb eines Unternehmens und später als Open Source für einebreitere Nutzung.

In seinem oben erwähnten Blogbeitrag hat Phil Calçado darauf hingewiesen, dass selbst grundlegende Netzwerkfunktionen wie die Erkennung von Diensten und die Unterbrechung von Stromkreisen schwierig zu implementieren sind. Dies führte zur Entwicklung großer, anspruchsvoller Bibliotheken wie Finagle von Twitter und dem OSS-Stack von Netflix. Diese wurden sehr beliebt, um zu vermeiden, dass dieselbe Logik in jedem Dienst neu geschrieben werden muss, und um die gemeinsamen Anstrengungen auf die Gewährleistung der Korrektheit zu konzentrieren. Einige kleinere Unternehmen nahmen die Last auf sich, die erforderlichen Netzwerkbibliotheken und -tools selbst zu schreiben, aber die Kosten waren in der Regel hoch, vor allem auf lange Sicht. Manchmal waren diese Kosten explizit und deutlich sichtbar, z. B. die Kosten für Ingenieure, die in Teams eingesetzt wurden, die sich mit der Entwicklung von Tools befassten. Aber häufiger waren die wahren Kosten schwer zu beziffern, da sie sich in der Zeit, die neue Entwickler für das Erlernen proprietärer Lösungen benötigten, in den Ressourcen, die für die betriebliche Wartung benötigt wurden, oder in anderen Formen der Beanspruchung von Zeit und Energie für die Arbeit an deinen kundenorientierten Produkten äußerten.

Phil stellte außerdem fest, dass die Verwendung von Bibliotheken, die Funktionen über Sprachbindungen oder ein SDK bereitstellen, die Tools, Laufzeiten und Sprachen einschränkt, die du für deine Microservices verwenden kannst. Bibliotheken für Microservices werden oft für eine bestimmte Plattform geschrieben, sei es eine Programmiersprache oder eine Laufzeitumgebung wie die JVM. Wenn du andere Plattformen als die von der Bibliothek unterstützte verwendest, musst du den Code höchstwahrscheinlich selbst auf die neue Plattform portieren, wobei deine Kosten im Verhältnis zur Anzahl der Sprachen steigen.

Service Mesh Libraries und der Preis der Polyglotte

Viele Unternehmen verfolgen einen polyglotten Ansatz bei der Programmierung von Anwendungen und verwenden eine Vielzahl von Sprachen, wobei sie für einen Dienst die am besten geeignete Sprache auswählen, um die Anforderungen zu erfüllen. Zum Beispiel verwenden sie Java für langlaufende Geschäftsdienste, Go für Infrastrukturdienste und Python für Data Science. Wenn du den bibliotheksbasierten Ansatz für die Implementierung eines Dienstnetzes wählst, musst du dir darüber im Klaren sein, dass du alle deine Bibliotheken im Gleichschritt erstellen, warten und aktualisieren musst, um Kompatibilitätsprobleme zu vermeiden oder eine suboptimale Entwicklererfahrung für einige Sprachen zu bieten. Du könntest auch subtile Unterschiede zwischen den Implementierungen auf verschiedenen Sprachplattformen oder Bugs finden, die nur eine bestimmte Laufzeit betreffen.

Seitenwagen

In den frühen 2010er Jahren verfolgten viele Ingenieure den Ansatz der polyglotten Programmierung, und es war nicht ungewöhnlich, dass ein einzelnes Unternehmen Dienste in mehreren Sprachen geschrieben hatte, die in der Produktion eingesetzt wurden. Der Wunsch, eine einzige Bibliothek zu schreiben oder zu pflegen, die alle erforderlichen Netzwerkabstraktionen handhabte, führte zur Entwicklung von Bibliotheken, die außerhalb eines Dienstes als eigenständige Prozesse liefen. Der Microservice "Sidecar" war geboren. 2013 schrieb Airbnb über "Synapse and Nerve", seine Open-Source-Implementierung eines Sidecars für die Service-Erkennung. Ein Jahr später stellte Netflix Prana vor, ein Sidecar, das eine HTTP-Schnittstelle für Nicht-JVM-Anwendungen bereitstellte, um sie mit dem Rest des Netflix-OSS-Ökosystems für die Service-Erkennung, die Unterbrechung von Verbindungen usw. zu integrieren. Das Kernkonzept bestand darin, dass ein Dienst nicht direkt mit seinen nachgelagerten Abhängigkeiten verbunden war, sondern der gesamte Datenverkehr über das Prana-Sidecar lief, das die gewünschten Netzwerkabstraktionen und -funktionen transparent hinzufügte.

Mit der zunehmenden Nutzung der Microservices-Architektur entstand eine neue Welle von Proxys, die flexibel genug sind, um sich an unterschiedliche Infrastrukturkomponenten und Kommunikationsanforderungen anzupassen. Das erste bekannte System in diesem Bereich war Linkerd, das von Buoyant entwickelt wurde und auf den Erfahrungen der Ingenieure bei der Arbeit an der Microservices-Plattform von Twitter basiert. Kurze Zeit später kündigte das Entwicklerteam von Lyft Envoy Proxy an, das einem ähnlichen Prinzip folgt und schnell von Google in sein Istio-Service-Mesh übernommen wurde. Bei der Verwendung des Sidecar-Patterns hat jeder deiner Dienste einen begleitenden Proxy-Prozess, der eigenständig neben deiner Anwendung läuft. Dieser Sidecar teilt sich in der Regel denselben Prozess-, Datei- und Netzwerk-Namensraum, und es werden bestimmte Sicherheitsgarantien gegeben (z. B, dass jede Kommunikation mit dem "lokalen" Netzwerk vom externen Netzwerk isoliert ist). Da die Dienste nur über den Sidecar-Proxy miteinander kommunizieren, ergibt sich ein Einsatz, der dem Diagramm in Abbildung 4-6 ähnelt.

maar 0406
Abbildung 4-6. Service-Mesh-Proxys bilden eine übergeordnete Netzwerkabstraktion

Wie Phil Calçado und William Morgan von Buoyant feststellten, besteht der wichtigste Aspekt dieser Integration von Sidecar-Proxys darin, dass du Proxys nicht mehr als isolierte Komponenten betrachtest, sondern das Netzwerk, das sie bilden, als etwas sehr Wertvolles anerkennst.

Mitte der 2010er Jahre begannen Unternehmen, ihre Microservices auf anspruchsvollere Laufzeiten wie Apache Mesos (mit Marathon), Docker Swarm und Kubernetes zu verlagern, und nutzten die von diesen Plattformen zur Verfügung gestellten Tools, um ein Service Mesh zu implementieren. Dies führte zu einer Abkehr von einer Reihe unabhängiger, isoliert arbeitender Proxies, wie wir sie bei Synapse und Nerve gesehen haben, und zur Verwendung einer zentralen Steuerungsebene. Wenn du dieses Einsatzmuster von oben nach unten betrachtest, siehst du, dass der Datenverkehr immer noch direkt von Proxy zu Proxy fließt, aber die Control Plane weiß über jede Proxy-Instanz Bescheid und kann sie beeinflussen. Die Control Plane ermöglicht es den Proxies, Funktionen wie Zugriffskontrolle und das Sammeln von Metriken zu implementieren, die eine Zusammenarbeit und Koordination zwischen den Diensten erfordern, wie in Abbildung 4-7 dargestellt.

maar 0407
Abbildung 4-7. Steuerung und Koordinierung einer Service-Mesh-Datenebene

Der Sidecar-basierte Ansatz ist das heute am weitesten verbreitete Muster und wahrscheinlich eine gute Wahl für unser Konferenzsystem. Die Hauptkosten für den Einsatz eines Sidecar-basierten Servicenetzes liegen in der Erstinstallation und der laufenden betrieblichen Wartung sowie in den Ressourcen, die für den Betrieb aller Sidecars benötigt werden - da unsere Anforderungen andie Skalierbarkeit derzeit bescheiden sind, sollten wir keine großen Mengen an Rechenleistung für den Betrieb der Sidecar-Proxys benötigen.

Die Kosten für den Betrieb von Sidecars in großem Maßstab

Viele der heute gängigen Service-Mesh-Lösungen erfordern, dass du jedem Dienst oder jeder Anwendung, die in deinem Cluster läuft, einen Proxy-Sidecar-Container wie Envoy, Linkerd-proxy oder NGINX hinzufügst und ausführst. Selbst in einer relativ kleinen Umgebung mit z.B. 20 Diensten, von denen jeder fünf Pods auf drei Knoten ausführt, hast du 100 Proxy-Container laufen. Wie klein und effizient die Proxy-Implementierung auch sein mag, die schiere Duplizierung der Proxies wirkt sich auf die Ressourcen aus.

Je nach Service-Mesh-Konfiguration kann der Speicherbedarf jedes Proxys im Verhältnis zur Anzahl der Dienste, mit denen er kommunizieren muss, ansteigen.Pranay Singhal schrieb über seine Erfahrungen bei der Konfiguration von Istio, um den Verbrauch von etwa 1 GB pro Proxy auf viel vernünftigere 60-70 MB pro Proxy zu reduzieren. Aber selbst in der kleinen, imaginären Umgebung mit 100 Proxys auf drei Knoten benötigt diese optimierte Konfiguration immer noch etwa 2 GB pro Knoten.

Proxylose gRPC-Bibliotheken

In einer Entwicklung, mit der sich der Kreis zu schließen scheint, begann die Google Cloud Anfang 2021 mit der Förderung von "proxyless gPRC", bei der die Netzwerkabstraktionen wieder in eine sprachspezifische Bibliothek verlagert werden (wenn auch eine Bibliothek, die von Google und einer großen OSS-Community gepflegt wird). Diese gRPC-Bibliotheken sind in jedem Dienst enthalten und fungieren als Datenebene innerhalb des Dienstnetzes. Die Bibliotheken benötigen für die Koordinierung Zugang zu einer externen Steuerungsebene, wie z. B. dem Google Traffic Director-Dienst. Traffic Director verwendet Open-Source-"xDS-APIs", um die gRPC-Bibliotheken direkt in den Anwendungen zu konfigurieren.6 Diese gRPC-Anwendungen fungieren als xDS-Clients und stellen eine Verbindung zur globalen Steuerebene von Traffic Director her, die globales Routing, Lastausgleich und regionales Failover für Service Mesh- und Lastausgleichsanwendungen ermöglicht. Traffic Director unterstützt sogar einen "hybriden" Betriebsmodus, der sowohl Sidecar-Proxy-basierte Dienste als auch Proxyless-Dienste einschließt (siehe Abbildung 4-8).

maar 0408
Abbildung 4-8. Beispiel für ein Netzwerkdiagramm von Diensten, die sowohl Sidecars als auch proxylose Kommunikation nutzen

Da unser Konferenzsystem neben gRPC-APIs auch REST-APIs verwendet, würde dies derzeit die Wahl einer Service-Mesh-Implementierung ausschließen. Wenn unsere interne Verwendung von REST-APIs veraltet ist oder die gRPC-Bibliotheken so erweitert werden, dass sie eine nicht gRPC-basierte Kommunikation unterstützen, könnte die Verwendung dieses Ansatzes neu überdacht werden.

Sidecarless: Betriebssystem-Kernel (eBPF) Implementierungen

Eine weitere aufkommende alternative Service-Mesh-Implementierung basiert darauf, dass die erforderlichen Netzwerkabstraktionen in den Kernel des Betriebssystems (OS) selbst zurückverlagert werden. Dies ist dank der Verbreitung von eBPF möglich geworden, einer Kernel-Technologie, die es benutzerdefinierten Programmen ermöglicht, innerhalb des Kernels in einer Sandbox zu laufen. eBPF-Programme werden als Reaktion auf Ereignisse auf OS-Ebene ausgeführt, von denen es Tausende gibt, an die man sie anhängen kann. Zu diesen Ereignissen gehören der Eintritt in oder der Austritt aus einer Funktion im Kernel- oder Userspace oder "Trace-Points" und "Probe-Points" und - wichtig für das Service Mesh - das Eintreffen von Netzwerkpaketen. Da es nur einen Kernel pro Knoten gibt, teilen sich alle Container und Prozesse, die auf einem Knoten laufen, denselben Kernel. Wenn du ein eBPF-Programm zu einem Ereignis im Kernel hinzufügst, wird es ausgelöst, unabhängig davon, welcher Prozess dieses Ereignis verursacht hat, ob er in einem Anwendungscontainer oder direkt auf dem Host läuft. Damit sollten alle möglichen Versuche, das Service Mesh zu umgehen, egal ob versehentlich oder auf andere Weise, ausgeschlossen sein.

Das eBPF-basierte Cilium-Projekt bietet die Möglichkeit, die Netzwerkverbindung zwischen Container-Workloads zu sichern und zu überwachen. Cilium bringt dieses "Sidecarless"-Modell in die Welt des Service Mesh. Die Verwendung von Cilium kann die Latenz zwischen Service-Aufrufen reduzieren, da einige Funktionen vom Kernel bereitgestellt werden können, ohne dass ein Netzwerksprung zu einem Sidecar-Proxy durchgeführt werden muss.7 Neben dem herkömmlichen Sidecar-Modell unterstützt Cilium die Ausführung einer Service-Mesh-Datenebene mit einer einzigen Envoy-Proxy-Instanz pro Knoten, was den Ressourcenverbrauch reduziert. Abbildung 4-9 zeigt, wie zwei Dienste mit Cilium und einem einzigen Envoy Proxy pro Knoten kommunizieren können.

maar 0409
Abbildung 4-9. Verwendung von Cilium, eBPF und einem einzelnen Envoy Proxy pro Knoten zur Implementierung der Service-Mesh-Funktionalität

Dienst Mesh Taxonomy

Tabelle 4-4 verdeutlicht die Unterschiede zwischen den drei Arten der Implementierung von Servicemeshes, wie sie im vorherigen Abschnitt beschrieben wurden.

Tabelle 4-4. Vergleich von bibliotheks-, proxy- und OS/Kernel-basierten Dienstnetzen
Anwendungsfall Bibliotheksbasiert (und "proxylos") Sidecars, Proxy-basiert OS/Kernel-basiert

Unterstützung von Sprachen/Plattformen

Einsprachige, plattformunabhängige Bibliotheken

Sprachunabhängig, breite Plattformunterstützung

Sprachunabhängig, Unterstützung auf Betriebssystemebene

Laufzeitmechanismus

Verpackt und innerhalb der Anwendung ausgeführt

Neben der Anwendung in einem separaten Prozess laufen lassen

Laufen als Teil des Betriebssystemkerns, mit vollem Zugriff auf den Benutzer- und Kernelbereich

Komponenten des Dienstnetzes aufrüsten

Erfordert die Neuerstellung und Neuverteilung der gesamten Anwendung

Erfordert die Neuverteilung von Sidecar-Komponenten (kann oft ohne Ausfallzeit erfolgen)

Erfordert Aktualisierung/Patching des Kernelprogramms

Beobachtbarkeit

Vollständiger Einblick in die Anwendung und den Datenverkehr, mit der Möglichkeit, den Kontext einfach zu verbreiten

Nur Einblicke in den Verkehr, die Weitergabe von Kontext erfordert Sprachunterstützung oder Shim

Nur Einblicke in den Verkehr, die Weitergabe von Kontext erfordert Sprachunterstützung oder Shim

Modell der Sicherheitsbedrohung

Bibliothekscode läuft als Teil der Anwendung

Sidecars teilen sich in der Regel den Prozess- und Netzwerk-Namensraum mit der Anwendung

Die Anwendung interagiert direkt mit dem Betriebssystem über syscalls

Fallstudie: Einsatz eines Service Mesh für Routing, Beobachtbarkeit und Sicherheit

In diesem Abschnitt des Kapitels lernst du anhand mehrerer konkreter Beispiele, wie du ein Service-Mesh nutzen kannst, um die allgemeinen Anforderungen an das Routing, die Beobachtung und die sichere Segmentierung (über die Autorisierung) deines Dienst-zu-Dienst-Verkehrs zu erfüllen. Alle Beispiele verwenden Kubernetes, da dies die gängigste Plattform ist, auf der Service-Meshes eingesetzt werden, aber die vorgestellten Konzepte gelten für alle Plattformen und Infrastrukturen, die jedes Service-Mesh unterstützt. Obwohl wir empfehlen, nur eine Service-Mesh-Implementierung innerhalb des Technologie-Stacks deiner Anwendung zu wählen und zu übernehmen, werden wir die Konfiguration des Konferenzsystems mit drei verschiedenen Service-Meshes demonstrieren, rein zu Lehrzwecken.

Routing mit Istio

Istio kann mit dem Tool istioctl in deinem Kubernetes-Cluster installiert werden. Die wichtigste Voraussetzung für die Nutzung von Istio ist die Aktivierung der automatischen Injektion der Proxy-Sidecars in alle Dienste, die innerhalb deines Clusters laufen. Das kannst du wie folgt tun:

$ kubectl label namespace default istio-injection=enabled

Wenn die Auto-Injection konfiguriert ist, sind die beiden wichtigsten benutzerdefinierten Ressourcen, mit denen du arbeiten wirst, VirtualServices und DestinationRules.8 Ein VirtualService definiert eine Reihe von Regeln für das Routing des Datenverkehrs, die bei der Adressierung eines Hosts angewendet werden, z. B. http://sessions. Eine DestinationRule definiert Richtlinien, die für den Datenverkehr gelten, der für einen Service bestimmt ist, nachdem das Routing stattgefunden hat. Diese Regeln geben die Konfiguration für den Lastausgleich, die Größe des Verbindungspools vom Sidecar und die Einstellungen für die Ausreißererkennung an, um ungesunde Hosts zu erkennen und aus dem Lastausgleichspool zu entfernen.

Um zum Beispiel das Routing zu deinen Sitzungs- und Teilnehmerdiensten innerhalb der Fallstudie zu ermöglichen, kannst du die folgenden VirtualServices erstellen:

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sessions
spec:
  hosts:
  - sessions
  http:
  - route:
    - destination:
        host: sessions
        subset: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: attendees
spec:
  hosts:
  - attendees
  http:
  - route:
    - destination:
        host: attendees
        subset: v1

Die folgenden DestinationRules können ebenfalls erstellt werden. Beachte, dass die attendees DestinationRule zwei Versionen des Dienstes angibt; dies ist die Grundlage für die Aktivierung des Canary Routing für die neue v2-Version des Dienstes:

---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: sessions
spec:
  host: sessions
  subsets:
  - name: v1
    labels:
      version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: attendees
spec:
  host: attendees
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

Wenn Istio installiert ist und die vorangegangenen VirtualServices und DestinationRules konfiguriert sind, kannst du mit dem Routing des Datenverkehrs und der API-Aufrufe zwischen den Diensten Attendee und Session beginnen. Es ist wirklich so einfach, loszulegen, auch wenn die Konfiguration und Wartung von Istio in einer Produktionsumgebung aufwändiger sein kann. Istio kümmert sich um das Routing und generiert außerdem Telemetriedaten zu jeder Verbindung. Erfahren wir mehr über die Beobachtbarkeit anhand des Linkerd Service Mesh.

Verkehrsbeobachtung mit Linkerd

Du kannst Linkerd in einem Kubernetes-Cluster installieren, indem du der Anleitung "Erste Schritte" folgst. Die Telemetrie- und Überwachungsfunktionen von Linkerd werden automatisch aktiviert, ohne dass du irgendwelche Konfigurationsänderungen an der Standardinstallation vornehmen musst. Zu diesen Überwachungsfunktionen gehören:

  • Aufzeichnung der wichtigsten ("goldenen") Metriken (Anfragevolumen, Erfolgsrate und Latenzverteilungen) für HTTP-, HTTP/2- und gRPC-Datenverkehr

  • Aufzeichnung von Metriken auf TCP-Ebene (Bytes in/out, etc.) für anderen TCP-Verkehr

  • Berichtsmetriken pro Dienst, pro Anrufer/Abnehmer-Paar oder pro Route/Pfad (mit Dienstprofilen)

  • Erstellung von Topologiegraphen, die die Laufzeitbeziehung zwischenDiensten anzeigen

  • Live, on-demand Stichproben anfordern

Du kannst diese Daten auf verschiedene Arten nutzen:

  • Über die Linkerd CLI, z.B. mit linkerd viz stat und linkerd viz routes

  • Über das Linkerd Dashboard und vorgefertigte Grafana Dashboards

  • Direkt von Linkerds eingebauter Prometheus-Instanz

Um Zugang zu den Beobachtungsfunktionen von Linkerd zu erhalten, musst du nur die viz-Erweiterung installieren und das Dashboard über deinen lokalen Browser öffnen:

linkerd viz install | kubectl apply -f -
linkerd viz dashboard

So erhältst du Zugriff auf Dienstdiagramme, die den Verkehrsfluss anzeigen. In Abbildung 4-10 siehst du, wie der Datenverkehr von der Webapp zu den Buch- und Autorendiensten durch das Netz fließt.

maar 0410
Abbildung 4-10. Verwendung von Linkerd viz zur Beobachtung des Verkehrsflusses zwischen Diensten

Du kannst die Top-Line-Verkehrsmetriken auch mit den vorgefertigten Grafana-Dashboards anzeigen, wie in Abbildung 4-11 dargestellt.

maar 0411
Abbildung 4-11. Ansicht des Linkerd viz Grafana Dashboards

Der Einsatz eines Service Meshes zur Beobachtung deiner Anwendungen ist sowohl in der Entwicklung als auch in der Produktion nützlich. Obwohl du die Erkennung von ungültigem Service-zu-Service-Verkehr in der Produktion immer automatisieren solltest, kannst du dieses Tool zur Beobachtung des Service Meshes auch nutzen, um zu erkennen, wenn interne APIs oder Dienste falsch aufgerufen werden. Jetzt wollen wir uns ansehen, wie du mithilfe von Richtlinien genau festlegen kannst, welche Dienste im Service Mesh miteinander kommunizieren können. Consul von HashiCorp.

Netzwerksegmentierung mit Consul

Du kannst Consul als Service Mesh innerhalb eines Kubernetes-Clusters installieren und konfigurieren, indem du die Anleitung "Erste Schritte mit Consul Service Mesh für Kubernetes" befolgst. Vor Microservices wurde die Autorisierung der Inter-Service-Kommunikation hauptsächlich über Firewall-Regeln und Routing-Tabellen durchgesetzt. Consul vereinfacht die Verwaltung der Inter-Service-Autorisierung mit Intentionen, die es dir ermöglichen, Service-zu-Service-Kommunikationsberechtigungen nach Servicenamen zu definieren.

Intentions steuern, welche Dienste miteinander kommunizieren können, und werden vom Sidecar-Proxy bei eingehenden Verbindungen durchgesetzt. Die Identität des eingehenden Dienstes wird durch sein TLS-Client-Zertifikat überprüft, und Consul stellt jedem Dienst eine Identität zur Verfügung, die als TLS-Zertifikat kodiert ist. Dieses Zertifikat wird verwendet, umVerbindungen zu und von anderen Diensten herzustellen und zu akzeptieren.9 Der Sidecar-Proxy prüft dann, ob es eine Absicht gibt, die den eingehenden Dienst zur Kommunikation mit dem Zieldienst berechtigt. Wenn der eingehende Dienst nicht berechtigt ist, wird die Verbindung abgebrochen.

Eine Absicht besteht aus vier Teilen:

Quellendienst

Gibt den Dienst an, der die Kommunikation initiiert. Es kann der vollständige Name eines Dienstes sein oder ein "*", um auf alle Dienste zu verweisen.

Zielort-Service

Gibt den Dienst an, der die Kommunikation empfängt. Dies ist der "Upstream" (Dienst), den du in deiner Dienstdefinition konfiguriert hast. Es kann der vollständige Name eines Dienstes sein oder auch ein "*", um auf alle Dienste zu verweisen.

Erlaubnis

Legt fest, ob die Kommunikation zwischen Quelle und Ziel erlaubt ist. Dies kann entweder auf erlauben oder verweigern eingestellt werden.

Beschreibung

Optionales Metadatenfeld, um eine Beschreibung mit einer Absicht zu verknüpfen.

Die erste Absicht, die du erstellen wirst, ändert die "allow all"-Richtlinie, bei der jeglicher Verkehr erlaubt ist, sofern er nicht in bestimmten Regeln verweigert wird, in eine "deny all"-Richtlinie, bei der jeglicher Verkehr verweigert wird und nur bestimmte Verbindungen erlaubt sind:

apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: deny-all
spec:
  destination:
    name: '*'
  sources:
    - name: '*'
      action: deny

Wenn du das Platzhalterzeichen (*) im Zielfeld angibst, verhindert diese Absicht die gesamte Kommunikation zwischen den Diensten. Wenn du die Standardrichtlinie "Alle verweigern" definiert hast, kannst du den Datenverkehr zwischen dem Legacy-Dienst des Konferenzsystems, dem Teilnehmerdienst und dem Sitzungsdienst zulassen, indem du eine ServiceIntentions-CRD für jede erforderliche Dienstinteraktion definierst. Ein Beispiel:

---
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: legacy-app-to-attendee
spec:
  destination:
    name: attendee
  sources:
    - name: legacy-conf-app
      action: allow
---
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: legacy-app-to-sessions
spec:
  destination:
    name: sessions
  sources:
    - name: legacy-conf-app
      action: allow
---
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: attendee-to-sessions
spec:
  destination:
    name: sessions
  sources:
    - name: attendee
      action: allow
---
apiVersion: consul.hashicorp.com/v1alpha1
kind: ServiceIntentions
metadata:
  name: sessions-to-attendee
spec:
  destination:
    name: attendee
  sources:
    - name: sessions
      action: allow

Wenn du diese Konfiguration auf den Kubernetes-Cluster anwendest, können diese Interaktionen - und nur diese Interaktionen zwischen den Diensten - wie erforderlich verarbeitet werden. Alle anderen Interaktionen werden verhindert und der API-Aufruf oder die Anfrage wird verworfen.

Zusätzlich zu den Absichten von Consul ist das Open Policy Agent (OPA) Projekt eine beliebte Wahl, um ähnliche Funktionen innerhalb eines Service Meshes zu implementieren. Ein Beispiel für die Verwendung von OPA zur Konfiguration von Service-to-Service Richtlinien innerhalb von Istio findest du in der "OPA Tutorial documentation".

Nachdem du nun die Beispielkonfiguration kennengelernt hast, die bei der Weiterentwicklung des Konferenzsystems zum Einsatz kommt, wollen wir uns nun dem Betrieb und der Verwaltung der Service-Mesh-Implementierung zuwenden.

Ein Service Mesh einrichten:Misserfolge verstehen undbewältigen

Ungeachtet des Einsatzmusters und der Anzahl der Instanzen, die in einem System oder Netzwerk laufen, befindet sich ein Service Mesh in der Regel auf dem kritischen Pfad vieler, wenn nicht sogar aller Benutzeranfragen, die durch dein System laufen. Der Ausfall einer Service Mesh-Instanz in einem Cluster oder Netzwerk führt in der Regel dazu, dass das gesamte System innerhalb des Blastradius dieses Netzwerks nicht mehr verfügbar ist. Aus diesem Grund ist es von entscheidender Bedeutung, dass du dich mit dem Verständnis und dem Management von Ausfällen befasst.

Service Mesh als Single Point of Failure

Ein Service Mesh befindet sich oft auf dem Hot Path des gesamten Datenverkehrs, was eine Herausforderung in Bezug auf Zuverlässigkeit und Ausfallsicherheit darstellen kann. Je mehr Funktionen im Service Mesh vorhanden sind, desto größer ist das Risiko und desto größer sind die Auswirkungen eines Ausfalls. Da ein Service Mesh häufig dazu verwendet wird, die Freigabe von Anwendungsdiensten zu orchestrieren, wird auch die Konfiguration ständig aktualisiert. Es ist wichtig, Probleme zu erkennen und zu beheben und Risiken zu minimieren. Viele der in "API Gateway als Single Point of Failure" besprochenen Punkte lassen sich auch auf das Verständnis und das Management von Ausfällen im Service Mesh anwenden.

Gemeinsame Herausforderungen bei der Implementierung von Service Mesh

Da die Service-Mesh-Technologien im Vergleich zu den API-Gateway-Technologien neueren Datums sind, müssen einige der gemeinsamen Implementierungsprobleme erst noch entdeckt und verbreitet werden. Es gibt jedoch eine Reihe von Mustern, die es zu vermeiden gilt.

Service Mesh als ESB

Mit dem Aufkommen von Service-Mesh-Plug-ins oder Verkehrsfiltern ( ) und unterstützenden Technologien wie Web Assembly (Wasm) ist es zunehmend verlockend, Service-Meshes als ESB-ähnliche Funktionalitäten zu betrachten, wie z. B. die Umwandlung und Übersetzung von Nutzdaten. Aus all den Gründen, die bereits in diesem Buch erörtert wurden, raten wir dringend davon ab, Geschäftsfunktionen hinzuzufügen oder zu viele "intelligente" Funktionen mit der Plattform oder Infrastruktur zu koppeln.

Service Mesh als Gateway

Da viele Service-Mesh-Implementierungen eine Art Ingress-Gateway bieten, haben wir erlebt, dass Unternehmen, die ein API-Gateway einführen wollten, sich stattdessen für ein Service-Mesh entschieden haben und nur die Gateway-Funktionalität nutzen. Die Motivation macht Sinn, da die Ingenieure im Unternehmen erkennen, dass sie bald eine Service-Mesh-ähnliche Funktionalität einführen wollen, ihr größter Schmerzpunkt aber die Verwaltung des Ingress-Verkehrs ist. Allerdings ist der Funktionsumfang der meisten Service-Mesh-Gateways nicht so groß wie der eines vollwertigen API-Gateways. Außerdem fallen höchstwahrscheinlich Installations- und Betriebskosten für den Betrieb eines Service Mesh an, ohne dass du von den Vorteilen profitierst.

Zu viele Vernetzungsschichten

Wir haben festgestellt, dass einige Unternehmen eine Reihe von Netzwerkabstraktionen und -funktionen bereitstellen, die die aktuellen Anforderungen an die Kommunikation zwischen den Diensten erfüllen, aber die Entwicklungsteams wissen entweder nichts davon oder weigern sich aus irgendeinem Grund, diese zu übernehmen. Wenn die Entwicklungsteams versuchen, ein Service Mesh auf den bestehenden Netzwerktechnologien zu implementieren, tauchen zusätzliche Probleme auf, z. B. Inkompatibilitäten (z. B., Inkompatibilitäten (z. B. Strippen von Headern durch bestehende Netzwerktechnologien), erhöhte Latenzzeiten (aufgrund mehrerer Proxy-Hops) oder mehrfach implementierte Funktionen innerhalb des Netzwerkstapels (z. B. Unterbrechung von Verbindungen sowohl im Service Mesh als auch im darunter liegenden Netzwerkstapel). Aus diesem Grund empfehlen wir allen beteiligten Teams, sich mit dem Service Mesh abzustimmen und zusammenzuarbeiten Lösungen.

Auswählen eines Servicenetzes

Nachdem du auf mehr über die Funktionen eines Service Meshes, die Entwicklung des Musters und der Technologien sowie die Einbindung eines Service Meshes in die gesamte Systemarchitektur erfahren hast, stellt sich als Nächstes eine wichtige Frage: Wie wählst du ein Service Mesh aus, um es in den Technologie-Stack deiner Anwendung einzubinden?

Anforderungen identifizieren

Wie bereits im Zusammenhang mit der Auswahl eines API-Gateways erwähnt, ist einer der wichtigsten Schritte bei jedem neuen Infrastrukturprojekt die Ermittlung der damit verbundenen Anforderungen. Das mag offensichtlich erscheinen, aber ich bin sicher, du kannst dich an eine Zeit erinnern, in der du von glänzender Technologie, magischem Marketing oder guten Verkaufsunterlagen abgelenkt warst!

Im Abschnitt "Warum ein Service Mesh?" dieses Kapitels findest du genauere Informationen zu den wichtigsten Anforderungen, die du bei der Auswahl eines Service Mesh berücksichtigen solltest. Es ist wichtig, Fragen zu stellen, die sich sowohl auf aktuelle Probleme als auch auf deine zukünftige Roadmap beziehen.

Bauen versus Kaufen

Im Vergleich zu der Entscheidung, ein API-Gateway zu bauen oder zu kaufen, werden die damit verbundenen Diskussionen über Service Mesh weniger wahrscheinlich im Vorfeld geführt, insbesondere bei Organisationen, die über alte oder veraltete Systeme verfügen. Dies kann teilweise darauf zurückgeführt werden, dass Service Mesh eine relativ neue Technologiekategorie ist. Unserer Erfahrung nach sind in den meisten alten Systemen, die etwas verteilt sind (z. B, mehr als ein LAMP-Stack), werden Teilimplementierungen eines Service Mesh über die gesamte Organisation verstreut sein - zum Beispiel verwenden einige Abteilungen sprachspezifische Bibliotheken, andere einen ESB und wieder andere einfache API-Gateways oder einfache Proxys, um den internen Datenverkehr zu verwalten.

Wenn du dich für das Service-Mesh-Pattern entschieden hast, ist es unserer Meinung nach in der Regel am besten, eine Open-Source-Implementierung oder eine kommerzielle Lösung zu übernehmen und zu standardisieren, anstatt eine eigene Lösung zu entwickeln. Die Argumente für Build- versus Buy-Technologien für die Softwarebereitstellung darzustellen, würde ein ganzes Buch in Anspruch nehmen, daher wollen wir in diesem Abschnitt nur einige allgemeine Herausforderungen hervorheben:

Unterschätzung der Gesamtbetriebskosten (TCO)

Viele Ingenieurinnen und Ingenieure vergessen die Kosten für die Entwicklung einer Lösung, die fortlaufenden Wartungskosten und die laufenden Betriebskosten.

Nicht über Opportunitätskosten nachdenken

Wenn du kein Cloud- oder Plattform-Anbieter bist, ist es sehr unwahrscheinlich, dass dir ein benutzerdefiniertes Service-Netz einen Wettbewerbsvorteil verschafft. Du kannst deinen Kunden stattdessen mehr Wert bieten, indem du Funktionen entwickelst, die auf dein zentrales Leistungsversprechen ausgerichtet sind.

Operative Kosten

Unverständnis über die Einführungs- und Betriebskosten, die entstehen, wenn mehrere verschiedene Implementierungen zur Lösung derselben Probleme eingesetzt werden.

Das Bewusstsein für technische Lösungen

Sowohl im Bereich der Open-Source- als auch der kommerziellen Plattformkomponenten geht es schnell voran, und es kann schwierig sein, auf dem Laufenden zu bleiben. Es gehört jedoch zu den wichtigsten Aufgaben einer technischen Führungskraft, auf dem Laufenden zu bleiben.

Checkliste: Auswahl eines Servicenetzes

Die Checkliste in Tabelle 4-5 hebt die wichtigsten Entscheidungen hervor, die du und dein Team bei der Entscheidung über die Implementierung des Service-Mesh-Patterns und bei der Auswahl der zugehörigen Technologien berücksichtigen sollten.

Tabelle 4-5. ADR-Leitfaden: Checkliste für die Auswahl eines Dienstnetzes

Entscheidung

Wie sollten wir bei der Auswahl eines Dienstleistungsnetzes für unsere Organisation vorgehen?

Diskussionspunkte

Haben wir alle Anforderungen, die mit der Auswahl eines Dienstleistungsnetzes verbunden sind, identifiziert und nach Prioritäten geordnet?

Haben wir aktuelle Technologielösungen identifiziert, die in diesem Bereich in der Organisation eingesetzt werden?

Kennen wir alle Einschränkungen unseres Teams und unserer Organisation?

Haben wir unseren zukünftigen Fahrplan in Bezug auf diese Entscheidung erkundet?

Haben wir die Kosten für den Bau gegenüber dem Kauf ehrlich berechnet?

Haben wir die aktuelle Technologielandschaft erkundet und sind wir uns aller verfügbaren Lösungen bewusst?

Haben wir alle beteiligten Interessengruppen bei unserer Analyse und Entscheidungsfindung konsultiert und informiert?

Empfehlungen

Konzentriere dich vor allem auf deine Anforderung, die interne Kopplung zwischen API und System zu reduzieren, die Nutzung zu vereinfachen, APIs vor übermäßiger Nutzung und Missbrauch zu schützen, zu verstehen, wie APIs genutzt werden, und APIs als Produkte zu verwalten.

Zu den wichtigsten Fragen gehören: Gibt es ein bestehendes Dienstnetz? Wurde eine Sammlung von Technologien zusammengestellt, die ähnliche Funktionen bieten, z. B. haben Entwickler Service-to-Service-Kommunikationsbibliotheken erstellt oder haben Plattform-/SRE-Teams Sidecar-Proxys eingesetzt?

Achte auf die technologischen Fähigkeiten deines Teams, die Verfügbarkeit von Mitarbeitern für ein Service-Mesh-Projekt, die verfügbaren Ressourcen und das Budget usw.

Es ist wichtig, alle geplanten Änderungen, neuen Funktionen und aktuellen Ziele zu ermitteln, die sich auf das interne Verkehrsmanagement und die anderen Funktionen eines Dienstnetzes auswirken könnten.

Berechne die Gesamtbetriebskosten (TCO) aller aktuellen Service-Meshlike-Implementierungen und potenziellen zukünftigen Lösungen.

Ziehe bekannte Analysten, Trendberichte und Produktbewertungen zu Rate, um alle derzeit verfügbaren Lösungen zu verstehen.

Die Auswahl und Einführung eines Service Mesh betrifft viele Teams und Einzelpersonen. Du musst dich mit den Entwicklungsteams, der Qualitätssicherung, dem Architekturprüfungsausschuss, dem Plattformteam, InfoSec usw. beraten.

Zusammenfassung

In diesem Kapitel hast du erfahren, was ein Service Mesh ist und welche Funktionen, Vorteile und Herausforderungen die Einführung dieses Musters und der damit verbundenen Technologien bietet:

  • Grundsätzlich ist "Service Mesh" ein Muster für die Verwaltung der gesamten Service-to-Service-Kommunikation innerhalb eines verteilten Softwaresystems.

  • Auf Netzwerkebene agiert ein Service Mesh Proxy als vollständiger Proxy, der den gesamten eingehenden Verkehr von anderen Diensten annimmt und auch alle ausgehenden Anfragen an andere Dienste initiiert.

  • Ein Service Mesh wird innerhalb eines internen Netzwerks oder Clusters eingesetzt. Große Systeme oder Netzwerke werden in der Regel durch den Einsatz mehrerer Instanzen eines Service Mesh verwaltet, wobei jedes einzelne Mesh oft ein Netzwerksegment oder eine Geschäftsdomäne abdeckt.

  • Ein Service Mesh kann Endpunkte innerhalb einer entmilitarisierten Zone (DMZ) des Netzwerks oder zu externen Systemen oder zusätzlichen Netzwerken oder Clustern offenlegen, aber dies wird häufig durch ein "Ingress", "Terminating" oder "Transit" Gateway realisiert.

  • Es gibt viele API-bezogene, übergreifende Anliegen, die du für jeden einzelnen oder alle deine internen Dienste haben könntest, darunter: Produktlebenszyklusmanagement (schrittweise Freigabe neuer Versionen eines Dienstes), Zuverlässigkeit, Unterstützung für mehrsprachige Kommunikation, Beobachtbarkeit, Sicherheit, Wartbarkeit und Erweiterbarkeit. Ein Service Mesh kann bei all diesen Punkten helfen.

  • Ein Service Mesh kann mit sprachspezifischen Bibliotheken, Sidecar-Proxys, proxylosen Kommunikationsframeworks (gRPC) oder kernelbasierten Technologien wie eBPF implementiert werden.

  • Die verwundbarste Komponente eines Dienstnetzes ist in der Regel die Steuerungsebene, die gesichert und überwacht werden muss und als hochverfügbarer Dienst läuft.

  • Zu den Gegnern der Verwendung von Service Mesh gehören: Service Mesh als ESB, Service Mesh als Gateway und die Verwendung zu vieler Netzwerkschichten.

  • Die Entscheidung, ein Service Mesh zu implementieren und die Technologie dafür auszuwählen, ist eine Entscheidung des Typs 1. Es müssen Untersuchungen, Anforderungsanalysen und ein entsprechendes Design durchgeführt werden.

  • Wenn du dich für das Service-Mesh-Muster entschieden hast, ist es unserer Meinung nach in der Regel am besten, eine Open-Source-Implementierung oder eine kommerzielle Lösung zu übernehmen und zu standardisieren, anstatt eine eigene zu entwickeln.

Unabhängig davon, ob du dich für ein Service Mesh entscheidest, ist es wichtig, sowohl den externen als auch den internen Betrieb und die Sicherheit deiner APIs zu berücksichtigen. Dies ist der Schwerpunkt des nächsten Abschnitts in diesem Buch.

1 Das Linkerd-Projekt ist aus der Finagle-Technologie von Twitter hervorgegangen, die als Kommunikationsframework für Entwickler entwickelt wurde, die verteilte Anwendungen von Twitter erstellen. Linkerd hat sich inzwischen zu einem abgestuften Projekt der Cloud Native Computing Foundation (CNCF) entwickelt.

2 Du kannst mehr über die Netzwerkkonzepte von Kubernetes in den offiziellen Dokumenten erfahren: Service, NetworkPolicies und Container Networking Interface (CNI).

3 Der SmartStack von Airbnb war eine der ersten Implementierungen der externen Microservice Service Discovery.

4 Du solltest beachten, dass das Finagle RPC-Framework und die Netflix OSS-Bibliotheken inzwischen veraltet sind und nicht mehr für den Einsatz in modernen Produktionssystemen empfohlen werden.

5 Mehr dazu erfährst du auf den Websites von Fowlers "Microservice Prerequisites", "Calçado's Microservices Prerequisites" und Phils Blog "Pattern: Service Mesh".

6 Du kannst mehr über Traffic Director und das von Envoy Proxy inspirierte xDS-Protokoll auf den jeweiligen Dokumentations-Websites erfahren.

7 Mehr dazu erfährst du in "Wie eBPF das Service Mesh löst - Goodbye Sidecars".

8 Du kannst mehr über VirtualServices und DestinationRules in den Istio-Dokumenten erfahren.

9 Die Identität wird im TLS-Zertifikat in Übereinstimmung mit dem SPIFFE X.509 Identity Document kodiert, das es den Connect-Diensten ermöglicht, Verbindungen mit anderen SPIFFE-konformen Systemen herzustellen und zu akzeptieren.

Get Beherrschung der API-Architektur now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.