Wie vermeiden Mikroservice-Systemarchitekturen Netzwerkengpässe?


72

Ich habe viel über Mikroservice-Architekturen für Serveranwendungen gelesen und mich gefragt, warum die interne Netzwerknutzung im Vergleich zu einer Monolith-Architektur kein Engpass oder ein wesentlicher Nachteil ist.

Aus Gründen der Genauigkeit sind hier meine Interpretationen der beiden Begriffe:

  1. Monolith-Architektur: Eine Anwendung in einer einzigen Sprache, die alle Funktionen, Daten usw. verarbeitet. Ein Lastenausgleich verteilt die Anforderungen des Endbenutzers auf mehrere Computer, auf denen jeweils eine Instanz unserer Anwendung ausgeführt wird.

  2. Microservice-Architektur: Viele Anwendungen (Microservices) verarbeiten einen kleinen Teil der Funktionen und Daten. Jeder Mikrodienst stellt eine gemeinsame API bereit, auf die über das Netzwerk zugegriffen wird (im Gegensatz zur Kommunikation zwischen Prozessen oder zum gemeinsamen Speicher auf demselben Computer). API-Aufrufe werden meistens auf dem Server abgestickt, um eine Seite zu erstellen, obwohl möglicherweise ein Teil dieser Arbeit vom Client ausgeführt wird, der einzelne Microservices abfragt.

Meiner naiven Vorstellung nach scheint eine Microservices-Architektur langsamen Netzwerkverkehr zu verwenden, im Gegensatz zu schnelleren Ressourcen auf demselben Computer (dem Speicher und der Festplatte). Wie kann man sicherstellen, dass API-Abfragen über das interne Netzwerk die Gesamtantwortzeit nicht verlangsamen?


Internes Netzwerk ist oft 1 Gbit / s, manchmal schneller. Denken Sie an die durchschnittliche Größe der JSON-Antwort von einer API. Wie viele solcher Antworten können in einer Sekunde über eine 1-Gbit / s-Verbindung übertragen werden?
Arseni Mourzenko

3
Wenn Sie denken, Sie brauchen Microservices - und Sie könnten! - Zwei ausgezeichnete Bücher zum Vorbereiten: amazon.com/Building-Microservices-Sam-Newman/dp/1491950358 und amazon.com/Release-It-Production-Ready-Pragmatic-Programmers/dp/…
Steven A. Lowe

@MainMa das Problem liegt nicht in der Bandbreite, sondern in der Verzögerung. Und wenn Sie eine Rundreise machen müssen, werden Sie überrascht sein, wie wenig Bandbreite Sie tatsächlich nutzen können
Stephan Eggermont,

Antworten:


61

Interne Netzwerke verwenden häufig Verbindungen mit 1 Gbit / s oder schneller. Glasfaserverbindungen oder Bonding ermöglichen viel höhere Bandbreiten zwischen den Servern. Stellen Sie sich nun die durchschnittliche Größe einer JSON-Antwort von einer API vor. Wie viele solcher Antworten können in einer Sekunde über eine 1-Gbit / s-Verbindung übertragen werden?

Lassen Sie uns tatsächlich die Mathematik machen. 1 Gbit / s entspricht 131 072 KB pro Sekunde. Wenn eine durchschnittliche JSON-Antwort 5 KB beträgt (was ziemlich viel ist!), Können Sie mit nur einem Maschinenpaar 26.214 Antworten pro Sekunde über das Kabel senden . Nicht so schlimm, oder?

Aus diesem Grund ist die Netzwerkverbindung normalerweise nicht der Engpass.

Ein weiterer Aspekt von Microservices ist die einfache Skalierbarkeit. Stellen Sie sich zwei Server vor, von denen einer die API hostet und der andere sie verbraucht. Wenn die Verbindung zum Engpass wird, fügen Sie einfach zwei weitere Server hinzu, und Sie können die Leistung verdoppeln.

Dies ist der Fall, wenn unsere früheren 26 214 Antworten pro Sekunde für den Maßstab der App zu klein werden. Sie fügen weitere neun Paare hinzu und können jetzt 262.140 Antworten liefern.

Kommen wir jedoch zu unserem Serverpaar zurück und führen einige Vergleiche durch.

  • Wenn eine durchschnittliche nicht zwischengespeicherte Abfrage an eine Datenbank 10 ms dauert, sind Sie auf 100 Abfragen pro Sekunde beschränkt. 100 Abfragen. 26 214 Antworten. Das Erreichen der Geschwindigkeit von 26.214 Antworten pro Sekunde erfordert ein hohes Maß an Zwischenspeicherung und Optimierung (wenn die Antwort tatsächlich etwas Nützliches wie das Abfragen einer Datenbank erfordert; Antworten im "Hello World" -Stil sind nicht qualifiziert).

  • Auf meinem Computer passierte DOMContentLoaded für Googles Homepage gerade 394 ms. nachdem die Anfrage gesendet wurde. Das sind weniger als 3 Anfragen pro Sekunde. Für die Homepage von Programmers.SE sind es 603 ms. nachdem die Anfrage gesendet wurde. Das sind nicht einmal 2 Anfragen pro Sekunde. Ich habe übrigens eine 100-Mbit / s-Internetverbindung und einen schnellen Computer: Viele Benutzer werden länger warten.

    Wenn der Engpass die Netzwerkgeschwindigkeit zwischen den Servern ist, können diese beiden Sites buchstäblich Tausende von Aufrufen an verschiedene APIs ausführen, während die Seite bereitgestellt wird.

Diese beiden Fälle zeigen, dass das Netzwerk in der Theorie wahrscheinlich nicht Ihr Engpass ist (in der Praxis sollten Sie die tatsächlichen Benchmarks und Profile durchführen, um den genauen Ort des Engpasses Ihres bestimmten Systems zu bestimmen , das auf einer bestimmten Hardware gehostet wird). Viel wichtiger ist die Zeit, die für die eigentliche Arbeit aufgewendet wird (wären dies SQL-Abfragen, Komprimierung usw.) und das Senden des Ergebnisses an den Endbenutzer.

Denken Sie an Datenbanken

Normalerweise werden Datenbanken getrennt von der Webanwendung gehostet, die sie verwendet. Dies kann zu Bedenken führen: Wie steht es mit der Verbindungsgeschwindigkeit zwischen dem Server, auf dem sich die Anwendung befindet, und dem Server, auf dem sich die Datenbank befindet?

Es scheint , dass es Fälle gibt , in denen in der Tat, die Verbindungsgeschwindigkeit problematisch wird, das heißt , wenn Sie große Mengen an Daten speichern , die nicht brauchen , von der Datenbank selbst verarbeitet werden und sollten zur Verfügung stehen jetzt (dh große binäre Dateien). Solche Situationen sind jedoch selten: In den meisten Fällen ist die Übertragungsgeschwindigkeit im Vergleich zur Verarbeitungsgeschwindigkeit der Abfrage selbst nicht so hoch.

Die tatsächliche Übertragungsgeschwindigkeit hängt davon ab, ob ein Unternehmen große Datenmengen auf einem NAS hostet und auf den NAS von mehreren Clients gleichzeitig zugegriffen wird. Hier kann ein SAN eine Lösung sein. Dies ist jedoch nicht die einzige Lösung. Cat 6-Kabel unterstützen Geschwindigkeiten von bis zu 10 Gbit / s. Das Bonden kann auch verwendet werden, um die Geschwindigkeit zu erhöhen, ohne die Kabel oder Netzwerkadapter zu wechseln. Es gibt andere Lösungen, die die Datenreplikation über mehrere NAS hinweg umfassen.

Vergiss die Geschwindigkeit; Denken Sie an Skalierbarkeit

Ein wichtiger Punkt einer Web-App ist die Skalierbarkeit. Während die tatsächliche Leistung von Bedeutung ist (weil niemand für leistungsfähigere Server zahlen möchte), ist die Skalierbarkeit viel wichtiger, da Sie bei Bedarf zusätzliche Hardware bereitstellen können.

  • Wenn Sie eine nicht besonders schnelle App haben, verlieren Sie Geld, weil Sie leistungsstärkere Server benötigen.

  • Wenn Sie eine schnelle App haben, die sich nicht skalieren lässt, verlieren Sie Kunden, weil Sie nicht in der Lage sind, auf eine steigende Nachfrage zu reagieren.

Ebenso wurden virtuelle Maschinen vor einem Jahrzehnt als ein großes Leistungsproblem wahrgenommen. In der Tat hatte das Hosten einer Anwendung auf einem Server im Vergleich zum Hosten auf einer virtuellen Maschine erhebliche Auswirkungen auf die Leistung. Obwohl die Lücke heute viel kleiner ist, besteht sie immer noch.

Trotz dieses Leistungsverlustes wurden virtuelle Umgebungen aufgrund ihrer Flexibilität sehr beliebt.

Wie bei der Netzwerkgeschwindigkeit stellen Sie möglicherweise fest, dass die virtuelle Maschine der eigentliche Engpass ist. Angesichts Ihrer tatsächlichen Größe können Sie Milliarden von Dollar sparen, indem Sie Ihre App direkt ohne die virtuellen Maschinen hosten. Bei 99,9% der Apps ist dies jedoch nicht der Fall: Ihr Engpass liegt an einer anderen Stelle, und der Nachteil eines Verlusts von wenigen Mikrosekunden aufgrund der VM kann leicht durch die Vorteile der Hardwareabstraktion und -skalierbarkeit ausgeglichen werden.


Natürlich können wir sagen, dass JSON-Antworten klein sind, aber wie steht es mit ihrer Anzahl ? Ich bin der Meinung, dass eine Website mit hoher Auslastung in einer Microservice-Architektur mehr Netzwerkverkehr aufweist als in einer monolithischen Architektur (bei der der einzige Netzwerkverkehr zu / von den Datenbankservern erfolgt). Zwischenspeichern kann helfen, aber für Echtzeit- und / oder dynamisch generierte Inhalte weiß ich nicht, wie weit das Zwischenspeichern gehen würde.
James Mishra

@ JamesMishra: Ich habe meine Antwort bearbeitet, um auf Ihre Bedenken einzugehen.
Arseni Mourzenko

Deine Antwort ist perfekt . Sie haben nicht nur alle Einwände beantwortet, die mir einfallen, sondern auch Einwände, an die ich nicht gedacht habe.
James Mishra

5
Meine 2 Cent aus der realen Welt: Ein System, das aus sehr gesprächigen Microservices besteht, kann allein aufgrund eines überlasteten Netzwerks Leistungsprobleme haben. Caching und ein Event Stream-basiertes Design sind in solchen Fällen Ihr Freund. Neben Netzwerk, CPU und Speicher muss ein auf Mikrodiensten basierendes System auch Ausfallsicherheit in seinen Entwurf einbeziehen: Was passiert, wenn ein Mikrodienst ausfällt? Wie erstellt man Wiederholungen, verteilte Transaktionen, Selbstheilung, Überwachung
?

4
Bitte korrigieren Sie mich, wenn ich falsch liege. Wenn Sie jedoch über ein 1-Gbit / s-Netzwerk verfügen, können Sie theoretisch Daten im Wert von 1 Gbit / s pro Sekunde über dieses Netzwerk senden. Unabhängig von der Anzahl der Verbindungen. Je höher die Anzahl der Verbindungen ist, desto geringer ist die Bandbreite für jede Verbindung. Das tatsächliche Limit ohne Aktualisierung Ihres Netzwerks zur Unterstützung einer höheren Bandbreite liegt bei 26.214 Antworten pro Sekunde. Durch Hinzufügen weiterer Server wird die Netzwerkbandbreite nicht erhöht. Wenn ein einzelner Cluster diese Datenmenge ausspucken kann, wird Ihr Netzwerk durch Hinzufügen weiterer Server, die noch mehr Daten generieren, überlastet.
Sebbe

7

Ich denke, Sie lesen zu viel in den 'Mikro'-Teil. Es bedeutet nicht, jede Klasse durch einen Netzwerkdienst zu ersetzen, sondern eine monolithische Anwendung in Komponenten mit vernünftiger Größe zu unterteilen, die sich jeweils mit einem Aspekt Ihres Programms befassen. Die Dienste sprechen nicht miteinander. Im schlimmsten Fall haben Sie eine große Netzwerkanforderung in mehrere kleinere aufgeteilt. Die zurückgegebenen Daten unterscheiden sich sowieso nicht wesentlich von dem, was Sie erhalten (obwohl Sie möglicherweise mehr Daten zurückgeben und im Client konsolidieren).


3
"Die Dienste werden nicht miteinander reden." Ich stelle mir vor, dass Microservices gemeinsame Abhängigkeiten haben könnten (Authentifizierung vielleicht?), Die man in einen anderen Microservice aufteilen könnte. LDAP ist in gewissem Sinne ein Authentifizierungs-Microservice, und ich stelle mir vor, dass alle anderen Microservices mit ihm sprechen. Oder ... findet die Authentifizierung nur einmal statt? Wie überprüft jeder Mikrodienst die Berechtigungen anhand der Authentifizierung, um Angriffe mit direktem Objektzugriff zu verhindern?
James Mishra

2
@ JamesMishra gut .. es kommt darauf an. Als ich das letzte Mal die Microservice-Architektur verwendet habe, war jeder Service aus Sicherheitsgründen (aber auch aus Gründen des Unternehmenssilos) völlig unabhängig von den anderen. Die Authentifizierung wurde von beiden unterschiedlich gehandhabt, obwohl dies von einer Architekturrichtlinie gesteuert wurde. Dennoch gibt es keinen Grund, warum sie zum Beispiel nicht mit auth sprechen oder nur eine auf einer Bibliothek basierende Authentifizierung haben könnten. Aber ... ich wollte damit sagen, dass sie nicht viele Anrufe untereinander weiterleiten sollten, und nicht, dass sie selbst keine Dienste als Kunden in Anspruch nehmen sollten.
gbjbaanb

@JamesMishra, auth ist in diesen Umgebungen oft ein eigener Dienst, und daher sollte jeder Dienst nur davon Gebrauch machen, anstatt selbst eine vollständige Implementierung durchzuführen.
Paul

2

Indem Sie Ihren Code- und Ressourcenzugriff so strukturieren, dass das resultierende System flexibel genug ist, um als monolithische oder verteilte Anwendung über die Konfiguration ausgeführt zu werden. Wenn Sie den Kommunikationsmechanismus hinter einer gemeinsamen Schnittstelle abstrahieren und Ihr System unter Berücksichtigung der Parallelität erstellen, können Sie problemlos alles optimieren, nachdem Sie Ihr System profiliert und die echten Engpässe gefunden haben.


Ein Beispiel, um zu erklären, wovon ich annehme, dass @mortalapeman bedeutet: Sie haben eine Java / C # -Schnittstelle IProductAvailibitiy, mit der alle IProductAvailibitiy-Konsumenten verknüpft sind. Es gibt auch eine Klasse ProductAvailibitiyImpl, die diese Schnittstelle implementiert, und einen ProductAvailibitiyMicroservice, der ProductAvailibitiyImpl verwendet. Die Consumer können so konfiguriert werden, dass sie entweder ein lokales ProductAvailibitiyImpl oder einen Remote-Proxy für ProductAvailibitiyMicroservice
k3b am

2

Ich möchte eine andere Perspektive aus einer anderen Branche mit sehr unterschiedlichen Annahmen hinzufügen - verteilte Simulation (auf Entitätsebene). Konzeptionell ähnelt dies einem verteilten FPS-Videospiel. Hauptunterschiede: Alle Spieler teilen einen Zustand: wo sich der Drache gerade befindet; keine Datenbankaufrufe; Alles wird aus Gründen der Geschwindigkeit und der geringen Latenz im RAM gespeichert, der Durchsatz ist weniger relevant (aber ich denke, Sie können ihn auch nicht vollständig ignorieren).

Sie können sich jede teilnehmende Anwendung entweder als einen Monolithen (der alle Facetten eines Spielers darstellt) oder als einen Mikrodienst (der nur einen einzelnen Spieler in einer Menge darstellt) vorstellen.

Meine Kollegen hatten Interesse daran, eine einzelne teilnehmende Anwendung selbst in kleinere Mikrodienste zu zerlegen, die möglicherweise gemeinsam genutzt werden, z. B. Schadensentscheidungs- oder Sichtlinienberechnungen, die normalerweise in den Simulationen gebündelt sind.

Das Problem ist die Wartezeit beim Versenden von Anrufen und beim Warten auf Anforderungen. Die Bandbreite ist ohnehin irrelevant und reichlich, wie andere darauf hingewiesen haben. Wenn eine Sichtlinienberechnung jedoch von 1 Mikrosekunde auf 100 Mikrosekunden geht (z. B. aufgrund von Warteschlangen in dem neuen Mikrodienst, der von allen Playeranwendungen gemeinsam genutzt wird), ist dies ein großer Verlust (für den möglicherweise mehrere oder viele Sichtlinienberechnungen erforderlich sind) jedes Update mehrere Updates / Sekunde).

Überlegen Sie genau, wie Dienste funktionieren, wann sie aufgerufen werden und welche Daten ausgetauscht werden. Unsere Anwendungen tauschen bereits nicht nur Positionsinformationen aus, sondern auch Informationen zur Abrechnung. Ich befinde mich an Position x und fahre mit der Geschwindigkeit q in Richtung y. Und ich muss meine Informationen erst aktualisieren, wenn sich diese Annahmen ändern. Viele Updates werden seltener durchgeführt, und die Latenz (obwohl immer noch ein Problem) tritt im Verhältnis seltener auf.

Versuchen Sie also, die Frequenz zu verringern, anstatt einen Service mit feiner Körnung bei einer höheren Frequenz anzufordern:

  1. Ändern Sie, welche Daten angefordert werden, und verwenden Sie lokale Berechnungen
  2. Senden von Abfrage- oder Triggerparametern für eine asynchrone Antwort
  3. Batch-Anfragen
  4. Antizipieren von Anfragen und Vorbereiten einer Antwort auf Spekulation (Gegenteil von fauler Bewertung)
  5. Vermeiden Sie nach Möglichkeit Microservices, die andere Microservices anrufen. Dies verstärkt natürlich das Problem. Ich verstehe, dass dies ein Anreiz ist, Microservices größer zu machen, und den Punkt etwas zunichte macht, aber Microservices sind nicht mit Latenz befreundet. Vielleicht einfach zugeben und darüber hinwegkommen.

Denken Sie jetzt daran, Ihre Annahmen über Ihr System zu überprüfen. Wenn Sie sich mehr mit Durchsatz als mit Latenz beschäftigen oder keinen gemeinsamen Status usw. haben, sollten Sie auf jeden Fall Microservices verwenden, wenn sie sinnvoll sind. Ich sage nur, vielleicht verwenden Sie sie nicht dort, wo sie keinen Sinn ergeben.


1

Ihre naive Vorstellung ist richtig. Und oft ist das egal. Moderne Maschinen sind schnell. Die Hauptvorteile der Mikrodienstarchitektur liegen im Entwicklungs- und Wartungsaufwand und in der Zeit.

Und natürlich gibt es keine Regel, die besagt, dass Sie nicht gemeinsam genutzten Speicher verwenden oder sogar mehrere Dienste physisch in einer ausführbaren Datei bereitstellen können. Nur solange Sie es entwerfen, um nicht davon abhängig zu sein.


CPUs sind schnell. Das Gedächtnis ist schnell. SSDs sind schnell. Aber sind Netzwerkkarten und Router und Switches "schnell"? Eine andere Antwort besteht darauf, aber ich bin nicht sicher.
James Mishra

Es ist definitiv leicht, auf Probleme mit der Netzwerkgeschwindigkeit zu stoßen. Führen Sie einen Dienst in San Francisco, einen anderen in Amsterdam durch und konsumieren Sie sie in Sydney. Verzögerung ist der Schlüssel, nicht Bandbreite. Also mach das nicht. Und machen Dienstleistungen so groß wie sinnvoll
Stephan Eggermont

1

Wie viele Leute bereits erwähnten, geht es nicht um Netzwerkengpässe. Es geht mehr um Netzwerkversprödung. Der erste Schritt besteht also darin, eine synchrone Kommunikation zu vermeiden. Es ist einfacher als es klingt. Alles, was Sie brauchen, sind Dienste mit richtigen Grenzen. Rechte Grenzen führen dazu, dass Dienste autonom, lose gekoppelt und in hohem Maße kohärent sind. Ein guter Service benötigt keine Informationen von einem anderen Service, er hat sie bereits. Gute Dienste kommunizieren nur über Veranstaltungen. Gute Dienste sind schließlich auch konsistent, sodass es keine verteilten Transaktionen gibt.

Der Weg, um diese Güte zu erreichen, besteht darin, zuerst Ihre Geschäftsfähigkeiten zu identifizieren. Geschäftsfähigkeit ist eine spezifische Geschäftsverantwortung. Ein gewisser Beitrag zum allgemeinen Unternehmenswert. Also hier ist meine Schrittfolge, die ich nehme, wenn ich an Systemgrenzen denke:

  1. Identifizieren Sie übergeordnete Geschäftsverantwortlichkeiten. Es wird einige von ihnen geben. Behandeln Sie diese Services als Schritte, die Ihr Unternehmen ausführen sollte, um sein Geschäftsziel zu erreichen.
  2. Tauchen Sie in jeden Service ein. Identifizieren Sie untergeordnete Dienste, die einen übergeordneten Dienst umfassen.
  3. Denken Sie neben den ersten beiden Punkten auch an die Servicekommunikation. Sie sollten dies hauptsächlich über Ereignisse tun, um sich gegenseitig über das Ergebnis ihrer Geschäftsprozesse zu informieren. Ereignisse sollten nicht als Datenübermittler betrachtet werden.

Denken Sie daran, dass der Business-Service Menschen, Anwendungen und Geschäftsprozesse umfasst. In der Regel wird nur ein Teil davon als Fachbehörde vertreten.

Dies könnte ein bisschen abstrakt klingen, daher wäre wahrscheinlich ein Beispiel für die Identifizierung von Dienstgrenzen von Interesse.


0

Ein weiterer Faktor, um die aktuellen Antworten zu ergänzen. Mit einem grobkörnigen Service . Sie möchten die Latenz aller Anrufe vermeiden. Statt 10 Anrufe zu tätigen, rufen Sie 10 Daten an, die in einem DTO benötigt werden.

Und denken Sie daran, dass Microservices nicht so mikro sind, wie die Leute denken.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.