Testen von Microservice-orientierten Anwendungen

Hallo Habr! Wir setzen



das Studium des Themas Microservices fort und bieten Ihnen eine Übersetzung eines Artikels zum Testen von MOA (Microservice-orientierte Anwendungen) an. Vor kurzem haben wir uns bereits mit dem Thema Testen befasst. Bei Microservices reichen regelmäßige Unit-Tests jedoch nicht aus. Sie müssen auch Aspekte in Bezug auf CI / CD und andere Aspekte berücksichtigen, die in diesem Artikel behandelt werden.







Microservices sind ein neuer Stil der Softwarearchitektur, der bei der Erstellung verteilter Systeme verwendet wird, und werden zunehmend in Unternehmen implementiert, die im Web tätig sind, einschließlich der größten. Beispielsweise haben Netflix und Amazon eine Microservice-Architektur eingeführt, um die Veröffentlichung von Softwareprodukten erheblich zu beschleunigen. Gleichzeitig können ältere monolithische Systeme nicht mit einer Geschwindigkeit skaliert werden, die modernen Herausforderungen gerecht wird.



Die Vorteile einer Microservice-Architektur sind jedoch nur so gut, wie die Best Practices zur Unterstützung getestet werden können. Bei der Entwicklung von Tests zur Validierung von Microservices-Systemen, bei denen die Freisetzungsrate als blitzschnell beschrieben werden kann, ist innovatives Denken sowohl auf Mikro- als auch auf Makroebene erforderlich.



Als Nächstes werden wir die drei Arten von Microservice-orientierten Anwendungen untersuchen, einige der Herausforderungen erörtern, die Sie zum Testen bewältigen müssen, und darüber sprechen, wie Tests geschrieben werden, um die Vorteile von Microservices voll zu nutzen.



Kurz über Microservices



Bevor wir uns mit den Feinheiten des Entwurfs von Tests für Mikrodienste befassen, werfen wir einen Blick auf die Mikrodienste. Microservice ist eine detaillierte Softwarekomponente, die eine klare semantische Definition erhalten hat. Der Microservice verfügt jedoch über einen eigenen Datensatz und ist nicht von anderen Datenstrukturen und Datenquellen abhängig. Jeder Mikrodienst verfügt über einen eigenen Bereitstellungszyklus. Nachdem Änderungen am Mikrodienst vorgenommen wurden, können Sie ihn freigeben, ohne die Arbeit anderer Mikrodienste im Bereich der Anwendung zu unterbrechen, mit der dieser Mikrodienst ausgeführt wird.



Vorteile von Mikrodiensten gegenüber monolithischen Anwendungen



Schauen wir uns auch an, was ein Microservice nicht ist. Die folgende Abbildung zeigt ein Beispiel für eine typische monolithische Anwendung.







Zahl: 1: Monolithische Anwendungsarchitekturen weisen typischerweise eine starke Komponentenkohäsion auf



Die Komponenten Kunden, Produkte, Bestellungen und (Kommentare) können als eine Reihe von Klassen betrachtet werden, die in einer objektorientierten Sprache wie Java oder C # geschrieben sind, wobei Kunden ein Array von Objekten ist, die Kunden, Produkten - einem Array - entsprechen von Gegenständen, die Produkten usw. entsprechen Das Kundenobjekt kann sowohl das Kundenobjekt als auch das Produktobjekt verwenden. Aufgrund der Tatsache, dass alle Komponenten einer monolithischen Anwendung auf dieselbe Datenbank zugreifen, kann das Bestellobjekt auch direkt auf die Datenbank zugreifen und alle Informationen über das Produkt und die Bestellung abrufen, die zur Ausführung der Aufgaben erforderlich sind. Ein direkter Zugriff auf die Datenbank ist nicht nur möglich - und inwieweit widerspricht dies dem Geist der objektorientierten Programmierung auf der Grundlage einer objektrelationalen Zuordnung ORM - aber es wird auch aktiv eingesetzt, insbesondere in den Bereichen, in denen zum vereinbarten Zeitpunkt eine hohe Nachfrage nach vorgefertigten Funktionen besteht, unabhängig von den Kosten.



Das Ergebnis ist ein eng gekoppeltes, manchmal fragiles System, bei dem die Veröffentlichung einer neuen Version einer Anwendung eine erhebliche Koordination zwischen allen an der Entwicklung dieses Systems beteiligten Entwicklungsteams erfordert. Aufgrund der starken Kopplung kann der gesamte Release-Zyklus nicht schneller verlaufen als die langsamste Arbeit zur Neuverhandlung einer Abhängigkeit. Mit anderen Worten, wenn es an der Zeit ist, die Anwendung zu aktualisieren und eine neue Funktion von Kunden und eine neue Funktion von Produkten hinzuzufügen, erfolgt die Freigabe erst, wenn beide Funktionen bereit sind. Wenn ein Produktupdate einen Tag und eine Kundenänderung drei Wochen dauert, erfolgt die Freigabe frühestens nach drei Wochen. Darüber hinaus kann es erforderlich sein, nicht nur den neuen Kodex für Kunden und Waren zu koordinieren, was die Situation während der Veröffentlichung weiter verschärft.Nehmen Sie aber auch Änderungen am Datenbankschema vor, die auch während des Freigabeprozesses verwaltet werden müssen.



Das Freigeben von Änderungen an einer Datenbank ist ein sehr heikles Unterfangen. Beim Ändern der Datenbankstruktur besteht immer das Risiko unbeabsichtigter Nebenwirkungen. Denken Sie daran, dass eine Komponente, die auf die Datenbank zugreifen kann, darauf zugreifen und sogar Vorgänge mit den Daten ausführen kann, die nicht im Umfang dieser Komponente liegen. Eine solche "Manipulation außerhalb des Bereichs" kann zu Ausfällen anderer Komponenten führen, und solche Ausfälle können unbemerkt bleiben, bis eine Katastrophe eintritt. Manchmal kann eine potenzielle Gefahr im Code bis zur Freigabe dieses Codes in der Produktion gefunden werden. Leider passiert dies die ganze Zeit.

Einige Unternehmen sind bereit, die für die Arbeit mit monolithischen Anwendungen typischen langsamen Release-Zyklen in Kauf zu nehmen. Wenn es sich jedoch um ein Unternehmen handelt, das Hunderttausende von Benutzern unterstützt und gleichzeitig Tausende von Komponenten in funktionsfähiger Form halten muss, ist das Tempo "nicht schneller als die Veröffentlichung der spätesten Komponente" inakzeptabel .



Microservice-orientierte Anwendungen



In einer mikroserviceorientierten Anwendung (MOA) wird jede Funktionskomponente in die kleinstmöglichen Einheiten mit einer ausgeprägten Funktionalität (innerhalb angemessener Grenzen) zerlegt. In diesem Fall ist jede solche Funktionskomponente als Mikrodienst organisiert. Jedes Unternehmen hat sein eigenes Legacy-Code-Gepäck sowie eine Unternehmenskultur, die eingehalten werden sollte, sodass es unmöglich ist, "Like Notes" zu schreiben, wie genau die Zerlegung durchgeführt werden soll.



Wenn es darum geht, eine monolithische Anwendung in MOA zu zerlegen, ist der Schlüssel zu beachten, dass das Beste der Feind des Guten ist. Stellen Sie sicher, dass jeder Mikrodienst gemäß seiner semantischen Definition strukturiert ist, dass der Mikrodienst seine eigenen Daten und seinen eigenen Veröffentlichungszyklus hat. Die Tiefe der Implementierung hängt davon ab, was sich das Unternehmen leisten kann, basierend auf der verfügbaren Zeit, der Mitarbeitererfahrung und den verfügbaren Ressourcen. Einige Mikrodienste haben möglicherweise nur eine Funktion, andere haben möglicherweise viele Funktionen.

Es gibt drei Arten von MOA : synchron , asynchron und hybrid .



Synchrone mikroserviceorientierte Anwendungen



Abbildung 2 zeigt eine synchrone MOA. Die Interservice-Kommunikation ist ein für HTTP-Interaktionen im Web typisches Request-Response- Prinzip .







Abbildung 2: Mikroservice-orientierte Anwendung basierend auf synchroner Interservice-Kommunikation



Jeder Mikrodienst ist hinter dem HTTP-Server segmentiert, der den Zugriff auf die Logik dieses Mikrodienstes ermöglicht. Ein bestimmter Microservice kennt nur seinen eigenen Verantwortungsbereich; Möglicherweise kennt er auch die Schnittstelle für die Interaktion mit einem anderen Mikrodienst, kann jedoch die interne Logik eines anderen Dienstes nicht erkennen. Außerdem kennt der Microservice nur seine eigenen Daten. Die Datenspeicher anderer Microservices sind ihm nicht bekannt und stehen ihm nicht zur Verfügung. Es ist unmöglich, die Daten eines anderen Mikrodienstes zu "entführen", indem direkt auf das Data Warehouse zugegriffen wird. Die einzige Möglichkeit, Daten vom Microservice abzurufen und neue Daten an diesen zu übertragen, besteht darin, über die öffentliche Schnittstelle mit ihm zu interagieren.



Zu den Vorteilen synchroner MOAs gehört ihre Unabhängigkeit. Beispielsweise kann der oben gezeigte Kunden-Mikroservice jederzeit aktualisiert werden. Es gibt keine externen Abhängigkeiten, die daran angepasst werden müssen. Solange der Microservice seine öffentliche Schnittstelle sowie die Struktur der Daten, die er aus der Anforderung verwenden und als Antwort zurückgeben möchte, nicht ändert, ist das Risiko, die gesamte MOA-Architektur zu beschädigen, minimal.



Die MOA-Architektur ist von Natur aus so beschaffen, dass sie ihre eigene strukturelle Integrität beibehält. Da der Mikrodienst selbst seine eigenen Daten enthält, wirkt sich seine Arbeit nicht auf die Datenspeicher anderer Dienste aus. Da ein Microservice als eine Reihe von HTTP-URLs und zugehörigen Datenstrukturen dargestellt wird, die auf einem Request-Response-Prinzip basieren, sind die Grenzen der Schnittstelle des Microservices klar definiert.



Synchrone MOAs werden immer beliebter. Viele synchrone MOA-Schnittstellen basieren auf dem REST-Paradigma, einem Stil, der seit 2000 existiertdes Jahres. Trotz seiner Beliebtheit hat MOA einen Nachteil: niedrige Geschwindigkeit. Verbraucher eines synchronen Mikrodienstes werden niemals schneller ausgeführt, als dieser Mikrodienst Anforderungen und Antworten verarbeiten kann. Dies kann ein großer Engpass sein, insbesondere beim Umgang mit Microservices, deren Ausführung lange dauert. Ein Beispiel ist ein komplexer Analysedienst, der Terabyte an Daten verbraucht und verarbeitet. Nur wenige Kunden werden zustimmen, einige Minuten hintereinander zu warten, bis der Dienst beendet wird. Es wäre bequemer, dem Microservice mitzuteilen, welche Arbeiten ausgeführt werden müssen, und dann benachrichtigt zu werden, wenn die Ergebnisse vorliegen.



In solchen Situationen ist es bequemer, beim Entwurf von Mikrodiensten einen asynchronen Ansatz zu wählen.



Asynchrone mikroserviceorientierte Anwendungen



Abbildung 3 zeigt eine asynchrone MOA-Implementierung, bei der die Service-zu-Service-Kommunikation durch den Austausch von Nachrichten zwischen den beteiligten Parteien bereitgestellt wird. Typischerweise wird diese Interaktion als "Feuer und Vergessen" bezeichnet.







Abbildung 3: Asynchrone MOA-Architektur basiert auf Messaging



In der asynchronen MOA-Architektur können Nachrichten zufällig oder als Reaktion auf ein bestimmtes Ereignis generiert werden. Wenn beispielsweise (wie in der Abbildung oben gezeigt) eine Bestellung im Mikrodienst "Bestellungen" erstellt wird, kann dieser Dienst ein Ereignis veröffentlichen orders_created



und in eine Warteschlange für Begleitnachrichten stellen ., der einen anderen Microservice abhört, abrechnet (in der Abbildung nicht dargestellt) und eingehende Nachrichten akzeptiert. Der Abrechnungsmikroservice nimmt die Bestellinformationsnachricht auf und verarbeitet sie auf eine aus Abrechnungssicht relevante Weise.



Der Vorteil eines asynchronen Ansatzes zum Entwerfen von mikroserviceorientierten Anwendungen besteht darin, dass in einem solchen System keine Engpässe bestehen und es daher äußerst effizient ist. Der Nachteil ist, dass es sehr schwierig ist, ein solches System zu erstellen und dann zu verwalten.

Für asynchrone Großsysteme wie UberEs ist normal, Tausende von Nachrichten pro Sekunde zu verarbeiten. Das Debuggen eines solchen Systems ist schwierig, da seine Workflows keine klaren Trajektorien aufweisen. Es geht nicht darum, zuerst eine Aktion und dann eine andere auszuführen. Die Logik wird abhängig von der empfangenen Nachricht ausgelöst, dh es kann jederzeit alles passieren.



Dies sollte bei der Entwicklung von Teststrategien berücksichtigt werden. Zum Beispiel ist ein asynchrones System unpraktisch, dessen Leistung von den Anforderungs- und Antwortzeiten abhängt, da es niemals eine Eins-zu-Eins-Korrespondenz "eine Anfrage-eine-Antwort" geben wird.



Hybride mikroserviceorientierte Anwendungen



Der ausgewogene Ansatz zur Implementierung einer mikroserviceorientierten Anwendung ist hybride. Dienste sind gleichzeitig synchron, dh die direkte Anfrage-Antwort-Kommunikation wird zwischen ihnen unterstützt und gleichzeitig asynchron. Das heißt, einige der Nachrichten werden in Verbindung mit oder als Ergebnis von synchronem Messaging generiert.



Abbildung 4 zeigt die Kommunikationsmuster, die bei einem Hybridansatz für mikroserviceorientierte Anwendungen verwendet werden. Der Kunden-Mikroservice wird sowohl als URL eines HTTP-Servers als auch als Warteschlange in einem Nachrichtenbroker dargestellt.







Abbildung 4: Ein hybrider Ansatz zum Entwerfen mikroserviceorientierter Anwendungen, bei dem sowohl synchrone als auch asynchrone Kommunikationsoptionen zwischen Diensten und Verbrauchern verwendet werden.

Sie können dem Microservice einen Client mithilfe der Standard-HTTP-Anfrage-Antwort-Kommunikation hinzufügen. Die Anfrage wird empfangen und verarbeitet, dann wird eine Antwort generiert. Bevor jedoch eine Antwort generiert wird, wird eine Nachricht mit Informationen zum neuen Client in der Warteschlange für Begleitnachrichten veröffentlicht, damit andere interessierte Dienste sie verwenden können. Die an die Nachrichtenwarteschlange gesendeten Informationen können nach Ermessen des Mikrodienstes dieselben sein, die in der HTTP-Antwort generiert wurden, oder geringfügig abweichen. Es hängt alles davon ab, wie der Microservice aufgebaut ist und welche QoS-Vereinbarungen der Microservice durchsetzen muss.



GraphQLIst eine API-Technologie, die sowohl die synchrone als auch die asynchrone Kommunikation zwischen einem Verbraucher und einem Dienst unterstützt. Erfahren Sie mehr über diese Technik und GraphQL Abonnements hier .



Das wichtigste Merkmal des Hybridansatzes ist, dass er die Vorzüge der beiden anderen Ansätze kombiniert. Es gibt jedoch auch Nachteile, insbesondere potenzielle Engpässe, die die Leistung verringern, und die zusätzliche Komplexität, die mit der Notwendigkeit verbunden ist, zwei grundlegend unterschiedliche Arten von Schnittstellen zu unterstützen, die vom Mikrodienst "in" und "out" verwendet werden.



Beim Entwerfen von Tests für Mikrodienste treten Schwierigkeiten auf



Wenn Sie solche Anwendungen testen möchten, müssen Sie sich zunächst daran erinnern, dass ein einzelner Mikrodienst nur sehr selten von mehreren MOAs gemeinsam genutzt wird. In der Regel ist ein Mikrodienst einer von vielen in einer bestimmten Domäne innerhalb einer Anwendung. Der Vorteil eines auf Mikroservices ausgerichteten Ansatzes für das Design von Anwendungsarchitekturen ist eine schnellere Codeübertragung zur und von der Produktion. Netflix verfügt beispielsweise über mehr als 4.000 Bereitstellungen pro Tag .) Diese Freigaberate ist in einer herkömmlichen monolithischen Anwendungsumgebung einfach nicht möglich.



Es sollte auch beachtet werden, dass MOA-Tests sowohl auf Mikro- als auch auf Makroebene durchgeführt werden sollten.



Tests auf Mikroebene



Auf Mikroebene muss jeder Dienst in seinem Verantwortungsbereich gründlich getestet werden. Nach einigen Interpretationen wird eine Funktion als Mikrodienstgrenze betrachtet.



Gehen Sie über herkömmliche Unit-Tests hinaus



Angesichts der wachsenden Beliebtheit des serverlosen Paradigmas, nach dem der Mikroservice nur als einzelne Funktion dargestellt werden sollte, ist es ratsam, der Funktion innerhalb des Mikrodienstes besondere Aufmerksamkeit zu widmen . Viele praktizierende Tester beschränken sich jedoch bei der Arbeit mit Microservices auf Unit-Tests. Während ein Komponententest normalerweise eine einzelne Funktion abdeckt, die in einer sehr begrenzten Testumgebung funktioniert, ist ein Microservice so konzipiert, dass er ein Publikum im Internet bedient. Daher müssen die Testbedingungen extrem sein.



Im Rahmen eines guten Tests auf Mikroebene können Sie beispielsweise hunderttausend Instanzen eines Mikrodienstes gleichzeitig ausführen und sehen, wie sie sich auf dieser Skala verhalten. Es reicht nicht aus, jeweils nur eine Funktion zu testen, indem ein einzelner Komponententest darauf angewendet wird. Es ist notwendig, solche Tests für Tausende von Instanzen der Funktion gleichzeitig durchzuführen, wobei die Indikatoren der Hosting-Umgebung zu berücksichtigen sind, in der Sie arbeiten müssen.



Testen Sie Ihre Bereitstellungseinheit



Neben dem Testen der Funktionalität des Mikrodienstes müssen Sie auch die Bereitstellungseinheit testen, in der der Mikrodienst freigegeben ist. In der Regel werden Microservices als Container im Rahmen einer Orchestrierungstechnologie wie Kubernetes oder Docker Swarm bereitgestellt . Ein wichtiger Aspekt der Container-Orchestrierung ist die Sicherstellung der langfristigen Ausfallsicherheit von Microservices.



Es wird angenommen, dass Microservices aus verschiedenen Gründen ausfallen können, sowohl aufgrund eines Hostfehlers als auch aufgrund von Fehlern im Microservice selbst. Es ist ganz normal, dass beim gleichzeitigen Betrieb von Tausenden von Containern eine Art Stromstörung auftritt. Die Wichtigkeit des Testens ist, dass das korrekte Beenden des Microservices aus dem Spiel nicht weniger wichtig ist als seine korrekte Funktion. Tests auf Mikroebene stellen sicher, dass der Mikrodienst in jeder Größenordnung des Systems sauber zum Leben erweckt wird und sauber stirbt.



Stellen Sie sicher, dass absolut alles, was Ihnen passiert, protokolliert wird



Die Tests müssen auch sicherstellen, dass alle im Microservice auftretenden wichtigen Ereignisse ordnungsgemäß protokolliert werden - und ebenso wichtig ist, dass diese Protokolleinträge verstanden werden können. In der Welt der Mikrodienste ist die Protokollierung sehr wichtig, insbesondere für asynchrone MOA, bei denen keine sequentielle Ausführung von Verhaltensweisen erfolgt. Oft helfen Ihnen nur die Protokolldaten dabei, zu verstehen, was in der Anwendung geschieht.



Makrotests



Unabhängig davon, ob die MOA synchron, asynchron oder hybrid ist, wird ein strenger Testmodus angezeigt. Wenn Sie Microservices auf Makroebene testen, müssen Sie sicherstellen, dass zwei Aspekte zufriedenstellend sind: dienstübergreifende Kommunikation und Bereitstellungsprozesse.



Gewährleistung einer intelligenten dienstübergreifenden Kommunikation



Microservices sind per Definition unabhängig voneinander. Sie bestimmen anhand der empfangenen Informationen, was zu tun ist. Daher ist die Genauigkeit der dienstübergreifenden Kommunikation für den ganzheitlichen Betrieb einer mikroserviceorientierten Anwendung von entscheidender Bedeutung.



Um dienstübergreifende Kommunikation bereitzustellen, muss sichergestellt werden, dass die richtigen Informationen dort ankommen, wo sie benötigt werden und wohin sie gehen. Tests sollten in der Lage sein zu verfolgen, wie Nachrichten ausgetauscht und wie sie verarbeitet werden. Dies gilt sowohl für die HTTP-Anfrage-Antwort-Kommunikation als auch für den Austausch von asynchronen Nachrichten, die über einen Nachrichtenbroker weitergegeben werden. Durch Tests sollte sichergestellt werden, dass Nachrichtenformate unterstützt werden, um einen positiven Systempfad sicherzustellen .und falsch formatierte Nachrichten werden abgelehnt und mit ausreichenden Erklärungen (und nicht nur mit einem Fehler "schlechte Nachricht").



Testen der kontinuierlichen Integration und Bereitstellung



Gut organisierte Prozesse für die kontinuierliche Integration und kontinuierliche Bereitstellung (CI / CD) sind in jedem Softwareentwicklungsparadigma von wesentlicher Bedeutung. Bei Microservices-Anwendungen ist jedoch ein effizienter, genauer und schneller CI / CD-Prozess von entscheidender Bedeutung. MOAs können mit einer Rate von Hunderten von Aktualisierungen täglich überarbeitet werden, sodass ein einzelner Mikrodienst, der spät erstellt wird, zu einem Engpass werden und den gesamten Veröffentlichungsprozess verlangsamen kann.



Der beste Weg, auf Nummer sicher zu gehen, besteht darin, dem Testen von CI / CD-Pipelines die gleiche Priorität zu geben wie jedem anderen Testmodus auf hoher Ebene. Das Erkennen und Beheben von Problemen wie langsame Erstellung von Mikrodiensten aufgrund von Artefakten im Code, langsame Bereitstellung von Laufzeiten, in denen Mikrodienste gehostet werden, und langsamer Anstieg bereits bereitgestellter Mikrodienste sind Voraussetzungen für eine gesunde CI / CD-Pipeline. Selbst wenn der Microservice so komplex wie ein Shuttle ist, ist er wenig nützlich, wenn Sie Betriebseinheiten nicht schnell bereitstellen und bereitstellen können.



Fazit



Microservices sind die wahre Wildcard. Microservice-orientierte Anwendungen bieten die Flexibilität und Geschwindigkeit, die erforderlich sind, um neue Funktionen blitzschnell online zu stellen. Große Unternehmen, die Millionen von Benutzern unterstützen, haben dies heute gelernt, aber jeden Tag übernehmen immer mehr Unternehmen diesen Architekturstil, wenn ihre Anwendungen die Größe des gesamten Webs erreichen.



Während viele Unternehmen ernsthaft versuchen, den Geist einer auf Mikroservices ausgerichteten Architektur in ihre Entwicklungsprozesse einzubeziehen, werden diese MOAs häufig anhand von Methoden getestet, die ursprünglich für monolithische Anwendungen vorgesehen waren. Dies ist ein kurzsichtiger Ansatz.

Im Gegenteil, Unternehmen müssen moderne Testtechniken erlernen, um die Unabhängigkeit von Microservices und die Agilität der Anwendungen zu gewährleisten, die diese Microservices verwenden. Wenn es Entwicklungsteams und Testern gelingt, die Prinzipien für das Entwerfen von Microservices-Anwendungen zu synchronisieren, kann sich das gesamte Unternehmen viel stärker auf die Stärken von Microservices verlassen.



All Articles