Einführung in Mikrodienste

Last reviewed 2021-06-24 UTC

Dieser Referenzleitfaden ist der erste in einer vierteiligen Reihe zum Entwerfen, Erstellen und Bereitstellen von Mikrodiensten. In dieser Reihe werden die verschiedenen Elemente einer Mikrodienstarchitektur beschrieben. Die Reihe enthält Informationen zu den Vor- und Nachteilen des Mikrodienstarchitekturmusters und zu ihrer Anwendung.

  1. Einführung in Mikrodienste (dieses Dokument)
  2. Monolithische Anwendung in Mikrodienste refaktorieren
  3. Kommunikation zwischen Diensten in einem Mikrodienst-Setup
  4. Verteiltes Tracing in Mikrodienstanwendungen

Diese Serie richtet sich an Anwendungsentwickler und Architekten, die Migrationen entwerfen und implementieren, um eine monolithische Anwendung in eine Mikrodienstanwendung zu refaktorieren.

Monolithische Anwendungen

Eine monolithische Anwendung ist eine einschichtige Softwareanwendung, bei der verschiedene Module zu einem einzigen Programm kombiniert werden. Wenn Sie beispielsweise eine E-Commerce-Anwendung erstellen, muss diese eine modulare Architektur haben, die an den objektorientierten Programmierprinzipien (OOP) ausgerichtet ist. Das folgende Diagramm zeigt ein Beispiel für eine E-Commerce-Anwendung, bei der die Anwendung aus verschiedenen Modulen besteht. In einer monolithischen Anwendung werden Module mithilfe einer Kombination aus Programmiersprachenkonstrukten (z. B. Java-Paketen) und Build-Artefakten (z. B. Java-JAR-Dateien) definiert.

Eine monolithische Anwendung nutzt mehrere Module.

Abbildung 1. Diagramm einer monolithischen E-Commerce-Anwendung mit mehreren Modulen, die eine Kombination aus Programmiersprachen-Konstrukten verwendet.

In Abbildung 1 entsprechen die verschiedenen Module der E-Commerce-Anwendung der Geschäftslogik für Zahlungs-, Liefer- und Bestellverwaltung. Alle diese Module werden als einzelne logische ausführbare Datei gepackt und bereitgestellt. Das tatsächliche Format hängt von der Sprache und dem Framework der Anwendung ab. Viele Java-Anwendungen werden beispielsweise als JAR-Dateien gepackt und auf Anwendungsservern wie Tomcat oder Jetty bereitgestellt. Ähnlich wird eine Rails- oder Node.js-Anwendung als Verzeichnishierarchie verpackt.

Vorteile von monolithischen Anwendungen

Die monolithische Architektur ist eine konventionelle Lösung zum Erstellen von Anwendungen. Im Folgenden sind einige Vorteile der Nutzung eines monolithischen Designs für Ihre Anwendung aufgeführt:

  • Sie können End-to-End-Tests einer monolithischen Anwendung mit Tools wie Selenium implementieren.
  • Zur Bereitstellung einer monolithischen Anwendung kopieren Sie das Anwendungspaket einfach auf einen Server.
  • Alle Module in einer monolithischen Anwendung teilen sich Arbeitsspeicher, Speicherplatz und Ressourcen, sodass Sie eine einzige Lösung verwenden können, um übergreifende Belange wie Logging, Caching und Sicherheit zu berücksichtigen.
  • Der monolithische Ansatz kann Leistungsvorteile bieten, da Module einander direkt aufrufen können. Im Gegensatz dazu benötigen Mikrodienste in der Regel einen Netzwerkaufruf, um miteinander zu kommunizieren.

Probleme bei monolithischen Anwendungen

Komplexe monolithische Anwendungen werden oft immer schwieriger zu erstellen, zu debuggen und zu verstehen. Irgendwann überwiegen die Nachteile die Vorteile.

  • Anwendungen wachsen in der Regel im Laufe der Zeit. Es kann kompliziert sein, Änderungen an einer großen und komplexen Anwendung mit eng gekoppelten Modulen zu implementieren. Da sich jede Codeänderung auf das gesamte System auswirkt, müssen Änderungen umfassend koordiniert werden. Die Koordination von Änderungen verlängert den Entwicklungs- und Testprozess im Vergleich zu Mikrodienstanwendungen insgesamt deutlich.
  • Es kann schwierig sein, eine kontinuierliche Integration und Bereitstellung (CI/CD) bei einer großen monolithischen Anwendung zu erreichen. Das Problem ist hier, dass Sie die gesamte Anwendung noch einmal bereitstellen müssen, um einen Teil davon zu aktualisieren. Außerdem müssen Sie wahrscheinlich umfassende manuelle Tests der gesamten Anwendung durchführen, um nach Regressionen zu suchen.
  • Es kann schwierig sein, monolithische Anwendungen zu skalieren, wenn in verschiedenen Modulen widersprüchliche Ressourcenanforderungen auftreten. Beispielsweise kann ein Modul eine CPU-intensive Bildverarbeitungslogik implementieren. Ein anderes Modul könnte eine In-Memory-Datenbank sein. Da diese Module gemeinsam bereitgestellt werden, müssen Sie bei der Auswahl der Hardware Kompromisse eingehen.
  • Da alle Module im selben Prozess ausgeführt werden, kann ein Programmfehler in einem beliebigen Modul, z. B. ein Speicherleck, das gesamte System zum Absturz bringen.
  • Monolithische Anwendungen fügen Komplexität hinzu, wenn Sie neue Frameworks und Sprachen einführen möchten. Beispiel: Es kostet viel Zeit und Geld, eine ganze Anwendung neu zu schreiben, um ein neues Framework zu verwenden, auch wenn dieses Framework erheblich besser ist.

Auf Mikrodiensten basierende Anwendungen

Ein Mikrodienst implementiert in der Regel eine Reihe unterschiedlicher Features oder Funktionen. Jeder Mikrodienst ist eine Minianwendung mit eigener Architektur und eigener Geschäftslogik. Einige Mikrodienste stellen beispielsweise eine API bereit, die von anderen Mikrodiensten oder von den Anwendungsclients genutzt wird, z. B. Integrationen von Drittanbietern in Zahlungsgateways und Logistikanwendungen.

Abbildung 1 zeigt eine monolithische E-Commerce-Anwendung mit mehreren Modulen. Das folgende Diagramm zeigt eine mögliche Aufteilung der E-Commerce-Anwendung in Mikrodienste:

Eine monolithische Anwendung wird in Mikrodienste zerlegt.

Abbildung 2. Diagramm einer E-Commerce-Anwendung mit funktionalen Bereichen, die durch Mikrodienste implementiert werden.

In Abbildung 2 implementiert ein dedizierter Mikrodienst den jeweiligen Funktionsbereich der E-Commerce-Anwendung. Jeder Backend-Dienst kann eine API bereitstellen und Dienste verbrauchen APIs, die von anderen Diensten bereitgestellt werden. Zum Rendern von Webseiten rufen die UI-Dienste beispielsweise den Checkout-Dienst und andere Dienste auf. Dienste können auch asynchrone, nachrichtenbasierte Kommunikation verwenden. Weitere Informationen zur Kommunikation von Diensten finden Sie im dritten Dokument dieser Reihe, Interservice-Kommunikation in einer Mikrodiensteinrichtung.

Das Mikrodienst-Architekturmuster ändert die Beziehung zwischen der Anwendung und der Datenbank erheblich. Anstatt eine einzelne Datenbank für andere Dienste freizugeben, empfehlen wir, dass jeder Dienst eine eigene Datenbank erhält, die auf seine Anforderungen zugeschnitten ist. Wenn Sie für jeden Dienst eine Datenbank haben, sorgen Sie für eine lose Verknüpfung von Diensten, da alle Datenanfragen über die Dienst-API und nicht direkt über die gemeinsam genutzte Datenbank laufen. Das folgende Diagramm zeigt das Muster einer Mikrodienstarchitektur, wobei jeder Dienst eine eigene Datenbank hat:

Jeder Mikrodienst hat eine eigene Datenbank.

Abbildung 3. Jeder Dienst in einer Mikrodienstarchitektur hat seine eigene Datenbank.

In Abbildung 3 funktioniert der Bestelldienst in der E-Commerce-Anwendung gut mit einer dokumentenbasierten Datenbank mit Echtzeit-Suchfunktionen. Die Zahlungs- und Lieferdienste basieren auf den starken Garantien der Atomarität, Konsistenz, Isolation, Langlebigkeit (ACID) einer relationalen Datenbank.

Vorteile von Mikrodiensten

Das Mikrodienstarchitekturmuster behebt das Problem der Komplexität, das im vorherigen Abschnitt (Monolithische Herausforderungen) beschrieben wurde. Mikrodienstarchitekturen bieten folgende Vorteile:

  • Obwohl die Gesamtfunktion unverändert bleibt können Sie mit Mikrodiensten die Anwendung in überschaubare Blöcke oder Dienste unterteilen. Jeder Dienst hat eine klar definierte Grenze in Form einer RPC- oder Nachrichten-API. Das kann dazu beitragen, dass einzelne Dienste schneller entwickelt und einfacher verstanden und gewartet werden können.
  • Autonome Teams können einzelne Dienste unabhängig voneinander entwickeln. Sie können Mikrodienste an Geschäftsgrenzen organisieren, nicht aber an den technischen Möglichkeiten eines Produkts. Sie organisieren Ihre Teams für eine einzelne, unabhängige Verantwortung für den gesamten Lebenszyklus ihrer zugewiesenen Software, von der Entwicklung über Tests über die Bereitstellung bis hin zu Wartung und Monitoring.
  • Beim unabhängigen Mikrodienstentwicklungsprozess können Entwickler außerdem jeden Mikrodienst in einer anderen Programmiersprache schreiben und so eine polyglotte Anwendung erstellen. Wenn Sie für jeden Mikrodienst die jeweils effektivste Sprache verwenden, können Sie eine Anwendung schneller entwickeln und Ihre Anwendung optimieren, um die Codekomplexität zu reduzieren und die Leistung und Funktionalität zu erhöhen.
  • Wenn Sie Funktionen von einem monolithischen Netzwerk trennen, können die unabhängigen Teams ihren Mikrodienst unabhängig freigeben. Unabhängige Release-Zyklen können die Geschwindigkeit Ihres Teams verbessern und die Produkteinführungszeit beschleunigen.
  • Dank der Mikrodienstarchitektur können Sie jeden Dienst auch unabhängig skalieren. Sie können die Anzahl an Dienstinstanzen an nach deren Kapazitäts- und Verfügbarkeitsbeschränkungen anpassen. Sie können auch die Hardware verwenden, die den Ressourcenanforderungen des jeweiligen Dienstes am besten entspricht. Wenn Sie Dienste unabhängig voneinander skalieren, können Sie Verfügbarkeit und Zuverlässigkeit des gesamten Systems erhöhen.

Im Folgenden finden Sie einige Beispiele für Fälle, in denen es sinnvoll sein kann, von einer monolithischen Anwendung zu einer Mikrodienstarchitektur zu migrieren:

  • Implementierungen von Verbesserungen bei Skalierbarkeit, Verwaltung, Agilität oder Geschwindigkeit der Bereitstellung.
  • Inkrementelles Umschreiben einer großen Legacy-Anwendung auf eine moderne Sprache und einen modernen Technology Stack, um neue Geschäftsanforderungen zu erfüllen.
  • Extrahieren von Querschnittsanwendungen und Querschnittsdiensten, damit Sie diese in mehreren Kanälen wiederverwenden können. Dienste, die Sie wiederverwenden können, sind beispielsweise Zahlungsdienste, Anmeldedienste, Verschlüsselungsdienste, Flugsuchdienste, Kundenprofildienste und Benachrichtigungsdienste.
  • Übernahme einer speziell entwickelten Sprache oder eines Frameworks für eine bestimmte Funktionalität einer bestehenden monolithischen Anwendung.

Herausforderungen bei Mikrodiensten

Mikrodienste bedingen im Vergleich zu monolithischen Anwendungen einige Herausforderungen. Dazu gehören:

  • Eine große Herausforderung bei Mikrodiensten ist die Komplexität, die entsteht, da die Anwendung ein verteiltes System ist. Entwickler müssen einen Mechanismus zur Kommunikation zwischen Diensten wählen und implementieren. Die Dienste müssen auch partielle Fehler und die Nichtverfügbarkeit von Upstream-Diensten bewältigen können.
  • Eine weitere Herausforderung bei Mikrodiensten besteht darin, dass Sie Transaktionen über verschiedene Mikrodienste hinweg verwalten müssen (auch als verteilte Transaktion bezeichnet). Geschäftsvorgänge, die mehrere Geschäftsentitäten aktualisieren, sind relativ üblich und werden normalerweise atomar angewendet, wobei entweder alle Vorgänge angewendet werden oder alles fehlschlägt. Wenn Sie mehrere Vorgänge in einer einzigen Datenbanktransaktion zusammenfassen, sorgen Sie für Atomarität.

    In einer auf Mikrodiensten basierenden Anwendung können Geschäftsvorgänge möglicherweise auf verschiedene Mikrodienste verteilt sein. Daher müssen Sie mehrere Datenbanken aktualisieren, die verschiedenen Diensten gehören. Wenn ein Fehler auftritt, ist es nicht ganz einfach, Ausfall oder Erfolg von Aufrufen an die verschiedenen Mikrodienste und den Rollback-Status zu verfolgen. Im ungünstigsten Fall kann es, wenn das Rollback des Zustands aufgrund von Fehlern nicht korrekt durchgeführt wurde, zu inkonsistenten Daten zwischen Diensten kommen. Informationen zu den verschiedenen Methoden zum Einrichten verteilter Transaktionen zwischen Diensten finden Sie im dritten Dokument dieser Serie, Dienstübergreifende Kommunikation in einer Mikrodienst-Einrichtung.

  • Umfassende Tests von auf Mikrodiensten basierenden Anwendungen sind komplexer als Tests monolithischer Anwendungen. Beispiel: Wenn Sie die Funktionalität der Bearbeitung einer Bestellung in einem monolithischen E-Commerce-Dienst testen möchten, wählen Sie Artikel aus, legen sie in Ihren Einkaufswagen und gehen dann zur Kasse. Wenn Sie denselben Ablauf in einer auf Mikrodiensten basierenden Architektur testen möchten, rufen Sie Dienste wie Frontend, Bestellung und Zahlung auf, um den Testlauf abzuschließen.

  • Die Bereitstellung einer auf Mikrodiensten basierenden Anwendung ist komplexer als die Bereitstellung einer monolithischen Anwendung. Eine Mikrodienstanwendung besteht in der Regel aus vielen Diensten, von denen jeder mehrere Laufzeitinstanzen hat. Sie müssen außerdem einen Diensterkennungsmechanismus implementieren, mit dem ein Dienst die Standorte anderer Dienste ermitteln kann, mit denen er kommunizieren muss.

  • Eine Mikrodienstarchitektur erhöht den Vorgangsaufwand, da weitere Dienste überwacht und gemeldet werden müssen. Außerdem weist die Mikrodienstarchitektur aufgrund der erhöhten Kommunikation zwischen Diensten auch mehr Points of Failure auf. Eine monolithische Anwendung kann in einem kleinen Anwendungsserver-Cluster bereitgestellt werden. Eine auf Mikrodiensten beruhende Anwendung kann Dutzende von separaten Diensten zum Erstellen, Testen, Bereitstellen und Ausführen umfassen, möglicherweise in mehreren Sprachen und Umgebungen. Alle diese Dienste müssen für Failover und Ausfallsicherheit geclustert werden. Die Produktion einer Mikrodienstanwendung erfordert eine hochwertige Monitoring- und Betriebsinfrastruktur.

  • Die Aufteilung von Diensten in einer Mikrodienst-Architektur ermöglicht es der Anwendung, mehr Funktionen gleichzeitig auszuführen. Da die Module jedoch als isolierte Dienste laufen, kommt es aufgrund von Netzwerkaufrufen zwischen den Diensten zu einer Latenz in der Reaktionszeit.

  • Nicht alle Anwendungen sind groß genug, um in Mikrodienste aufzuteilen. Außerdem erfordern einige Anwendungen eine enge Integration zwischen Komponenten, beispielsweise Anwendungen, die schnelle Streams von Echtzeitdaten verarbeiten müssen. Jede zusätzliche Kommunikationsschicht zwischen Diensten kann die Verarbeitung in Echtzeit verlangsamen. Wenn Sie die Kommunikation zwischen den Diensten bereits im Voraus betrachten, können Sie hilfreiche Informationen erhalten, wenn Sie die Dienstgrenzen eindeutig markieren.

Berücksichtigen Sie bei der Entscheidung, ob die Mikrodienstarchitektur für Ihre Anwendung die beste Wahl ist, folgende Punkte:

  • Best Practices für Mikrodienste erfordern dienstspezifische Datenbanken. Achten Sie bei der Datenmodellierung für Ihre Anwendung darauf, ob die dienstspezifischen Datenbanken zu Ihrer Anwendung passen.
  • Wenn Sie eine Mikrodienstarchitektur implementieren, müssen Sie die Umgebung instrumentieren und überwachen, damit Sie Engpässe identifizieren, Fehler erkennen und verhindern und Diagnosevorgänge unterstützen können.
  • In einer Mikrodienstarchitektur hat jeder Dienst eine separate Zugriffssteuerung. Zum Schutz der Sicherheit müssen Sie den Zugriff auf jeden Dienst sowohl innerhalb der Umgebung als auch über externe Anwendungen sichern, die seine APIs nutzen.
  • Die synchrone Kommunikation zwischen Diensten senkt in der Regel die Verfügbarkeit einer Anwendung. Beispiel: Wenn der Auftragsdienst in einer E-Commerce-Anwendung andere vorgelagerte Dienste aufruft und diese Dienste nicht verfügbar sind, kann kein Auftrag erstellt werden. Daher empfehlen wir, eine asynchrone, nachrichtenbasierte Kommunikation zu implementieren.

Wann eine monolithische Anwendung auf Mikrodienste migriert werden sollte

Wenn Sie bereits eine monolithische Anwendung ausführen, entstehen durch die Einführung von Mikrodiensten erhebliche Investitionskosten für Ihr Team. Verschiedene Teams implementieren die Mikrodienst-Prinzipien unterschiedlich. Bei jedem Entwicklerteam sind die Ergebnisse im Hinblick darauf verschieden, wie klein die Mikrodienste sind oder wie viele Mikrodienste benötigt werden.

Bestimmen Sie, welche Mikrodienste für Ihre Anwendung am besten geeignet sind, zuerst die wichtigsten Geschäftsziele oder Problempunkte. Es kann einfacher sein, Ihre Ziele zu erreichen oder die von Ihnen erkannten Probleme zu beheben. Wenn Sie Ihre Anwendung beispielsweise schneller skalieren möchten, ist Autoscaling möglicherweise eine effizientere Lösung. Wenn Sie Fehler in der Produktion finden, können Sie zuerst Einheitentests und Continuous Integration (CI) implementieren.

Wenn Sie davon überzeugt sind, dass ein Mikrodienst-Ansatz der beste Weg ist, um Ihre Ziele zu erreichen, beginnen Sie damit, einen Dienst aus der monolithischen Anwendung zu extrahieren und diesen zu entwickeln, zu testen und in der Produktion bereitzustellen. Weitere Informationen finden Sie im nächsten Dokument dieser Reihe, Monolithische Anwendung in Mikrodienste refaktorieren. Nachdem Sie einen Dienst erfolgreich extrahiert haben und dieser in der Produktion läuft, beginnen Sie mit der Extraktion des nächsten Dienstes und lernen aus jedem Zyklus weiter.

Durch das Mikrodienstarchitekturmuster wird ein System in eine Reihe von unabhängig bereitstellbaren Diensten aufgeteilt. Wenn Sie eine monolithische Anwendung entwickeln, müssen Sie große Teams koordinieren, was die Softwareentwicklung verlangsamen kann. Wenn Sie eine Mikrodienstarchitektur implementieren, ermöglichen Sie kleinen, autonomen Teams, parallel zu arbeiten, was die Entwicklung beschleunigen kann.

Im nächsten Dokument dieser Serie, Monolithische Anwendung in Mikrodienste refaktorieren, lernen Sie verschiedene Strategien zur Refaktorierung von monolithischen Anwendung in Mikrodiensten kennen.

Nächste Schritte