19. September in Moskau das erste thematische Meetup der HUG (Highload++ User Group), das den Mikroservices gewidmet war. Auf diesem wurde der Vortrag "Betrieb von Mikroservices: Die GröĂe spielt eine Rolle, selbst wenn Sie Kubernetes haben" gehalten, in dem wir umfangreiche Erfahrungen der Firma "Flant" im Bereich des Betriebs von Projekten mit mikroservicebasierter Architektur geteilt haben. Insbesondere wird es allen Entwicklern nĂŒtzlich sein, die darĂŒber nachdenken, diesen Ansatz in ihrem aktuellen oder zukĂŒnftigen Projekt anzuwenden.

Wir prÀsentieren (50 Minuten, deutlich informativer als der Artikel), sowie die Hauptinhalte in Textform.
NB: Video und PrĂ€sentation sind auch am Ende dieser Veröffentlichung verfĂŒgbar.
EinfĂŒhrung
Normalerweise hat eine gute Geschichte einen Anfang, einen Hauptplot und ein Ende. Dieser Vortrag Àhnelt eher einem Anfang, und zwar einem tragischen. Es ist auch wichtig zu beachten, dass er einen Blick auf Mikroservices aus der Perspektive von der Ausnutzung.
Ich beginne mit einem solchen Diagramm, dessen Autor (im Jahr 2015) Martin Fowler:

Man sieht, dass in einem monolithischen Anwendungsszenario, das eine bestimmte GröĂe erreicht hat, die ProduktivitĂ€t zu sinken beginnt. Mikroservices unterscheiden sich darin, dass die anfĂ€ngliche ProduktivitĂ€t damit niedriger ist, aber mit zunehmender KomplexitĂ€t weniger auffĂ€llig ist die Effizienzdegradation.
Ich werde dieses Diagramm fĂŒr den Fall der Verwendung von Kubernetes ergĂ€nzen:

Warum ist es einer Anwendung mit Mikroservices besser geworden? Weil eine solche Architektur ernsthafte Anforderungen an die Architektur stellt, die ihrerseits hervorragend durch die Möglichkeiten von Kubernetes erfĂŒllt werden. Auf der anderen Seite wird ein Teil dieser FunktionalitĂ€t auch fĂŒr Monolithen nĂŒtzlich sein, insbesondere aus dem Grund, dass ein typischer Monolith heutzutage kein echter Monolith ist (Details werden spĂ€ter im Vortrag behandelt).
Wie man sieht, unterscheidet sich das endgĂŒltige Diagramm (wenn sowohl monolithische als auch mikroservicebasierte Anwendungen in einer Infrastruktur mit Kubernetes betrieben werden) nicht wesentlich von dem ursprĂŒnglichen. Im Folgenden wird es um Anwendungen gehen, die mit Kubernetes betrieben werden.
NĂŒtzliche und schĂ€dliche Mikroservicestruktur
Und hier ist der Hauptgedanke:

Was ist eigentlich eine normale Mikroservicearchitektur? Sie sollte Ihnen einen echten Nutzen bringen, indem sie die Effizienz Ihrer Arbeit erhöht. Wenn man zum Diagramm zurĂŒckkehrt, dann sieht man das hier:

Wenn man sie nĂŒtzlichnennt, dann wird auf der anderen Seite des Diagramms schĂ€dliche Mikroservicestruktur (behindert die Arbeit):

ZurĂŒck zur âHauptideeâ: Kann man meiner Erfahrung ĂŒberhaupt vertrauen? Seit Beginn dieses Jahres habe ich 85 Projektegesehen. Nicht alle waren mikroservices (diese Architektur hatten ungefĂ€hr ein Drittel bis die HĂ€lfte davon), aber es ist dennoch eine groĂe Zahl. Uns (der Firma âFlantâ) als Outsourcern gelingt es, eine groĂe Vielfalt an Anwendungen zu sehen, die sowohl in kleinen Unternehmen (mit 5 Entwicklern) als auch in groĂen (~500 Entwicklern) entwickelt werden. Ein zusĂ€tzlicher Vorteil ist, dass wir sehen, wie diese Anwendungen ĂŒber viele Jahre leben und sich entwickeln.
Warum Mikroservices?
Auf die Frage nach dem Nutzen von Mikroservices gibt es von dem bereits erwÀhnten Martin Fowler:
- klare Modulgrenzen;
- unabhÀngiges Deployment;
- Freiheit bei der Technologiewahl.
Ich habe viel mit Architekten und Softwareentwicklern gesprochen und gefragt, warum sie Mikroservices benötigen. Und habe meine eigene Liste ihrer Erwartungen zusammengestellt. Das ist das Ergebnis:

Wenn ich einige Punkte âgefĂŒhlsmĂ€Ăigâ beschreiben sollte:
- klare Modulgrenzen: hier haben wir ein schreckliches Monolith, und jetzt wird alles ordentlich in Git-Repositories aufgeteilt, in denen alles âordnungsgemĂ€Ăâ ist, nicht warm mit weich vermischt;
- unabhÀngiges Deployment: wir können Dienste unabhÀngig ausrollen, sodass die Entwicklung schneller voranschreiten kann (parallel neue Funktionen veröffentlichen);
- unabhÀngige Entwicklung: wir können diesen Mikroservice an ein Team/Entwickler abgeben, und die andere an einen anderen, was uns ermöglicht, schneller zu entwickeln;
- bogröĂere ZuverlĂ€ssigkeit: Wenn es zu einer teilweisen Degradation kommt (wenn ein Mikroservice von 20 ausfĂ€llt), wird nur ein Knopf nicht mehr funktionieren, wĂ€hrend das System insgesamt weiterhin funktioniert.
Typische (schÀdliche) Mikroservice-Architektur
Um zu erklÀren, warum in der RealitÀt alles nicht so ist, wie wir es erwarten, werde ich ein sammelnder Bild der Mikroservice-Architektur vorstellen, das auf Erfahrungen aus zahlreichen verschiedenen Projekten basiert.
Als Beispiel dient ein abstrakter Online-Shop, der plant, mit Amazon oder zumindest OZON zu konkurrieren. Seine Mikroservice-Architektur sieht folgendermaĂen aus:

Aus einer Vielzahl von GrĂŒnden sind diese Mikroservices auf unterschiedlichen Plattformen geschrieben worden:

Da jeder Mikroservice Autonomie haben muss, benötigen viele von ihnen eine eigene Datenbank und einen Cache. Die finale Architektur sieht folgendermaĂen aus:

Was sind die Folgen?
Bei Fowler gibt es dazu â ĂŒber die "Preise" fĂŒr die Nutzung von Mikrodiensten:

Wir werden sehen, ob unsere Erwartungen erfĂŒllt wurden.
Klare Grenzen der ModuleâŠ
Aber wie viele Mikrodienste tatsĂ€chlich angepasst werden mĂŒssen, um eine Ănderung auszurollen? Können wir ĂŒberhaupt nachvollziehen, wie alles funktioniert, ohne einen verteilten Tracer (denn jede Anfrage wird von der HĂ€lfte der Mikrodienste verarbeitet)?
Es gibt ein Muster von "", und hier haben wir es sogar mit einem verteilten Klumpen Dreck zu tun. Zur BestĂ€tigung â hier ist eine grobe Illustration, wie Anfragen verlaufen:

UnabhĂ€ngigkeit beim DeploymentâŠ
Technisch ist sie erreicht: wir können jeden Mikrodienst separat ausrollen. In der Praxis ist jedoch zu berĂŒcksichtigen, dass immer viele Mikrodienste, und wir mĂŒssen die Reihenfolge ihres RolloutberĂŒcksichtigen. Im Idealfall sollten wir sogar in einem separaten Workflow testen, ob wir das Release in der richtigen Reihenfolge ausrollen.
Freiheit in der TechnologieauswahlâŠ
Die gibt es. Man sollte jedoch daran denken, dass Freiheit oft an Chaos grenzt. Es ist wichtig, Technologien nicht nur auszuwÀhlen, um damit "zu spielen".
UnabhĂ€ngigkeit in der EntwicklungâŠ
Wie erstellen wir einen Testablauf fĂŒr die gesamte Anwendung (aus so vielen Komponenten)? Und zugleich muss er aktuell gehalten werden. Das fĂŒhrt dazu, dass die tatsĂ€chliche Anzahl der TestablĂ€ufe, die wir prinzipiell aufrechterhalten können, minimal bleibt.
Und alles lokal einzurichten? Es scheint, dass der Entwickler hÀufig unabhÀngig arbeitet, aber "ins Blaue hinein", weil er darauf warten muss, dass ein Testablauf frei wird.
Getrenntes SkalierenâŠ
Ja, aber es ist in Bezug auf die verwendeten DBMS eingeschrÀnkt. In dem gegebenen Architekturbeispiel wird es bei Cassandra keine Probleme geben, aber bei MySQL und PostgreSQL schon.
BogröĂere ZuverlĂ€ssigkeitâŠ
Abgesehen davon, dass die Ausfallzeit eines Mikrodienstes oft das ordnungsgemĂ€Ăe Funktionieren des gesamten Systems stört, gibt es ein neues Problem: jeden Mikrodienst ausfallsicher zu machen, ist sehr schwierig. Denn in Mikrodiensten werden unterschiedliche Technologien verwendet (memcache, Redis usw.), und fĂŒr jeden muss alles durchdacht und implementiert werden, was natĂŒrlich möglich ist, aber enorme Ressourcen erfordert.
Messbarkeit der LastâŠ
Damit ist wirklich alles in Ordnung.
Die "Leichtigkeit" von MicroservicesâŠ
Wir haben nicht nur enorme NetzwerkĂŒberheadkosten (Anfragen an DNS usw. nehmen zu), sondern auch wegen zahlreicher Subanfragen haben wir begonnen, Daten zu replizieren (Caches zu speichern), was zu erheblichem Speicherbedarf gefĂŒhrt hat.
Und so sieht das Ergebnis im Vergleich zu unseren Erwartungen aus:

Das ist aber noch nicht alles!
Denn:
- Wahrscheinlich benötigen wir eine Nachrichtenbus.
- Wie macht man ein konsistentes Backup zu einem bestimmten Zeitpunkt? Die einzige realistische Lösung ist, den Verkehr dafĂŒr abzuschalten. Aber wie macht man das in der Produktion?
- Wenn es um die UnterstĂŒtzung mehrerer Regionen geht, ist es eine sehr aufwendige Aufgabe, die StabilitĂ€t in jeder von ihnen zu organisieren.
- Es entsteht das Problem der zentralisierten Ănderungen. Zum Beispiel, wenn wir die PHP-Version aktualisieren mĂŒssen, mĂŒssen wir einen Commit in jedes Repository machen (von denen es Dutzende gibt).
- Das Wachstum der operativen KomplexitÀt scheint exponentiell zu sein.
Was ist mit all dem zu tun?
Beginnen Sie mit einer monolithischen Anwendung. Die Erfahrung von Fowler zeigt, dass fast alle erfolgreichen Microservice-Anwendungen mit einem Monolithen begonnen haben, der zu groĂ geworden ist, und danach aufgeteilt wurde. Gleichzeitig hatten praktisch alle Systeme, die von Anfang an als Microservices konzipiert wurden, frĂŒher oder spĂ€ter ernsthafte Probleme.
Ein weiterer wertvoller Gedanke â damit ein Projekt mit Mikrodienstarchitektur erfolgreich ist, mĂŒssen Sie sowohl die FachdomĂ€ne als auch die Erstellung von Microservices sehr gut verstehen.Und der beste Weg, die FachdomĂ€ne zu erlernen, ist, ein Monolith zu erstellen.
Aber was ist zu tun, wenn wir uns bereits in einer solchen Situation befinden?
Der erste Schritt zur Lösung eines Problems besteht darin, es zu akzeptieren und zu verstehen, dass es ein Problem ist, und dass wir nicht lÀnger leiden wollen.
Wenn wir bei einem gewachsenen Monolithen (wenn wir nicht mehr in der Lage sind, Ressourcen dafĂŒr hinzuzufĂŒgen) ihn aufteilen, ergibt sich in diesem Fall eine umgekehrte Situation: Wenn ĂŒbermĂ€Ăige Mikroservice-Architektur nicht hilft, sondern hindert â schneiden Sie das ĂberflĂŒssige ab und vergröĂern Sie!
Zum Beispiel fĂŒr das oben beschriebene zusammenfassende BildâŠ
Befreien Sie sich von den fragwĂŒrdigsten Microservices:

Kombinieren Sie alle Microservices, die fĂŒr die Frontend-Generierung verantwortlich sind:

⊠in einen Mikrodienst, der in einer (modernen und akzeptablen, wie Sie selbst finden) Sprache/Framework geschrieben ist:

Er wird ein einziges ORM (eine DBMS) und zunÀchst einige Anwendungen haben:

⊠tatsĂ€chlich kann man viel mehr dorthin ĂŒbertragen und dabei folgendes Ergebnis erzielen:

In Kubernetes starten wir all dies mit separaten Instanzen, was bedeutet, dass wir die Last immer noch messen und sie separat skalieren können.
Zusammenfassend
Betrachten Sie das Bild aus einer breiteren Perspektive. HĂ€ufig entstehen all diese Probleme mit Mikrodiensten, weil jemand seine eigene Aufgabe genommen hat, aber 'Mikrodienste spielen' wollte.
Im Wort 'Mikrodienste' ist der Teil 'mikro' ĂŒberflĂŒssig.Sie sind 'mikro' nur, weil sie kleiner als ein riesiges Monolith sind. Aber man sollte nicht denken, dass sie etwas Kleines sind.
Und um zum abschlieĂenden Gedanken zurĂŒckzukehren, kommen wir zum ursprĂŒnglichen Diagramm:

Die dazugehörige Anmerkung (rechts oben) lÀsst sich darauf reduzieren, dass die FÀhigkeiten des Teams, das Ihr Projekt umsetzt, immer primÀr sind. Sie spielen entscheidend eine Rolle bei Ihrer Entscheidung zwischen Mikrodiensten und Monolith. Wenn dem Team die FÀhigkeiten fehlen, aber es beginnt, Mikrodienste zu erstellen, wird die Geschichte mit Sicherheit fatal sein.
Videos und Folien
Das Video der PrĂ€sentation (~50 Minuten; leider vermittelt es nicht die zahlreichen Emotionen der Teilnehmer, die das Klima des Vortrags maĂgeblich geprĂ€gt haben, aber wie es ist):

PrÀsentation des Berichts:
P.S.
Weitere PrÀsentationen in unserem Blog:
- «» (Dmitri Stolyarov; 28. Mai 2018 auf RootConf);
- «» (Dmitri Stolyarov; 7. November 2017 auf HighLoad++);
- «» (Dmitri Stolyarov; 6. Juni 2017 auf RootConf);
- «» (Dmitrij Stoljarov; 8. November 2016 auf HighLoad++);
- «» (Dmitrij Stoljarov; 31. Mai 2016 auf RootConf).
Vielleicht interessieren Sie sich auch fĂŒr folgende Veröffentlichungen:
- «»;
- «»;
- «».
Quelle: habr.com
