Hallo habr
Die Praxis zeigt, dass es bei der anhaltenden
Relevanz des Microservice-Paradigmas nicht an
Interpretationen , Kritik und sogar
Entlarvung mangelt. Aus diesem Grund haben wir uns, um auf unsere übersetzten Veröffentlichungen zurückzukommen, entschlossen, speziell über
Microservices zu sprechen, oder vielmehr eine ausführliche Antwort auf die im Titel des Artikels gestellte Frage zu erwägen.
Der Begriff „Microservices“ tauchte erstmals um 2011/2012 auf. Seitdem ohne Microservices in der IT-Umgebung, fast nirgendwo. Haben wir es jedoch nach so vielen Jahren geschafft, richtig zu verstehen, was Mikrodienstleistungen sind?
Schauen wir uns zunächst einige Definitionen an:
Microservices ist ein Ansatz zur Softwareentwicklung (...), bei dem eine Anwendung als eine Gruppe lose gekoppelter Dienste strukturiert ist . In einer Mikrodienstarchitektur sind die Dienste sehr detailliert und die verwendeten Protokolle sind leicht . Der Vorteil der Zerlegung einer Anwendung in einzelne kleinere Dienste besteht in der Verbesserung der Modularität . In dieser Form ist die Anwendung leichter zu verstehen, zu entwickeln, zu testen und die Anwendung selbst wird widerstandsfähiger gegen Erosion der Architektur. Mit diesem Architekturansatz wird die Entwicklung parallelisiert, und kleine autonome Teams erhalten die Möglichkeit, die Dienste, für die sie verantwortlich sind, eigenständig zu entwickeln , bereitzustellen und zu skalieren . Auch mit diesem Ansatz kann kontinuierliches Refactoring auf die Architektur jedes Dienstes angewendet werden. Microservice-Architekturen sind auch für die kontinuierliche Bereitstellung und Bereitstellung konzipiert .
en.wikipedia.org/wiki/Microservices
Hier ist eine weitere Passage von Martin Fowler:
Der Begriff „Microservice-Architektur“ ist in den letzten Jahren fest verwurzelt, um eine bestimmte Methode zum Entwerfen solcher Anwendungen zu beschreiben, bei denen es sich jeweils um eine Reihe von unabhängig implementierten Diensten handelt . Obwohl es keine genaue Definition dieses Architekturstils gibt, gibt es eine Reihe allgemeiner Merkmale in Bezug auf die Organisation der Anwendung im Hinblick auf ihre Geschäftsfunktionen, die automatisierte Bereitstellung, die Erfassung von Informationen über Terminals und die dezentrale Verwaltung von Sprachen und Daten .
martinfowler.com/articles/microservices.html
Sie haben wahrscheinlich bemerkt, dass die Hauptähnlichkeit zwischen diesen beiden Formulierungen die Unabhängigkeit von Diensten und Optionen ist. Versuchen wir nun, ein paar Fragen zu beantworten und herauszufinden, ob das von Ihnen implementierte System eine Microservice-Basis hat!
Ermöglicht Ihr System den unabhängigen Neustart von Diensten?Oder müssen Sie die Dienste in einer bestimmten Reihenfolge neu starten? Dieses Verhalten kann von bestimmten Clustersystemen vorgegeben werden, bei denen der Knoten eine Verbindung zum Seed-Knoten herstellt, z. B. im Akka-Cluster, wenn er nicht ordnungsgemäß behandelt wird. In anderen Fällen kann es sich um langlebige Verbindungen oder um Buchsen handeln, die nur auf einer Seite geöffnet werden können. Denken Sie daran, dass die Kommunikation einfach und unkompliziert bleiben sollte. Noch besser, wenn es vollständig asynchron und nachrichtenbasiert ist. Alle Einschränkungen, die dazu führen, dass die Dienste langfristig voneinander abhängig sind, können zu Supportproblemen führen. Probleme mit einem der Dienste können Probleme mit allen anderen davon abhängigen Diensten verursachen, die eines Tages zu einem schwerwiegenden globalen Fehler führen können.
Können Sie Dienste unabhängig voneinander bereitstellen?Es gibt Fälle, in denen die Freigabe und Bereitstellung aller Dienste im System gleichzeitig erfolgen sollte. Dieser Vorgang dauert mehrere Tage. In diesem Fall sind die Möglichkeiten zur Einführung einer kontinuierlichen Bereitstellung natürlich begrenzt, es treten Verzögerungen auf, und die Reaktionsfähigkeit verschlechtert sich. Die Behebung dringender Fehler nimmt zu viel Zeit in Anspruch, allein aufgrund der mit dem Bereitstellungsprozess verbundenen Kosten. Wenn verschiedene Teams verschiedene Dienste unterstützen, kann jede Bereitstellungsabhängigkeit andere Teams daran hindern, ihre Dienste bereitzustellen, was dazu führt, dass die Arbeit angehalten wird und ihre Effektivität abnimmt.
Kann eine Änderung dazu führen, dass andere Dienste synchronisiert geändert werden müssen?Man kann sich die vielen Gründe vorstellen, die zu diesem Verhalten führen. Zunächst sind dies API-Änderungen. Es kann vorkommen, dass es ausreicht, der API-Anfrage ein neues Feld hinzuzufügen, damit die Kompatibilität zwischen den Diensten unterbrochen wird. Es gibt jedoch Problemumgehungen für die folgenden Situationen:
- Möglicherweise möchten Sie die obligatorische Abwärtskompatibilität für alle an der API vorgenommenen Änderungen beibehalten. Das heißt, wenn eine grundlegende Änderung vorgenommen wird, wird eine neue Version der API hinzugefügt. Dies bedeutet nicht, dass Sie immer viele Versionen der API unterstützen müssen. Sie benötigen sie nur für den Zeitraum bis zum Abschluss der Migration. Sie können einfach mit anderen Teams sprechen und sicherstellen, dass alle die Migration abgeschlossen haben, oder Metriken aktivieren, um zu beurteilen, ob eine bestimmte API noch verwendet wird.
- Sie können diese Option auch in Betracht ziehen: Stellen Sie mehrere Versionen Ihrer Anwendung gleichzeitig bereit, damit andere Dienste auf die neueste Version wechseln können, und deaktivieren Sie dann die alte.
- Versuchen Sie auch, Formate zu verwenden, die die Entwicklung von Schaltkreisen unterstützen, z. B. Avro , bei denen beim Hinzufügen eines neuen Felds die Kompatibilität möglicherweise nicht verletzt wird. Wenn ein Wert für ein Feld fehlt, kann der Standardwert verwendet werden.
Ein weiterer Grund für die synchronisierte Bereitstellung ist die Verwendung von gemeinsam genutztem Code durch verschiedene Dienste. Abhängig davon, wie der Freigabeprozess im gemeinsam genutzten Teil des Codes erstellt wird, müssen möglicherweise alle Dienste aktualisiert werden.
Verursacht eine Datenbankänderung eine Änderung in vielen Diensten?Ja, die Kommunikation über eine Datenbank ist ein bekanntes Antimuster. In einer solchen Situation ist es erforderlich, das Schema zu aktualisieren und gleichzeitig den Code mehrerer Mikrodienste zu ändern. Es ist besser sicherzustellen, dass nur ein Dienst für die Verwaltung des Stromkreises verantwortlich ist. In diesem Fall wird es viel einfacher, die Datenbank zu warten (dh ihre Aktualisierungen durchzuführen) und Releases zu implementieren. Wenn Sie bereits in der Lage sind, gemeinsam genutzte Datenbanken zu verwenden, versuchen Sie, die Anzahl der Schreibvorgänge zu begrenzen, damit ein anderer Dienst nur für den Verbrauch verwendet werden kann.
Können Sie eine Abhängigkeit oder Version von Java in einem einzigen Service aktualisieren?Theoretisch sollte es immer möglich sein, oder? Wirklich nicht. Es gibt viele Beispiele für "gemeinsam genutzte" Bibliotheken oder nur Projekte, die Definitionen aller im System verwendeten Abhängigkeiten enthalten. Das Ziel des Microservices-Paradigmas ist es, sicherzustellen, dass jeder von ihnen eine unabhängige Einheit ist und dass nicht einmal verschiedene Microservices im selben technologischen Stapel geschrieben werden müssen. Wenn Sie ein neues Projekt starten, sollten Sie selbst entscheiden können, welche Technologie dafür am besten geeignet ist. Jede Bindung wird neue Probleme verursachen. Irgendwann müssen Sie möglicherweise ein Upgrade auf Scala oder JDK durchführen, aber Sie möchten dies natürlich nicht sofort im gesamten System tun. In einem System, in dem der Detaillierungsgrad korrekt eingehalten wird, können Sie einen einzelnen Dienst aktualisieren, bereitstellen, mehrere Tage oder Wochen lang testen und überwachen. Wenn alles in Ordnung ist, können Sie Aktualisierungen im Rest des Systems durchführen. Wenn jedoch
common
oder andere starke Vereinigungsmechanismen existieren, sind diese Möglichkeiten stark eingeschränkt.
Zwingt Sie das von Ihnen gewählte Framework oder die Bibliothek, bei anderen Diensten die gleiche Wahl zu treffen?Einige Bibliotheken sind ziemlich invasiv. Wenn Sie sich für die Integration in externe Systeme entscheiden, kann sich plötzlich herausstellen, dass Ihre Auswahl nicht so groß ist, wenn Sie einen neuen Service auf einem anderen technologischen Stack implementieren. Die mit der Integration verbundenen Kosten sind möglicherweise einfach unerträglich.
Angenommen, Sie haben mehrere in
NodeJS geschriebene
Services , die aktiv die
JSON: API verwenden . Als nächstes möchten Sie einen neuen Dienst auf Scala implementieren, und es scheint, dass es keine geeignete Client-Bibliothek gibt (vor ein paar Jahren hatten wir einen ähnlichen Fall, aber jetzt hat sich die Situation in diesem Bereich leicht verbessert).
Verursacht der Ausfall eines einzelnen Dienstes einen Ausfall des gesamten Systems?Angenommen, die Kommunikation in Ihrem System ist vollständig synchron. Ein Dienst stellt eine Anfrage an einen anderen und wartet auf eine Antwort von diesem. Wenn der erste Dienst fehlschlägt, kann der zweite Dienst überhaupt nicht ausgeführt werden. Wenn dies in Ihrem System der Fall ist, versuchen Sie, eine asynchrone nachrichtenbasierte Kommunikation zu implementieren. Es mag etwas schwieriger sein, alle Prozesse zu simulieren, aber dieser Ansatz ermöglicht es Ihnen, die Auswirkungen von Fehlern auszugleichen.
In Fällen, in denen dies nicht möglich ist, können Sie versuchen, den Funktionsumfang der Anwendung vorübergehend einzuschränken. Auf der Seite des Onlineshops werden beispielsweise Informationen zum Produkt und Bewertungen angezeigt. Darüber hinaus stammen Produktinformationen und Bewertungen aus zwei verschiedenen Quellen. Wenn der Microservice für Überprüfungen nicht funktioniert, können Sie die Produktseite dennoch anzeigen, indem Sie den Benutzer lediglich darüber informieren, dass das Überprüfungssystem vorübergehend nicht verfügbar ist.
Befindet sich eine gemeinsam genutzte Komponente auf Ihrem System?Haben Sie Code geteilt? Konfiguration? Irgendwas? Ja, das ist eine nicht triviale Frage. Befürworter der Sauberkeit von Mikrodiensten sind der Ansicht, dass es am besten ist, geteilte Einheiten überhaupt nicht im System zuzulassen! Es ist besser, nur den Code zu kopieren als ihn zu teilen. In der Praxis wird es manchmal als akzeptabel angesehen, mehrere
gemeinsam genutzte Bibliotheken zu haben, jedoch mit strengen Einschränkungen. Vielleicht handelt es sich um Bibliotheken, die
proto
für
Protokollpuffer oder nur gewöhnliche POJO-Objekte enthalten. Vermeiden Sie Abhängigkeiten in solchen Bibliotheken. Wir hatten einen Fall, in dem eine einfache Clientbibliothek in einem großen System zu Abhängigkeitskonflikten führte. Irgendwann schien es, dass die ältesten Elemente der Anwendung die alte HTTP-Bibliothek verwendeten, die nicht aktualisiert werden konnte. Glücklicherweise können diese Situationen vermieden werden, indem Abhängigkeiten im Erstellungsprozess umbenannt werden (Abhängigkeitsschattierung). Seien Sie jedoch sehr vorsichtig.
Der Schaden durch übermäßige Kohäsion von Diensten ist weitaus größer als bei Problemen, die durch die Wiederholbarkeit von Code verursacht werden.
Sam Newman, Erstellen von Microservices
SchlussfolgerungenDie Implementierung des perfekten Mikroservice-basierten Systems ist keine leichte Aufgabe. Die Leute neigen dazu, „Ecken und Kanten abzuschneiden“ und enge Bindungen in das System einzuführen, die sich aus gemeinsamem Code ergeben, und irgendwann wird ein solches System in der Praxis zu einem verteilten Monolithen. Dies ist häufig der Fall, wenn Microservices bereits zu Beginn des Projekts eingesetzt werden, wenn das Fachgebiet noch nicht ausreichend erforscht ist und Sie keinen soliden Hintergrund in DevOps haben. Es ist besser, mit einem
richtig strukturierten Monolithen zu beginnen , bei dem alle Verantwortungsbereiche vollständig bekannt sind und sich leicht voneinander trennen lassen. Sie müssen jedoch von Anfang an sicherstellen, dass Ihr System
sauber aufgebaut ist und die Paketorganisation sorgfältig eingehalten wird, um anschließend eine einfache Codemigration zu neuen Diensten zu ermöglichen (z. B. kann ein einzelnes "fast Top-Level" -Paket die Basis für einen neuen Mikroservice sein). .
ArchUnit kann bei der Analyse von Abhängigkeiten helfen, die zwischen Paketen auftreten.
(...) Sie sollten mit der Einführung von Microservices nicht sofort mit der Arbeit an einem neuen Projekt beginnen, auch wenn Sie sicher sind, dass Ihre Bewerbung groß genug ist, damit sich die Microservices rechtfertigen.
martinfowler.com/bliki/MonolithFirst.html
Denken Sie daran, dass Microservices sowohl die Entwicklung als auch den Support vereinfachen sollten! Sie benötigen lediglich lose gekoppelte Dienste, von denen jeder unabhängig von den anderen bereitgestellt werden kann.