Verteilte Systeme. Entwurfsmuster. Buchbesprechung

Hallo Kollegen. Heute veröffentlichen wir eine Übersetzung der nächsten Rezension von Ben Neidels Website - diese Website wird Sie sicherlich für das Original interessieren. Dieses Mal werden wir über das Buch " Distributed Systems. Design Patterns " sprechen, das das Anfang dieses Jahres veröffentlichte Buch " Master Kubernetes " ergänzt und im Wesentlichen ein Analogon von GoF für das Design verteilter Systeme ist.



Viel Spaß beim Lesen.

Am Wochenende las ich das Buch Distributed Systems. Design Patterns von Brendan Burns . Das Buch hat mir sehr gut gefallen, obwohl ich zugeben muss, dass ich erwartet habe, ein etwas anderes Material darin zu finden. So werden in der Beschreibung der Buchbehälter nur nebenbei erwähnt. Obwohl die in diesem Buch beschriebenen Muster nicht nur für die Containerisierung gelten, werden fast alle hier beschriebenen Muster im Containerkontext angegeben und anschließend in der Kubernetes-Bereitstellungspipeline berücksichtigt. Es stellte sich übrigens heraus. Ich fange gerade erst an, mich mit der containerorientierten Entwicklung und Bereitstellung vertraut zu machen, und die Erörterung von Architekturmustern unter einem solchen „Container“ -Sichtpunkt war für mich eine Offenbarung. Dieser Ansatz hat mir geholfen, ein gutes Verständnis dafür zu bekommen, wie in der Microservice-Landschaft kleine Services richtig unterschieden werden, von denen jeder eine bestimmte Chance hat.

Der Autor des Buches, Brendan Burns, ist Mitbegründer des Open-Source-Projekts Kubernetes. Daher ist es nicht verwunderlich, dass alle Anwendungsbeispiele auf der Bereitstellung von Containern basieren, die auf Kubernetes-Konfigurationsdateien basieren. Zum Zeitpunkt des Lesens des Buches war ich ein wenig mit Docker vertraut und wusste nichts über Kubernetes. Daher habe ich versucht, den „Zweck“ der Kubernetes-Konfigurationsdateien durch einfaches Lesen herauszufinden. Ich glaube jedoch, dass das Buch nützlicher sein wird, wenn der Leser zumindest einige Erfahrungen mit Kubernetes hat.

Beim Lesen des Buches konnte ich die Assoziationen mit der Arbeit „ Integrationsvorlagen für Unternehmensanwendungen “ von Gregor Hope und Bobby Wolf nicht loswerden. Viele der von Burns diskutierten Muster sind den von Hope und Wolfe diskutierten Nachrichtenwarteschlangenmustern sehr ähnlich. Tatsächlich muss ich sagen, dass viele Muster in beiden Büchern sogar gleich erwähnt werden (zum Beispiel Scatter / Gather). Dies ist logisch, da das Thema beider Bücher die Aufteilung komplexer monolithischer Systeme in eine Reihe kleiner, eng zugeschnittener wiederverwendbarer Dienste ist. Ich denke, es kann sogar argumentiert werden, dass Burns spezifische Ansätze skizziert, die bei der Implementierung der Producer- und Consumer-Services nützlich sind, die an der Funktionsweise von nachrichtenbasierten Workflows beteiligt sind, die auch im Buch „Enterprise Application Integration Templates“ beschrieben sind.

Auch hier glaube ich, dass die Parallelen zwischen diesen beiden Büchern die Kraft von Designmustern bezeugen. Sowohl darin, wie gut sie uns zu bewährten Lösungen führen, als auch darin, dass Entwurfsmuster die technische Kommunikation erleichtern, da sie es uns ermöglichen, in einer gemeinsamen Sprache zu argumentieren.

Gleichzeitig ist einer der Ansätze, die mir am besten gefallen haben, im Buch „Distributed Systems. Entwurfsmuster “hängt genau mit dem Verbrauch der Nachrichtenwarteschlange zusammen. Burns empfiehlt, den Arbeitscontainer nicht zu zwingen, Nachrichten direkt aus dem System abzurufen (ähnlich wie im SQS-System (Simple Queue Service) von Amazon), sondern ein „Ambassador“ (Ambassador-Muster) zu erstellen. Ein solcher "Botschafter" -Container wird zusammen mit dem Arbeitscontainer bereitgestellt und bietet eine allgemeine API zum Bearbeiten von Warteschlangen. Mit dem Ambassador-Container können Sie Implementierungsdetails für die permanente Speicherung von Elementen in der Nachrichtenwarteschlange abstrahieren, sodass der Arbeitscontainer völlig unabhängig von bestimmten technologischen Lösungen ist.

„Der Botschafter der Containerquelle der Arbeitswarteschlange“ ist nur ein Beispiel aus einem Querschnittsthema, das sich als roter Faden durch das Buch zieht: Verwenden Sie Sätze kleiner Container, damit sich jeder einzelne Container so weit wie möglich auf eine bestimmte Aufgabe konzentrieren und sich als so wiederverwendbar wie möglich herausstellen kann. Burns untersucht dieses Konzept auf der Ebene der einzelnen Container und spricht über die Parametrisierung von Containern mithilfe von Befehlszeilenargumenten und Umgebungsvariablen. Dann geht er eine Ebene höher und spricht über die Muster von Seitenwagen und Botschaftern mit mehreren Containern in einem Einzelknotenkontext. Schließlich zeigt er, wie mithilfe von Multi-Container-Mustern eine leistungsstarke Microservice-Architektur erstellt wird.

Ich denke, dass Burns den "Traum" der gesamten Microservice-Landschaft perfekt artikulieren konnte:

Der Microservice-Ansatz bietet viele Vorteile, von denen viele mit Zuverlässigkeit und Flexibilität zusammenhängen. Microservices unterteilen die Anwendung in kleine Teile, von denen jeder für die Bereitstellung eines bestimmten Dienstes verantwortlich ist. Durch die Einschränkung des Leistungsumfangs kann jeder Dienst ein Team aufbauen und unterhalten, das mit zwei Pizzen versorgt werden kann.

Durch die Reduzierung der Teamgröße werden auch die Kosten für die Aufrechterhaltung der Aktivitäten gesenkt.

Darüber hinaus schwächt die Entstehung einer formalen Schnittstelle zwischen Mikrodiensten die gegenseitige Abhängigkeit der Teams und schafft einen zuverlässigen Vertrag zwischen den Diensten. Ein solcher formeller Vertrag verringert die Notwendigkeit einer engen Teamsynchronisation, da das Team, das die API bereitstellt, versteht, inwieweit es erforderlich ist, die Kompatibilität sicherzustellen, und das Team, das die API verwendet, auf einen stabilen Dienst zählen kann, ohne sich um die Details der Implementierung des verbrauchten Dienstes kümmern zu müssen. Eine solche Zerlegung ermöglicht es den Teams, das Entwicklungstempo und den Zeitplan für die Veröffentlichung neuer Versionen unabhängig zu steuern, wodurch sie die Möglichkeit haben, zu iterieren, wodurch der Servicecode verbessert wird.

Schließlich erhöht die Aufteilung in Mikrodienste die Skalierbarkeit. Da jede Komponente einem separaten Service zugeordnet ist, kann sie unabhängig von den anderen skaliert werden

(S. 79-80 in russischer Übersetzung)

Ich spreche von dem "Traum", weil es, wie Burns selbst zugibt, schwierig ist, ein Microservice-System und seine Architektur zu entwerfen. Das Überwachen und Debuggen eines solchen Systems ist viel komplizierter als das Überwachen und Debuggen eines monolithischen Analogons. Nur dem kann ich leicht zustimmen. Aufgrund meiner begrenzten Erfahrung mit Microservices bestätige ich, dass Shared Services schnell eng miteinander verbunden werden und „zuverlässige Verträge“ zwischen Services schnell zu einem beweglichen Ziel werden und immer mehr neue Änderungen erfahren.

Abschließend möchte ich auf das FaaS-Konzept eingehen - „Funktionen als Dienstleistungen“. Bei Systemen wie dem Lambda-Service von Amazon fühle ich mich gemischt. In einem äußerst abstrakten Sinne mag ich solche Systeme, aber ich habe keine Ahnung, wie sie sich in einer bestimmten Anwendung manifestieren. Burns geht in Teil II auf "Muster beim Entwerfen von Servesystemen" auf FaaS ein, aber leider klärt es das Faas-Problem für mich nicht vollständig.

Es hat mir sehr gut gefallen, dass Burns die Verwendung von FaaS empfiehlt, um nur einen Teil der bekannten Probleme zu lösen:

Wie bei anderen Tools zum Entwickeln verteilter Systeme möchten Sie möglicherweise eine bestimmte Lösung (z. B. ereignisorientierte Verarbeitung) als universelles Tool verwenden. Die Wahrheit ist, dass eine bestimmte Lösung normalerweise bestimmte Probleme löst. In einem bestimmten Kontext wird es sich als leistungsstarkes Werkzeug erweisen, aber wenn Sie es an den Ohren ziehen, um häufig auftretende Probleme zu lösen, entstehen komplexe, fragile Architekturen.

(S. 135 in russischer Übersetzung)

Vielen Dank an ihn für die Erwähnung der Schwierigkeiten, die bei der Verwendung von FaaS auftreten:

Wie im vorherigen Abschnitt erwähnt, müssen Sie bei der Systementwicklung mit dem FaaS-Ansatz die Systemkomponenten lose miteinander verbinden. Jede Funktion ist per Definition unabhängig. Alle Interaktionen werden über das Netzwerk ausgeführt. Funktionsinstanzen haben keinen eigenen Speicher, daher benötigen sie gemeinsam genutzten Speicher, um den Status zu speichern. Eine erzwungene Schwächung der Konnektivität von Systemelementen kann die Flexibilität und Geschwindigkeit der Serviceentwicklung erhöhen, gleichzeitig jedoch die Unterstützung erheblich erschweren.
Insbesondere ist es ziemlich schwierig, die umfassende Struktur des Dienstes zu erkennen, festzustellen, wie die Funktionen miteinander integriert sind, um zu verstehen, was und warum im Fehlerfall ein Fehler aufgetreten ist. Aufgrund der abfrageorientierten und serverlosen Natur von Funktionen sind einige Probleme nur schwer zu erkennen.

(S. 136-137 in russischer Übersetzung)

Wieder war ich überrascht, dass die meisten FaaS-Systeme nicht zu gut für die Lösung von Aufgaben sind, die eine aktive Verarbeitung erfordern:

... außerdem ist die Ausführungszeit einer Funktionsinstanz aufgrund der serverlosen Implementierung von Diensten normalerweise begrenzt. Dies bedeutet, dass der FaaS-Ansatz normalerweise nicht für Anwendungen geeignet ist, die eine lange Hintergrunddatenverarbeitung erfordern. (S. 138 in russischer Übersetzung)
Schließlich freute ich mich über die Bemerkung, dass FaaS wirtschaftlich unzweckmäßig wird, wenn es unmöglich ist, einen langen unterbrechungsfreien Betrieb des Prozessors sicherzustellen:
Wenn Sie jedoch so viele Anfragen haben, dass die Funktion ständig aktiv ist, zahlen Sie wahrscheinlich zu viel für die Anzahl der verarbeiteten Anfragen.

... wenn der Dienst wächst, wächst die Anzahl der verarbeiteten Anforderungen auf ein solches Niveau, dass der Prozessor ständig damit beschäftigt ist, sie zu verarbeiten. Ab diesem Zeitpunkt wird die Gebühr für die Anzahl der Anfragen unrentabel. Die Kosten pro CPU-Zeiteinheit für virtuelle Cloud-Maschinen sinken, wenn Kerne hinzugefügt werden und Ressourcen und Rabatte für die langfristige Nutzung reserviert werden. Die Kosten für die Zahlung der Anzahl der Anfragen steigen normalerweise mit der Anzahl der Anfragen.

(S. 139-140 in russischer Übersetzung)

Infolgedessen habe ich immer noch nicht verstanden: Wann ist es besser, „Funktionen als Dienste“ zu verwenden? Ich stelle fest, dass Burns kurz die Arbeit mit ereignisorientierten kurzfristigen Aufgaben beschreibt, die den Prozessor nicht stark belasten, wie z. B. die Zwei-Faktor-Authentifizierung (2FA). Angesichts der Tatsache, dass es sich um kleine kurzfristige Aufgaben mit geringen Kosten handelt, stellt sich jedoch die Frage: Warum sollten sie unabhängig voneinander skaliert werden? Warum nicht einfach diese Funktionen in einen anderen Containerservice aufnehmen, der eng mit dem ersten verwandt ist?

Ich hoffe, diese Probleme besser lösen zu können, wenn ich FaaS-Technologien in der Praxis einsetzen kann.

Abgesehen von einigen Verwechslungen mit FaaS hat mir das Buch sehr gut gefallen. Es ist schnell zu lesen, leicht wahrzunehmen. Es erinnert uns erneut an das enorme Potenzial, die Verbindung zwischen Komponenten auf allen Ebenen der Anwendungsentwicklung zu schwächen. Schließlich fällt es mir jetzt viel leichter, mit meinen Kollegen über Themen wie „Beiwagencontainer“ zu sprechen.

Source: https://habr.com/ru/post/de442514/


All Articles