Einführung von Microservices bei Netflix: Erkenntnisse für das Architekturdesign

NGINX | 19. Februar 2015

In einigen unserer jüngsten Blogbeiträge haben wir erläutert, warum wir es für entscheidend halten, eine vierstufige Anwendungsarchitektur einzuführen, bei der Anwendungen als Gruppen von Microservices entwickelt und bereitgestellt werden. Es wird immer deutlicher, dass Sie einfach nicht schnell genug agieren können, um das Interesse mobiler Nutzer zu wecken und dauerhaft zu halten, wenn Sie weiterhin Entwicklungsprozesse und Anwendungsarchitekturen verwenden, die vor zehn Jahren noch bestens funktioniert haben. Schließlich können diese Nutzer aus einer ständig wachsenden Zahl von Apps wählen.

Der Umstieg auf eine Microservices-Architektur eröffnet Unternehmen spannende Marktchancen. Systemarchitekten und Entwickler erhalten dadurch ein beispielloses Maß an Kontrolle und Geschwindigkeit, wenn sie ihren Kunden innovative neue Weberlebnisse bieten. Doch bei diesem rasanten Tempo kann schnell der Eindruck entstehen, dass kaum Spielraum für Fehler bleibt. In der Praxis können Sie die Entwicklung und Bereitstellung Ihrer Anwendungen nicht einfach unterbrechen, während Sie die dafür erforderlichen Prozesse neu gestalten. Sie wissen, dass Ihr künftiger Erfolg vom Umstieg auf eine Microservices-Architektur abhängt – aber wie gelingt dieser Umstieg konkret?

Glücklicherweise teilen mehrere frühe Anwender von Microservices inzwischen großzügig ihr Fachwissen im Sinne von Open Source – nicht nur in Form von veröffentlichtem Code, sondern auch in Konferenzvorträgen und Blogbeiträgen. Netflix ist dafür ein herausragendes Beispiel. Als Director of Web Engineering und später als Cloud Architect leitete Adrian Cockcroft den Wandel des Unternehmens von einem traditionellen Entwicklungsmodell, bei dem 100 Entwickler eine monolithische Anwendung für den DVD-Verleih erstellten, hin zu einer Microservices-Architektur mit vielen kleinen Teams, die für die durchgängige Entwicklung Hunderter Microservices verantwortlich sind. Diese arbeiten zusammen, um täglich digitale Unterhaltungsangebote an Millionen von Netflix-Kunden zu streamen. Heute ist Cockcroft Technology Fellow bei Battery Ventures, ein prominenter Verfechter von Microservices und Cloud-nativen Architekturen und Mitglied des technischen Beirats von NGINX.

In einer zweiteiligen Blogartikelserie stellen wir die wichtigsten Erkenntnisse aus zwei Vorträgen vor, die Cockcroft im vergangenen Jahr gehalten hat: im Oktober auf der ersten jährlichen NGINX-Konferenz und einige Monate zuvor bei einem Microservices-Meetup im Silicon Valley. (Auch die vollständigen Videoaufzeichnungen sind absolut sehenswert.)

Was ist eine Microservices-Architektur?

Cockcroft definiert eine Microservices-Architektur als eine serviceorientierte Architektur, die aus lose gekoppelten Elementen mit klar abgegrenzten Kontexten besteht.

Lose gekoppelt bedeutet, dass Sie die Dienste unabhängig voneinander aktualisieren können. Die Aktualisierung eines Dienstes erfordert keine Änderungen an anderen Diensten. Wenn Sie eine Reihe kleiner, spezialisierter Dienste haben, diese aber dennoch gemeinsam aktualisieren müssen, handelt es sich nicht um Microservices, da sie nicht lose gekoppelt sind. Eine Art der Kopplung, die beim Umstieg auf eine Microservices-Architektur häufig übersehen wird, ist die Datenbankkopplung. Dabei greifen alle Dienste auf dieselbe Datenbank zu, und die Aktualisierung eines Dienstes erfordert eine Änderung des Schemas. Sie müssen die Datenbank aufteilen und denormalisieren.

Das Konzept der „Bounded Contexts“ stammt aus dem Buch „Domain-Driven Design“ von Eric Evans. Ein Microservice mit korrekt abgegrenztem Kontext ist für die Zwecke der Softwareentwicklung eigenständig. Sie können den Code des Microservices verstehen und aktualisieren, ohne etwas über das Innenleben der anderen Microservices wissen zu müssen, da der Microservice und die anderen Microservices ausschließlich über APIs miteinander interagieren und daher weder Datenstrukturen noch Datenbankschemata oder andere interne Darstellungen von Objekten gemeinsam nutzen.

Wenn Sie Anwendungen für das Internet entwickelt haben, sind Sie mit diesen Konzepten bereits vertraut – wenn auch vielleicht nicht dem Namen nach, so doch aus der Praxis. Die meisten mobilen Apps kommunizieren mit einer ganzen Reihe von Backend-Diensten, damit ihre Nutzer beispielsweise Inhalte auf Facebook teilen, Wegbeschreibungen von Google Maps abrufen und Restaurants auf Foursquare finden können – und das alles innerhalb der App. Wäre Ihre mobile App eng mit diesen Diensten gekoppelt, müssten Sie vor der Veröffentlichung eines Updates mit allen zugehörigen Entwicklungsteams sprechen, um sicherzustellen, dass Ihre Änderungen keine Probleme verursachen.

Bei der Arbeit mit einer Microservices-Architektur betrachten Sie andere interne Entwicklungsteams ähnlich wie solche Internet-Backends: als externe Dienste, mit denen Ihr Microservice über APIs interagiert. Der allgemein anerkannte „Vertrag“ zwischen Microservices besagt, dass ihre APIs stabil und aufwärtskompatibel sind. So wie es inakzeptabel wäre, wenn sich die Google Maps API ohne Vorwarnung und auf eine Weise ändern würde, die bei ihren Nutzern zu Problemen führt, kann sich auch Ihre API weiterentwickeln, muss jedoch mit früheren Versionen kompatibel bleiben.

Best Practices für den Entwurf einer Microservices-Architektur

Cockcroft beschreibt seine Rolle als Cloud-Architekt bei Netflix nicht als Kontrolle der Architektur, sondern als Entdeckung und Formalisierung der Architektur, die im Zuge ihrer Entwicklung durch die Netflix-Ingenieure entstand. Das Netflix-Entwicklungsteam etablierte mehrere Best Practices für den Entwurf und die Implementierung einer Microservices-Architektur.

Erstellen Sie für jeden Microservice einen separaten Datenspeicher

Verwenden Sie nicht denselben Backend-Datenspeicher für mehrere Microservices. Das Team jedes Microservices sollte die Datenbank auswählen können, die am besten für den jeweiligen Service geeignet ist. Darüber hinaus verleitet ein gemeinsamer Datenspeicher die von verschiedenen Teams entwickelten Microservices allzu leicht dazu, Datenbankstrukturen gemeinsam zu nutzen – möglicherweise mit dem Ziel, doppelte Arbeit zu vermeiden. Das führt dazu, dass bei der Aktualisierung einer Datenbankstruktur durch ein Team auch andere Services angepasst werden müssen, die diese Struktur ebenfalls verwenden.

Die Aufteilung der Daten kann die Datenverwaltung komplizierter machen, da die separaten Speichersysteme leichter aus dem Takt geraten oder inkonsistent werden können und sich Fremdschlüssel unerwartet ändern können. Sie müssen ein Tool hinzufügen, das im Hintergrund ein Stammdatenmanagement (MDM) durchführt, um Inkonsistenzen zu finden und zu beheben. Beispielsweise könnte es jede Datenbank untersuchen, in der Abonnenten-IDs gespeichert sind, um zu überprüfen, ob in allen dieselben IDs vorhanden sind (also in keiner Datenbank IDs fehlen oder zusätzliche IDs vorhanden sind). Sie können ein eigenes Tool entwickeln oder eines kaufen. Viele kommerzielle relationale Datenbankmanagementsysteme (RDBMS) führen solche Prüfungen durch, stellen jedoch in der Regel zu hohe Anforderungen an die Kopplung und sind daher nicht skalierbar.

Code auf einem ähnlichen Reifegrad halten

Der gesamte Code in einem Microservice sollte einen ähnlichen Reifegrad und eine ähnliche Stabilität aufweisen. Wenn Sie also Code in einem bereitgestellten, gut funktionierenden Microservice ergänzen oder teilweise neu schreiben müssen, empfiehlt es sich in der Regel, für den neuen oder geänderten Code einen neuen Microservice zu erstellen und den bestehenden Microservice unverändert beizubehalten. [Anmerkung der Redaktion – Dies wird manchmal als das Prinzip der unveränderlichen Infrastruktur bezeichnet.] Auf diese Weise können Sie den neuen Code schrittweise bereitstellen und testen, bis er fehlerfrei und maximal effizient ist, ohne Ausfälle oder Leistungseinbußen beim bestehenden Microservice zu riskieren. Sobald der neue Microservice ebenso stabil ist wie der ursprüngliche, können Sie beide wieder zusammenführen, wenn sie tatsächlich gemeinsam eine einzige Funktion erfüllen oder sich durch ihre Zusammenführung andere Effizienzvorteile ergeben. Cockcrofts Erfahrung nach stellt man jedoch weitaus häufiger fest, dass ein Microservice aufgeteilt werden sollte, weil er zu groß geworden ist.

Erstellen Sie für jeden Microservice einen separaten Build

Erstellen Sie für jeden Microservice einen separaten Build, damit er die benötigten Komponentendateien in den jeweils passenden Revisionsständen aus dem Repository abrufen kann. Dies führt mitunter dazu, dass verschiedene Microservices ähnliche Dateisätze verwenden, jedoch in unterschiedlichen Revisionsständen. Dadurch kann es schwieriger werden, Ihre Codebasis zu bereinigen und alte Dateiversionen außer Betrieb zu nehmen, da Sie sorgfältiger prüfen müssen, ob eine Revision tatsächlich nicht mehr verwendet wird. Dieser Nachteil ist jedoch angesichts der einfachen Möglichkeit, beim Erstellen neuer Microservices neue Dateien hinzuzufügen, vertretbar. Diese Asymmetrie ist beabsichtigt: Das Hinzufügen eines neuen Microservices, einer neuen Datei oder Funktion soll einfach und nicht riskant sein.

In Containern bereitstellen

Die Bereitstellung von Microservices in Containern ist wichtig, da dadurch nur ein einziges Tool benötigt wird, um alles bereitzustellen. Solange sich der Microservice in einem Container befindet, weiß das Tool, wie er bereitgestellt werden muss. Dabei spielt es keine Rolle, um welchen Container es sich handelt. Allerdings scheint sich Docker sehr schnell zum De-facto-Standard für Container entwickelt zu haben.

Server als zustandslos behandeln

Behandeln Sie Server, insbesondere solche, auf denen kundenorientierter Code ausgeführt wird, als austauschbare Mitglieder einer Gruppe. Sie erfüllen alle dieselben Funktionen, sodass Sie sich nicht um jeden einzelnen kümmern müssen. Entscheidend ist lediglich, dass genügend Server vorhanden sind, um die erforderliche Arbeitslast zu bewältigen. Mithilfe der automatischen Skalierung können Sie ihre Anzahl nach Bedarf erhöhen oder verringern. Fällt ein Server aus, wird er automatisch durch einen anderen ersetzt. Vermeiden Sie „Snowflake“-Systeme, bei denen Sie darauf angewiesen sind, dass einzelne Server spezielle Funktionen ausführen.

Cockcrofts Analogie besagt, dass man Server wie Nutztiere und nicht wie Haustiere betrachten sollte. Wenn Sie eine Maschine im Produktivbetrieb haben, die eine spezielle Funktion erfüllt, die Sie beim Namen kennen und deren Ausfall alle traurig macht, dann ist sie ein Haustier. Stattdessen sollten Sie Ihre Server wie eine Kuhherde betrachten. Entscheidend ist, wie viele Liter Milch Sie erhalten. Wenn Sie eines Tages feststellen, dass Sie weniger Milch als üblich bekommen, ermitteln Sie, welche Kühe nicht genug produzieren, und ersetzen sie.

Die Bereitstellungsarchitektur von Netflix basiert auf NGINX

Netflix nutzt NGINX Open Source bereits seit Langem und wurde nach der Gründung von NGINX, Inc. im Jahr 2011 dessen erster Kunde. Tatsächlich wählte Netflix NGINX als Herzstück seiner Bereitstellungsinfrastruktur Open Connect, eines der größten Content Delivery Networks (CDNs) der Welt. Dank der Fähigkeit, Tausende und manchmal sogar Millionen von Anfragen pro Sekunde zu verarbeiten, sind NGINX und NGINX Plus optimale Lösungen für die leistungsstarke HTTP-Bereitstellung und ermöglichen es Unternehmen wie Netflix, Millionen von Kunden täglich hochwertige digitale Erlebnisse zu bieten.

Videoaufzeichnungen

Schnelle Bereitstellung
nginx.conf 2014, Oktober 2014

Migration zu Microservices, Teil 1
Silicon Valley Microservices Meetup, August 2014

Migration zu Microservices, Teil 2
Silicon Valley Microservices Meetup, August 2014


Teilen
Schlagwörter: F5 NGINX, Tech

Ähnliche Blogbeiträge

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
NGINX | 23.08.2022

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln

Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
NGINX | 08.09.2021

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen

Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
NGINX | 16.08.2021

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet

Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
NGINX | 12.12.2018

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77

Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.

Ankündigung von NGINX Plus R16
NGINX | 05.09.2018

Ankündigung von NGINX Plus R16

NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
NGINX | 13.10.2016

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing

Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.