{"id":35906,"date":"2019-10-31T22:07:29","date_gmt":"2019-10-31T19:07:29","guid":{"rendered":"https:\/\/prohoster.info\/blog\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\/"},"modified":"2019-10-31T22:07:29","modified_gmt":"2019-10-31T19:07:29","slug":"perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","title":{"rendered":"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>In diesem Artikel werde ich dar\u00fcber berichten, wie das Projekt, an dem ich arbeite, von einem gro\u00dfen Monolithen in eine Sammlung von Microservices umgewandelt wurde.<\/p>\n<p>Das Projekt hat seine Geschichte vor langer Zeit begonnen, Anfang der 2000er Jahre. Die ersten Versionen wurden in Visual Basic 6 geschrieben. Im Laufe der Zeit wurde klar, dass die Entwicklung in dieser Sprache in Zukunft schwer zu unterst\u00fctzen sein w\u00fcrde, da sich die IDE und die Sprache selbst nur langsam weiterentwickeln. Ende der 2000er Jahre entschied man sich, auf das vielversprechendere C# umzusteigen. Die neue Version wurde parallel zur \u00dcberarbeitung der alten geschrieben, und allm\u00e4hlich war mehr Code in .NET. Das Backend in C# war urspr\u00fcnglich auf eine serviceorientierte Architektur ausgerichtet, w\u00e4hrend in der Entwicklung jedoch gemeinsame Bibliotheken mit Logik verwendet wurden und die Services in einem einzigen Prozess gestartet wurden. Es entstand eine Anwendung, die wir \u201eserviceorientierten Monolith\u201c nannten. <\/p>\n<p>Einer der wenigen Vorteile dieser Kombination war die M\u00f6glichkeit, dass sich die Services \u00fcber eine externe API gegenseitig aufrufen konnten. Es gab deutliche Anzeichen f\u00fcr den \u00dcbergang zu einer besseren serviceorientierten und perspektivisch auch microservice-orientierten Architektur. <\/p>\n<p>Wir begannen etwa 2015 mit unserer Arbeit an der Dekompensation. Wir haben zwar noch nicht den idealen Zustand erreicht \u2013 es gibt Teile des gro\u00dfen Projekts, die man kaum noch als Monolithen bezeichnen kann, aber sie \u00e4hneln auch nicht wirklich Microservices. Dennoch ist der Fortschritt erheblich. <br \/>\nDar\u00fcber werde ich in dem Artikel berichten.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/132bb4ea6b9dbcdd202ee090f2b86289.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Inhalt<\/h3>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#1\"> Architektur und Probleme der bestehenden L\u00f6sung<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#2\">Erwartungen an Microservices<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#3\">Probleme beim \u00dcbergang<\/a><\/noindex><\/li>\n<li> <noindex><a rel=\"nofollow\" href=\"#4\">Wie man vom Monolithen zu Microservices \u00fcbergeht<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#5\">Erste Methode<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#6\">Zweiter Weg<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#7\">Dritte Methode<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#8\">Vierte Methode<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#9\">Arbeiten mit der Datenbank<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#10\">Trennung bestehender Tabellen<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#11\">Trennung mit \u00dcberarbeitung<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#12\">Arbeiten mit Quellcode<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#13\">Infrastrukturprobleme<\/a><\/noindex>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"#16\">Manuelle Installation in Umgebungen<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#14\">Getrennte Protokollierung<\/a><\/noindex><\/li>\n<li><noindex><a rel=\"nofollow\" href=\"#15\">Testen und Debuggen von miteinander verbundenen Services<\/a><\/noindex><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><noindex><a rel=\"nofollow\" name=\"1\"><\/a><\/noindex><b><\/p>\n<h3>Architektur und Probleme der bestehenden L\u00f6sung<\/h3>\n<p><\/b><br \/>\nUrspr\u00fcnglich sah die Architektur wie folgt aus: UI \u2013 eine separate Anwendung, der monolithische Teil wurde in Visual Basic 6 geschrieben, die Anwendung in .NET stellte eine Sammlung von verbundenen Services dar, die mit einer recht gro\u00dfen Datenbank arbeiteten.<\/p>\n<p><b>Nachteile der fr\u00fcheren L\u00f6sung<\/b><\/p>\n<p><u>Einzelner Ausfallpunkt<\/u><br \/>\nWir hatten einen einzigen Single Point of Failure: Die .NET-Anwendung lief in einem einzigen Prozess. Wenn einer der Module ausfiel, fiel die gesamte Anwendung aus und musste neu gestartet werden. Da wir eine gro\u00dfe Anzahl von Prozessen f\u00fcr verschiedene Benutzer automatisieren, konnten aufgrund eines Ausfalls in einem dieser Prozesse eine Zeit lang alle nicht arbeiten. Und bei einem Programmfehler half auch die Redundanz nicht. <\/p>\n<p><u>Warteschlange f\u00fcr Anpassungen<\/u><br \/>\nDieser Nachteil ist eher organisatorischer Natur. In unserer Anwendung gibt es viele Kunden, und alle m\u00f6chten die Anpassungen so schnell wie m\u00f6glich. Fr\u00fcher war es unm\u00f6glich, dies parallel zu tun, und alle Kunden mussten sich in eine Warteschlange einordnen. Dieser Prozess f\u00fchrte zu negativen R\u00fcckmeldungen aus der Wirtschaft, denn sie mussten nachweisen, dass ihre Aufgabe von Bedeutung war. Das Entwicklungsteam verbrachte Zeit damit, diese Warteschlange zu organisieren. Das kostete viel Zeit und Energie, und letztlich konnte sich das Produkt nicht so schnell \u00e4ndern, wie es gew\u00fcnscht war.<\/p>\n<p><u>Suboptimale Ressourcennutzung<\/u><br \/>\nBei der Bereitstellung von Services in einem einzigen Prozess kopierten wir immer die Konfiguration vollst\u00e4ndig von Server zu Server. Wir wollten die am st\u00e4rksten belasteten Services separat betreiben, um Ressourcen nicht unn\u00f6tig zu verschwenden und eine flexiblere Verwaltung unseres Bereitstellungsschemas zu erhalten.<\/p>\n<p><u>Schwierigkeiten bei der Einf\u00fchrung moderner Technologien<\/u><br \/>\nEin Problem, das allen Entwicklern bekannt ist: Der Wunsch, moderne Technologien in das Projekt zu integrieren, ist da, aber die M\u00f6glichkeit fehlt. Bei einer gro\u00dfen monolithischen L\u00f6sung wird jedes Update der aktuellen Bibliothek, ganz zu schweigen vom Wechsel zu einer neuen, zu einer recht komplexen Aufgabe. Man muss dem Teamleiter lange nachweisen, dass dies mehr Vorteile bringen wird als Nerven kosten. <\/p>\n<p><u>Komplexit\u00e4t der \u00c4nderungsbereitstellung<\/u><br \/>\nDas war das gr\u00f6\u00dfte Problem \u2013 wir hatten alle zwei Monate Releases. <br \/>\nJedes Release wurde trotz Tests und der Bem\u00fchungen der Entwickler zu einer echten Katastrophe f\u00fcr die Bank. Das Gesch\u00e4ft verstand, dass zu Beginn der Woche ein Teil der Funktionalit\u00e4t nicht funktionieren w\u00fcrde. Und die Entwickler wussten, dass sie eine Woche voller ernsthafter Vorf\u00e4lle bevorstand. <br \/>\nDer Wunsch, die Situation zu \u00e4ndern, war bei allen vorhanden. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"2\"><\/a><\/noindex><b><\/p>\n<h3>Erwartungen an Microservices<\/h3>\n<p><\/b><br \/>\n<u>Bereitstellung der Komponenten nach Fertigstellung. <\/u>Bereitstellung der Komponenten nach ihrer Fertigstellung dank der Dekomposition der L\u00f6sung und der Separation verschiedener Prozesse.<\/p>\n<p><u>Kleine Produktteams.<\/u> Das ist wichtig, weil es schwierig war, ein gro\u00dfes Team, das an einem alten Monolithen arbeitete, zu managen. Ein solches Team musste einem strengen Prozess folgen, w\u00e4hrend mehr Kreativit\u00e4t und Unabh\u00e4ngigkeit gew\u00fcnscht war. Das konnten sich nur kleine Teams leisten.<\/p>\n<p><u>Isolation von Diensten in separaten Prozessen.<\/u> Idealerweise wollten wir die Dienste in Containern isolieren, aber viele Dienste, die auf dem .NET Framework geschrieben sind, laufen nur unter Windows. Es kommen zwar immer mehr Dienste auf .NET Core, aber davon gibt es bisher nur wenige.<\/p>\n<p><u>Flexibilit\u00e4t beim Deployment.<\/u> Wir m\u00f6chten die Dienste so kombinieren, wie es f\u00fcr uns notwendig ist, und nicht so, wie es der Code vorschreibt.<\/p>\n<p><u>Einsatz neuer Technologien.<\/u> Das ist f\u00fcr jeden Programmierer interessant.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"3\"><\/a><\/noindex><b><\/p>\n<h3>Probleme beim \u00dcbergang<\/h3>\n<p><\/b><br \/>\nNat\u00fcrlich, wenn es einfach w\u00e4re, einen Monolithen in Mikrodienste zu zerlegen, m\u00fcsste man nicht auf Konferenzen dar\u00fcber sprechen und Artikel schreiben. In diesem Prozess gibt es viele Fallstricke, ich werde die wichtigsten beschreiben, die uns behindert haben.<\/p>\n<p><b>Das erste Problem<\/b> typisch f\u00fcr die meisten Monolithen: enge Kopplung der Gesch\u00e4ftslogik. Wenn wir einen Monolithen schreiben, m\u00f6chten wir unsere Klassen wiederverwenden, um unn\u00f6tigen Code zu vermeiden. Bei der Migration zu Mikrodiensten wird dies jedoch problematisch: Der gesamte Code ist ziemlich fest miteinander verbunden und es ist schwierig, die Dienste zu trennen.<\/p>\n<p>Zum Zeitpunkt des Projektbeginns gab es im Repository mehr als 500 Projekte und \u00fcber 700.000 Zeilen Code. Das ist eine ziemlich gro\u00dfe L\u00f6sung und <b>das zweite Problem<\/b>. Es war einfach nicht m\u00f6glich, ihn in Mikrodienste zu zerlegen.<\/p>\n<p><b>Das dritte Problem<\/b> \u2014 fehlende notwendige Infrastruktur. Tats\u00e4chlich haben wir manuell den Quellcode auf die Server kopiert.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"4\"><\/a><\/noindex><b><\/p>\n<h3>Wie man vom Monolithen zu Microservices \u00fcbergeht<\/h3>\n<p><\/b><br \/>\n<u>Abgrenzung von Mikrodiensten.<\/u><\/p>\n<p>Zun\u00e4chst haben wir f\u00fcr uns selbst klargestellt, dass die Abgrenzung der Mikrodienste ein iterativer Prozess ist. Wir wurden immer gefordert, gleichzeitig die Entwicklung der Gesch\u00e4ftsanforderungen voranzutreiben. Wie wir das technisch umsetzen, ist unser Problem. Daher haben wir uns auf einen iterativen Prozess vorbereitet. Andernfalls wird es nicht funktionieren, wenn Sie eine gro\u00dfe Anwendung haben, die von Anfang an nicht darauf vorbereitet ist, dass sie umgeschrieben wird.<\/p>\n<p>Welche Methoden verwenden wir zur Abgrenzung von Mikrodiensten?<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"5\"><\/a><\/noindex><b>Erste Methode <\/b>\u2014 bestehende Module als Dienste auslagern. In diesem Zusammenhang hatten wir Gl\u00fcck: Es gab bereits eingerichtete Dienste, die das WCF-Protokoll verwendeten. Diese waren in separate Assemblys aufgeteilt. Wir haben sie einzeln \u00fcbertragen und jeder Assembly ein kleines Startmodul hinzugef\u00fcgt. Dieses wurde mit der gro\u00dfartigen Topshelf-Bibliothek geschrieben, die es erm\u00f6glicht, die Anwendung sowohl als Dienst als auch als Konsole auszuf\u00fchren. Das ist bequem f\u00fcr das Debugging, da keine zus\u00e4tzlichen Projekte in der L\u00f6sung erforderlich sind.<\/p>\n<p>Die Dienste waren durch die Business-Logik miteinander verbunden, da sie gemeinsame Assemblys verwendeten und mit einer gemeinsamen Datenbank arbeiteten. Sie waren schwer als reine Mikrodienste zu bezeichnen. Dennoch konnten wir diese Dienste separat in verschiedenen Prozessen ausf\u00fchren. Bereits das erm\u00f6glichte es, ihre gegenseitigen Auswirkungen zu verringern, wodurch die Probleme mit paralleler Entwicklung und einem einzelnen Ausfallpunkt verringert wurden.<\/p>\n<p>Die Assembly mit dem Host ist nur eine Codezeile in der Program-Klasse. Die Arbeit mit Topshelf haben wir in einer Hilfsklasse verborgen.<\/p>\n<pre><code class=\"plaintext\">namespace RBA.Services.Accounts.Host\n{\n   internal class Program\n   {\n      private static void Main(string[] args)\n      {\n        HostRunner.Run(\"RBA.Services.Accounts.Host\");\n\n       }\n    }\n}\n<\/code><\/pre>\n<p>\n<noindex><a rel=\"nofollow\" name=\"6\"><\/a><\/noindex><b>Der zweite Weg zur Auslagerung von Mikrodiensten:<\/b> sie zur L\u00f6sung neuer Aufgaben zu erstellen. Wenn dabei das Monolith nicht w\u00e4chst, ist das bereits hervorragend, das bedeutet, dass wir in die richtige Richtung gehen. Zur L\u00f6sung neuer Aufgaben haben wir versucht, separate Dienste zu erstellen. Wenn es die M\u00f6glichkeit gab, dann haben wir \u201ekanonischere\u201c Dienste geschaffen, die vollst\u00e4ndig ihre Datenmodell verwalten und eine separate Datenbank haben. <\/p>\n<p>Wie viele andere haben wir mit Authentifizierungs- und Autorisierungsdiensten begonnen. Diese eignen sich perfekt daf\u00fcr. Sie sind unabh\u00e4ngig, in der Regel haben sie ein isoliertes Datenmodell. Sie interagieren nicht direkt mit dem Monolithen, sondern dieser wendet sich lediglich an sie, um bestimmte Aufgaben zu l\u00f6sen. Mit diesen Diensten kann der \u00dcbergang zu einer neuen Architektur begonnen werden, die Infrastruktur kann darauf getestet und bestimmte Ans\u00e4tze in Bezug auf Netzwerklibraries ausprobiert werden usw. Unserer Organisation gibt es keine Teams, die es nicht geschafft h\u00e4tten, einen Authentifizierungsdienst zu erstellen. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"7\"><\/a><\/noindex><b>Der dritte Weg zur Auslagerung von Mikrodiensten<\/b>, die wir verwenden, ist f\u00fcr uns etwas speziell. Es handelt sich um die Auslagerung der Gesch\u00e4ftslogik aus der UI-Schicht. Unsere Hauptanwendung f\u00fcr die Benutzeroberfl\u00e4che ist eine Desktop-Anwendung, die ebenso wie das Backend in C# geschrieben ist. Die Entwickler haben gelegentlich Fehler gemacht und Teile der Logik in die Benutzeroberfl\u00e4che ausgelagert, die eigentlich im Backend existieren und dort wiederverwendet werden sollten. <\/p>\n<p>Wenn man sich ein echtes Beispiel aus dem\u30b3\u30fc\u30c9 der UI-Teile ansieht, wird deutlich, dass ein gro\u00dfer Teil dieser L\u00f6sung echte Gesch\u00e4ftslogik enth\u00e4lt, die in anderen Prozessen n\u00fctzlich ist, nicht nur zur Erstellung von UI-Formularen. <\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/74c7b90ff94b343816ab3ac2fa0673c6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEchte Logik im UI gibt es nur in den letzten beiden Zeilen. Wir haben sie auf den Server \u00fcbertragen, um sie wiederverwendbar zu machen, wodurch wir die Benutzeroberfl\u00e4che verringern und eine korrekte Architektur erreichen.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"8\"><\/a><\/noindex><b>Der vierte und wichtigste Weg zur Identifikation von Mikrodiensten<\/b>, der es erm\u00f6glicht, das Monolith zu reduzieren, besteht in der Auslagerung bestehender Dienste mit \u00dcberarbeitung. Wenn wir bestehende Module unver\u00e4ndert auslagern, sind die Ergebnisse nicht immer zur Zufriedenheit der Entwickler, und der Gesch\u00e4ftsprozess kann seit der Erstellung der Funktionalit\u00e4t veraltet sein. Durch Refactoring k\u00f6nnen wir den neuen Gesch\u00e4ftsprozess unterst\u00fctzen, denn die Anforderungen des Unternehmens \u00e4ndern sich st\u00e4ndig. Wir k\u00f6nnen den Quellcode verbessern, bekannte Fehler beheben und ein qualitativ hochwertigeres Datenmodell erstellen. Es ergeben sich viele Vorteile.<\/p>\n<p>Die Trennung von Diensten mit \u00dcberarbeitung ist untrennbar mit dem Konzept des begrenzten Kontexts verbunden. Dieses Konzept stammt aus der objektorientierten Softwareentwicklung. Es bedeutet einen Abschnitt des Dom\u00e4nenmodells, in dem alle Begriffe einer gemeinsamen Sprache eindeutig definiert sind. Nehmen wir das Beispiel des Kontexts von Versicherungen und Rechnungen. Wir haben eine monolithische Anwendung und m\u00fcssen in den Versicherungen mit der Rechnung arbeiten. Wir erwarten, dass der Entwickler in einem anderen Build die vorhandene Klasse \u201eRechnung\u201c findet, von der Klasse \u201eVersicherung\u201c darauf verweist und wir funktionierenden Code erhalten. Das DRY-Prinzip wird eingehalten, die Aufgabe wird durch die Nutzung des vorhandenen Codes schneller erledigt.<\/p>\n<p>Es stellt sich heraus, dass die Kontexte von Rechnungen und Versicherungen miteinander verbunden sind. Wenn neue Anforderungen hinzukommen, wird diese Verbindung die Entwicklung erschweren und die ohnehin komplexe Gesch\u00e4ftslogik weiter verkomplizieren. Um dieses Problem zu l\u00f6sen, m\u00fcssen wir im Code die Grenzen zwischen den Kontexten finden und ihre \u00dcberschreitungen beseitigen. Zum Beispiel wird es f\u00fcr den Versicherungsbereich m\u00f6glicherweise ausreichen, eine 20-stellige Kontonummer der Zentralbank und das Er\u00f6ffnungsdatum des Kontos zu verwenden. <\/p>\n<p>Um diese begrenzten Kontexte voneinander zu trennen und den Prozess der Abtrennung von Mikrodiensten aus einer monolithischen L\u00f6sung zu starten, haben wir einen Ansatz verwendet, bei dem wir innerhalb der Anwendung externe APIs erstellen. Wenn wir wussten, dass ein Modul ein Mikrodienst werden sollte oder sich im Rahmen des Prozesses \u00e4ndern muss, haben wir sofort Logikaufrufe, die einem anderen begrenzten Kontext geh\u00f6ren, \u00fcber externe Aufrufe gemacht, beispielsweise \u00fcber REST oder WCF.<\/p>\n<p>Wir haben uns entschieden, den Code, der verteilte Transaktionen erfordert, nicht zu vermeiden. In unserem Fall stellte sich heraus, dass es einfach war, dieses Prinzip einzuhalten. Bislang sind keine Situationen aufgetreten, in denen wirklich strikte verteilte Transaktionen erforderlich waren \u2013 es reicht aus, eine finale Konsistenz zwischen den Modulen zu gew\u00e4hrleisten.<\/p>\n<p>Betrachten wir ein konkretes Beispiel. Wir haben das Konzept eines Orchestrators \u2013 eines Pipelines, die die Entit\u00e4t \u201eAntrag\u201c verarbeitet. Er erstellt nacheinander den Kunden, das Konto und die Bankkarte. Wenn der Kunde und das Konto erfolgreich erstellt werden, aber die Erstellung der Karte fehlschl\u00e4gt, wechselt der Antrag nicht in den Status \u201eerfolgreich\u201c und bleibt im Status \u201eKarte nicht erstellt\u201c. In Zukunft wird eine Hintergrundaktivit\u00e4t ihn aufgreifen und abschlie\u00dfen. Das System befindet sich einen Moment lang in einem Inkonsistenzzustand, was uns jedoch im Gro\u00dfen und Ganzen nicht st\u00f6rt.<\/p>\n<p>Falls jedoch eine Situation eintreten sollte, in der ein konsistentes Speichern eines Teils der Daten erforderlich ist, werden wir wahrscheinlich den Service zusammenfassen, um dies in einem Prozess zu behandeln. <\/p>\n<p>Betrachten wir das Beispiel der Abtrennung eines Mikrodienstes. Wie kann man ihn relativ sicher in die Produktion bringen? In diesem Beispiel haben wir einen separaten Teil des Systems \u2013 ein Modul zur Gehaltsabrechnung, einen Teil des Codes, den wir zu einem Mikrodienst machen m\u00f6chten.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/346af271b0c3f99897d330e56f713f18.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZun\u00e4chst erstellen wir einen Mikrodienst, indem wir den Code umschreiben. Wir verbessern einige Aspekte, die uns nicht gefallen haben. Wir implementieren neue Gesch\u00e4ftsanforderungen des Kunden. Wir f\u00fcgen einen API-Gateway in die Verbindung zwischen UI und Backend hinzu, der die Durchleitung von Aufrufen gew\u00e4hrleistet. <\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/bec8d68f20f3ec53af0cef225a51c2b3.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAnschlie\u00dfend setzen wir diese Konfiguration in Betrieb, aber im Pilotstatus. Die meisten unserer Benutzer arbeiten weiterhin mit den alten Gesch\u00e4ftsprozessen. F\u00fcr neue Benutzer entwickeln wir eine neue Version der monolithischen Anwendung, die diesen Prozess nicht mehr enth\u00e4lt. Im Grunde funktioniert unsere Verbindung aus Monolith und Mikrodienst im Pilotbetrieb.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/27e98812746bb7f142fa3a3c3a03b52f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nBei einem erfolgreichen Pilotversuch stellen wir fest, dass die neue Konfiguration tats\u00e4chlich funktionsf\u00e4hig ist. Wir k\u00f6nnen den alten Monolithen aus der Gleichung entfernen und die neue Konfiguration anstelle der alten L\u00f6sung belassen.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/11dcf1d771b57d3921c0aa91b82646e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZusammenfassend verwenden wir nahezu alle bestehenden Methoden zur Trennung des Quellcodes des Monolithen. All diese Methoden erm\u00f6glichen es uns, die Gr\u00f6\u00dfe der Teile der Anwendung zu verringern und sie auf neue Bibliotheken zu migrieren, wodurch der Quellcode qualitativ hochwertiger wird.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"9\"><\/a><\/noindex><b><\/p>\n<h3>Arbeiten mit der Datenbank<\/h3>\n<p><\/b><br \/>\nDie Datenbank l\u00e4sst sich schlechter trennen als der Quellcode, da sie nicht nur das aktuelle Schema, sondern auch angeh\u00e4ufte historische Daten enth\u00e4lt.<\/p>\n<p>Unsere Datenbank hatte, wie viele andere auch, einen weiteren wichtigen Nachteil \u2013 die enorme Gr\u00f6\u00dfe. Diese Datenbank wurde gem\u00e4\u00df einer komplizierten Gesch\u00e4ftslogik des Monolithen entworfen, und zwischen den Tabellen verschiedener begrenzter Kontexte haben sich Verbindungen angesammelt.<\/p>\n<p>In unserem Fall kam zus\u00e4tzlich zu all den Schwierigkeiten (gro\u00dfe Datenbank, zahlreiche Verbindungen, manchmal unklare Grenzen zwischen den Tabellen) das Problem auf, das in vielen gro\u00dfen Projekten auftritt: die Verwendung des Shared-Database-Musters. Daten wurden aus Tabellen \u00fcber Views abgerufen, repliziert und in andere Systeme \u00fcbertragen, wo diese Replikation ben\u00f6tigt wurde. Dadurch konnten wir Tabellen nicht in ein separates Schema auslagern, da sie aktiv genutzt wurden.<\/p>\n<p>Bei der Trennung hilft uns genau das Aufteilen in begrenzte Kontexte im Code. Dies gibt in der Regel ein ausreichend gutes Verst\u00e4ndnis daf\u00fcr, wie wir Daten auf der Ebene der Datenbank aufteilen. Wir verstehen, welche Tabellen zu einem begrenzten Kontext geh\u00f6ren und welche zu einem anderen.<\/p>\n<p>Wir haben zwei globale Methoden zur Trennung der Datenbank angewendet: die Trennung bestehender Tabellen und die Trennung mit \u00dcberarbeitung.<\/p>\n<p>Die Trennung bestehender Tabellen ist eine Methode, die gut angewendet werden kann, wenn die Datenstruktur von hoher Qualit\u00e4t ist und den Gesch\u00e4ftsanforderungen entspricht. In diesem Fall k\u00f6nnen wir bestehende Tabellen in ein separates Schema auslagern.<\/p>\n<p>Die Trennung mit \u00dcberarbeitung ist n\u00f6tig, wenn sich das Gesch\u00e4ftsmodell stark ge\u00e4ndert hat und die Tabellen uns nicht mehr zufriedenstellen.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"10\"><\/a><\/noindex><b>Die Trennung bestehender Tabellen.<\/b> Wir m\u00fcssen festlegen, was wir trennen wollen. Ohne dieses Wissen wird es nicht funktionieren, und hier hilft uns die Trennung begrenzter Kontexte im Code. In der Regel wird es klar, welche Tabellen in die Trennungsliste aufgenommen werden sollten, wenn man die Grenzen der Kontexte im Quellcode verstehen kann.<\/p>\n<p>Stellen wir uns vor, wir haben eine L\u00f6sung, in der zwei Module des Monolithen mit einer gemeinsamen Datenbank interagieren. Wir m\u00fcssen sicherstellen, dass nur ein Modul mit dem Bereich der abtrennbaren Tabellen interagiert, w\u00e4hrend das andere \u00fcber die API mit ihm kommuniziert. Zu Beginn reicht es, wenn \u00fcber die API nur Schreibzugriff erfolgt. Dies ist eine notwendige Bedingung, um \u00fcber die Unabh\u00e4ngigkeit der Mikrodienste sprechen zu k\u00f6nnen. Leseverbindungen k\u00f6nnen bestehen bleiben, solange dies kein gro\u00dfes Problem darstellt.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/1602637ad752ac055f475cfa45d95e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIm n\u00e4chsten Schritt k\u00f6nnen wir den Codeabschnitt, der mit den abzutrennenden Tabellen arbeitet, mit oder ohne \u00dcberarbeitung in einen separaten Mikrodienst auslagern und in einem separaten Prozess oder Container ausf\u00fchren. Dies wird ein separater Dienst mit einer Verbindung zur Datenbank des Monolithen und zu den Tabellen sein, die nicht direkt zu ihm geh\u00f6ren. Der Monolith interagiert noch lesend mit dem abgetrennten Teil. <\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/36011f4e6be4f6a2f19f2f074b645dcb.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSp\u00e4ter werden wir diese Verbindung entfernen, das hei\u00dft, auch der Lesezugriff der monolithischen Anwendung auf die abgetrennten Tabellen wird auf die API umgestellt.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/290f91bbfccac2a4b384078e4cf4e337.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAls N\u00e4chstes trennen wir aus der gemeinsamen Datenbank die Tabellen, mit denen nur der neue Mikrodienst arbeitet. Wir k\u00f6nnen die Tabellen in ein separates Schema oder sogar in eine separate physische Datenbank auslagern. Es bleibt eine Leseverbindung zwischen dem Mikrodienst und der Datenbank des Monolithen bestehen, aber das ist nicht schlimm, in dieser Konfiguration kann er lange Zeit so leben.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/ab947ac6a38ffbccd4e2b51103aef609.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer letzte Schritt besteht darin, alle Verbindungen vollst\u00e4ndig zu entfernen. In diesem Fall ben\u00f6tigen wir m\u00f6glicherweise eine Datenmigration von der Hauptdatenbank. Manchmal wollen wir Daten oder Verzeichnisse, die aus externen Systemen repliziert werden, in mehreren Datenbanken wiederverwenden. Das begegnet uns gelegentlich.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/f40cf17dd56b9575751e370c44f08344.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<noindex><a rel=\"nofollow\" name=\"11\"><\/a><\/noindex><b>Abteilung f\u00fcr Aufbereitung.<\/b> Diese Methode \u00e4hnelt der ersten, geht jedoch umgekehrt. Wir erstellen sofort eine neue Datenbank und einen neuen Mikroservice, der \u00fcber die API mit dem Monolithen interagiert. Dabei bleibt jedoch eine Reihe von Datenbanktabellen bestehen, die wir in Zukunft entfernen m\u00f6chten. Diese sind f\u00fcr uns nicht mehr erforderlich, in dem neuen Modell haben wir sie ersetzt.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/c94932033e47cfa1fd56595ab9a19246.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDamit dieses Schema funktioniert, ben\u00f6tigen wir h\u00f6chstwahrscheinlich eine \u00dcbergangsphase.<\/p>\n<p>Danach gibt es zwei m\u00f6gliche Ans\u00e4tze.<\/p>\n<p><b>Erster<\/b>: Wir duplizieren alle Daten in den neuen und alten Datenbanken. In diesem Fall entsteht Daten\u00fcberfluss, es k\u00f6nnen Synchronisationsprobleme auftreten. Aber wir k\u00f6nnen zwei verschiedene Kunden bedienen. Einer verwendet die neue Version, der andere die alte.<\/p>\n<p><b>Zweiter<\/b>: Wir teilen die Daten nach einem bestimmten Gesch\u00e4ftskriterium auf. Zum Beispiel hatten wir in unserem System 5 Produkte, die in der alten Datenbank gespeichert sind. Das sechste Produkt f\u00fcgen wir im Rahmen eines neuen Gesch\u00e4ftsprojekts in die neue Datenbank ein. Aber wir ben\u00f6tigen ein API Gateway, das diese Daten synchronisiert und dem Kunden zeigt, wo er was entnehmen kann.<\/p>\n<p>Beide Ans\u00e4tze sind praktikabel, w\u00e4hlen Sie je nach Situation.<\/p>\n<p>Nachdem wir sicher sind, dass alles funktioniert, kann der Teil des Monolithen, der mit alten Datenbankstrukturen arbeitet, abgeschaltet werden. <\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/973bf5015bdf49a290a5b901f89628cc.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDer letzte Schritt wird das Entfernen der alten Datenstrukturen sein. <\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/fe83acc07077b7eb3717138e3c20c005.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nZusammenfassend l\u00e4sst sich sagen, dass wir Probleme mit der Datenbank haben: Es ist schwieriger, damit zu arbeiten als mit dem Quellcode, es ist komplizierter zu trennen, aber es ist m\u00f6glich und notwendig. Wir haben einige M\u00f6glichkeiten gefunden, die es erm\u00f6glichen, dies ausreichend sicher zu tun; mit Daten einen Fehler zu machen, ist schlie\u00dflich einfacher als mit Quellcode. <\/p>\n<p><noindex><a rel=\"nofollow\" name=\"12\"><\/a><\/noindex><b><\/p>\n<h3>Arbeiten mit Quellcode<\/h3>\n<p><\/b><br \/>\nSo sah das Schema des Quellcodes aus, als wir begannen, das monolithische Projekt zu analysieren.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/a6d886e37117ccf8f63106d6616aa653.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSie l\u00e4sst sich grob in drei Schichten unterteilen. Dies ist die Schicht der ausf\u00fchrbaren Module, Plugins, Dienste und einzelner Aktivit\u00e4ten. Tats\u00e4chlich waren dies die Einstiegspunkte innerhalb einer monolithischen L\u00f6sung. Alle waren fest mit der Schicht Common verbunden. Darin befand sich die Gesch\u00e4ftslogik, die von den Diensten gemeinsam genutzt wurde, sowie zahlreiche Verbindungen. Jeder Dienst und jedes Plugin verwendete je nach Gr\u00f6\u00dfe und Gewissen der Entwickler 10 oder mehr Common-Bibliotheken.<\/p>\n<p>Wir hatten Gl\u00fcck, denn wir hatten infrastrukturelle Bibliotheken, die separat verwendet werden konnten. <\/p>\n<p>Manchmal kam es vor, dass einige Common-Objekte tats\u00e4chlich nicht zu dieser Schicht geh\u00f6rten, sondern infrastrukturelle Bibliotheken waren. Dies wurde durch Umbenennung gel\u00f6st.<\/p>\n<p>Am meisten sorgten die begrenzten Kontexte f\u00fcr Besorgnis. Es kam vor, dass 3-4 Kontexte in einer einzigen Common-Bibliothek gemischt wurden und sich innerhalb derselben Gesch\u00e4ftsfunktionen gegenseitig verwendeten. Es war notwendig zu verstehen, wo dies getrennt werden konnte und nach welchen Grenzen, sowie was als N\u00e4chstes mit der Zuordnung dieser Trennung zu den Quellcode-Bibliotheken zu tun war.<\/p>\n<p>Wir haben einige Regeln f\u00fcr den Code-Trennungsprozess formuliert.<\/p>\n<p><b>Erstens<\/b>: Wir wollten nicht l\u00e4nger die Gesch\u00e4ftslogik zwischen Diensten, Aktivit\u00e4ten und Plugins teilen. Wir wollten die Gesch\u00e4ftslogik innerhalb der Mikrodienste unabh\u00e4ngig gestalten. Andernfalls werden Mikrodienste idealerweise als Dienste wahrgenommen, die vollkommen unabh\u00e4ngig existieren. Ich halte diesen Ansatz f\u00fcr etwas verschwenderisch und es ist auch schwierig, ihn zu erreichen, da beispielsweise Dienste in C# in jedem Fall mit der Standardbibliothek verbunden sein werden. Unser System ist in C# geschrieben, andere Technologien mussten bisher nicht verwendet werden. Daher haben wir beschlossen, dass wir es uns leisten k\u00f6nnen, gemeinsame technische Bibliotheken zu verwenden. Das Wichtigste ist, dass keine Fragmente der Gesch\u00e4ftslogik enthalten sind. Wenn Sie eine praktische Wrapper \u00fcber ORM haben, die Sie verwenden, ist es sehr kostspielig, diese von Dienst zu Dienst zu kopieren.<\/p>\n<p>Unser Team ist ein Fan von dom\u00e4nenspezifischem Design, deshalb passte die \"Zwiebelarchitektur\" hervorragend zu uns. Grundlage unserer Services ist nicht die Datenzugriffsschicht, sondern eine Sammlung mit dom\u00e4nenspezifischer Logik, die nur die Gesch\u00e4ftslogik enth\u00e4lt und keine Abh\u00e4ngigkeiten zur Infrastruktur aufweist. Auf diese Weise k\u00f6nnen wir die Dom\u00e4nen-Assembly unabh\u00e4ngig weiterentwickeln, um Probleme im Zusammenhang mit Frameworks zu l\u00f6sen.<\/p>\n<p>In diesem Stadium trafen wir auf unser erstes ernsthaftes Problem. Der Service sollte auf eine Dom\u00e4nen-Assembly verweisen, wir wollten die Logik unabh\u00e4ngig gestalten, und dabei st\u00f6rte uns das DRY-Prinzip erheblich. Die Entwickler wollten zur Vermeidung von Duplikationen Klassen aus benachbarten Assemblies wiederverwenden, und infolgedessen begannen die Dom\u00e4nen erneut miteinander verbunden zu werden. Wir analysierten die Ergebnisse und kamen zu dem Schluss, dass das Problem m\u00f6glicherweise auch im Bereich der Struktur des Quellcode-Repositorys liegt. Wir hatten ein gro\u00dfes Repository, in dem sich der gesamte Quellcode befand. Es war sehr schwierig, die L\u00f6sung f\u00fcr das gesamte Projekt auf einem lokalen Rechner zusammenzustellen. Daher wurden f\u00fcr Projektteile separate kleine L\u00f6sungen erstellt, und niemand verbot es, eine Common- oder Dom\u00e4nen-Assembly hinzuzuf\u00fcgen und wiederzuverwenden. Das einzige Werkzeug, das uns daran hinderte, war das Code-Review. Aber manchmal fiel auch dieses aus.<\/p>\n<p>Dann begannen wir, auf ein Modell mit separaten Repositories umzusteigen. Die Gesch\u00e4ftslogik begann nicht mehr von Service zu Service zu lecken, die Dom\u00e4nen wurden tats\u00e4chlich unabh\u00e4ngig. Begrenzte Kontexte werden klarer unterst\u00fctzt. Wie nutzen wir dabei infrastrukturelle Bibliotheken wieder? Wir haben sie in ein separates Repository ausgelagert, dann in Nuget-Pakete verpackt, die wir in Artifactory hinterlegt haben. Bei jeder \u00c4nderung erfolgt der Build und die Ver\u00f6ffentlichung automatisch.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/8ddbc750dc7c6d397a459acf7825de90.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nUnsere Services begannen, auf interne infrastrukturelle Pakete genau wie auf externe zu verweisen. Externe Bibliotheken laden wir von Nuget herunter. F\u00fcr die Arbeit mit Artifactory, wo wir diese Pakete ablegten, verwendeten wir zwei Paketmanager. In kleinen Repositories nutzen wir ebenfalls Nuget. In Repositories mit mehreren Services verwendeten wir Paket, das mehr Konsistenz bei den Versionen zwischen den Modulen gew\u00e4hrleistet.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/672a25a70a481bff68baebe963184ccd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nDurch die Arbeit am Quellcode, die leichte \u00c4nderung der Architektur und die Trennung der Repositories machen wir unsere Dienste unabh\u00e4ngiger.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"13\"><\/a><\/noindex><b><\/p>\n<h3>Infrastrukturprobleme<\/h3>\n<p><\/b><br \/>\nDie meisten Nachteile beim \u00dcbergang zu Mikrodiensten h\u00e4ngen mit der Infrastruktur zusammen. Sie ben\u00f6tigen automatisierte Bereitstellungen und neue Bibliotheken f\u00fcr die Infrastruktur.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"16\"><\/a><\/noindex><b>Manuelle Installation in Umgebungen<\/b><\/p>\n<p>Urspr\u00fcnglich haben wir die Umgebungen manuell eingerichtet. Um diesen Prozess zu automatisieren, haben wir eine CI\/CD-Pipeline erstellt. Wir w\u00e4hlten den Prozess des Continuous Delivery, da Continuous Deployment f\u00fcr uns aus Gesch\u00e4ftsprozesssicht derzeit nicht akzeptabel ist. Daher erfolgt die Bereitstellung per Knopfdruck, w\u00e4hrend die Tests automatisch durchgef\u00fchrt werden.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/0fc092326a48813398c6f3a031197bab.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nWir verwenden Atlassian, Bitbucket zur Speicherung des Quellcodes und Bamboo f\u00fcr den Build-Prozess. Wir schreiben unsere Build-Skripte gerne in Cake, da es dasselbe wie C# ist. In Artifactory kommen bereits fertige Pakete an, und Ansible wird automatisch auf die Testserver \u00fcbertragen, die dann sofort getestet werden k\u00f6nnen.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/fcc743cfaa4a24b906ceeb40ec1ba0a0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<noindex><a rel=\"nofollow\" name=\"14\"><\/a><\/noindex><b><\/p>\n<h3>Getrennte Protokollierung<\/h3>\n<p><\/b><br \/>\nEiner der Gedanken hinter dem Monolithen war das gemeinsame Logging. Wir mussten au\u00dferdem herausfinden, was wir mit den einzelnen Logs machen, die auf Festplatten liegen. Unsere Logs werden in Textdateien geschrieben. Wir entschieden uns, den Standard-ELK-Stack zu verwenden. Anstatt direkt \u00fcber Provider in ELK zu schreiben, haben wir uns entschieden, die Textlogs zu optimieren und die Trace_ID als Identifikator hinzuzuf\u00fcgen, zusammen mit dem Servicenamen, damit wir die Logs sp\u00e4ter analysieren k\u00f6nnen.<\/p>\n<p><img decoding=\"async\" alt=\"Der \u00dcbergang von Monolithen zu Mikroservices: Geschichte und Praxis\" src=\"\/wp-content\/uploads\/2019\/07\/8e58c66ac134e65abe34b59939f31483.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMit Filebeat haben wir die M\u00f6glichkeit, unsere Logs zu sammeln von <a class=\"wpil_keyword_link\" href=\"https:\/\/prohoster.info\/de\/server\/\"   title=\"Server\" data-wpil-keyword-link=\"linked\"  data-wpil-monitor-id=\"1338\">Server<\/a>, sie anschlie\u00dfend zu transformieren, Queries in Kibana im UI zu erstellen und zu sehen, wie der Aufruf zwischen den Diensten verlief. Dabei hilft die Trace_ID erheblich.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"15\"><\/a><\/noindex><b><\/p>\n<h3>Testen und Debuggen von miteinander verbundenen Services<\/h3>\n<p><\/b><br \/>\nUrspr\u00fcnglich waren wir uns nicht ganz sicher, wie wir die entwickelten Dienste debuggen sollten. Bei einem Monolithen war es einfach, wir starteten ihn auf einem lokalen Computer. Zuerst versuchten wir es auch mit Mikrodiensten, aber manchmal ben\u00f6tigt man f\u00fcr den vollst\u00e4ndigen Start eines Mikrodienstes mehrere andere, was unpraktisch ist. Wir haben verstanden, dass wir zu einem Modell \u00fcbergehen m\u00fcssen, bei dem wir nur den Dienst oder die Dienste, die wir debuggen m\u00f6chten, auf dem lokalen Computer lassen. Die anderen Dienste werden von Servern genutzt, die mit der Prod-Konfiguration \u00fcbereinstimmen. Nach dem Debuggen werden beim Testen f\u00fcr jede Aufgabe nur die ge\u00e4nderten Dienste auf den Testserver bereitgestellt. Auf diese Weise wird die L\u00f6sung in der Form getestet, in der sie in Zukunft in der Produktion erscheinen wird.<\/p>\n<p>Es gibt Server, auf denen nur Produktionsversionen der Dienste installiert sind. Diese Server sind f\u00fcr den Fall von Vorf\u00e4llen, zur \u00dcberpr\u00fcfung der Bereitstellung vor dem Deployment und f\u00fcr interne Schulungen n\u00f6tig.<\/p>\n<p>Wir haben einen automatisierten Testprozess mit der beliebten Bibliothek Specflow eingef\u00fchrt. Die Tests werden automatisch mit NUnit direkt nach dem Deployment aus Ansible gestartet. Wenn die Abdeckung der Aufgabe vollst\u00e4ndig automatisiert ist, ist kein manuelles Testing erforderlich. Obwohl manchmal doch zus\u00e4tzliches manuelles Testing notwendig ist. Um zu bestimmen, welche Tests f\u00fcr eine bestimmte Aufgabe durchgef\u00fchrt werden sollen, verwenden wir Tags in Jira.<\/p>\n<p>Zus\u00e4tzlich ist der Bedarf an Lasttests gestiegen, die fr\u00fcher nur in seltenen F\u00e4llen durchgef\u00fchrt wurden. F\u00fcr den Teststart verwenden wir JMeter, zur Speicherung nutzen wir InfluxDB und zur Erstellung von Grafiken des Prozesses verwenden wir Grafana.<\/p>\n<p><b><\/p>\n<h3>Was haben wir erreicht?<\/h3>\n<p><\/b><br \/>\nErstens haben wir das Konzept \u201eRelease\u201c abgeschafft. Die monstr\u00f6sen Releases alle zwei Monate sind verschwunden, bei denen dieses Ungeheuer in der Produktionsumgebung bereitgestellt wurde und vor\u00fcbergehend Gesch\u00e4ftsprozesse st\u00f6rte. Jetzt stellen wir die Dienste im Durchschnitt alle 1,5 Tage bereit, indem wir sie gruppieren, da sie nach Genehmigung in die Betriebsphase \u00fcbergehen.<\/p>\n<p>In unserem System gibt es keine fatalen Ausf\u00e4lle. Wenn wir einen Mikrodienst mit einem Fehler herausgeben, ist die damit verbundene Funktionalit\u00e4t beeintr\u00e4chtigt, w\u00e4hrend die gesamte andere Funktionalit\u00e4t nicht betroffen ist. Dies verbessert die Benutzererfahrung erheblich.<\/p>\n<p>Wir k\u00f6nnen das Bereitstellungsschema verwalten. Es ist m\u00f6glich, Gruppen von Diensten separat von der restlichen L\u00f6sung zu \u0432\u044b\u0434\u0435\u043ben, falls dies erforderlich ist.<\/p>\n<p>Dar\u00fcber hinaus haben wir das Problem mit langen Warteschlangen f\u00fcr Anpassungen erheblich verringert. Wir haben separate Produktteams, die unabh\u00e4ngig an Teilen der Dienste arbeiten. Hier passt der Scrum-Prozess bereits gut. Ein bestimmtes Team kann einen eigenen Product Owner haben, der Aufgaben zuweist. <\/p>\n<p><b><\/p>\n<h3>Zusammenfassung<\/h3>\n<p><\/b><\/p>\n<ul>\n<li>Mikroservices eignen sich gut f\u00fcr die Dekomposition komplexer Systeme. Im Verlauf beginnen wir zu verstehen, was in unserem System vorhanden ist, welche begrenzten Kontexte bestehen und wo deren Grenzen verlaufen. Dies erm\u00f6glicht es, Anpassungen korrekt auf Module zu verteilen und Verwirrung im Code zu vermeiden. <\/li>\n<li>Mikroservices bieten organisatorische Vorteile. Oft wird nur \u00fcber sie als Architektur gesprochen, aber jede Architektur dient der L\u00f6sung von Gesch\u00e4ftsbed\u00fcrfnissen und nicht um ihrer selbst willen. Daher k\u00f6nnen wir sagen, dass Mikroservices gut geeignet sind, um Aufgaben in kleinen Teams zu l\u00f6sen, insbesondere da Scrum derzeit sehr beliebt ist.<\/li>\n<li>Die Aufteilung ist ein iterativer Prozess. Man kann eine Anwendung nicht einfach in Mikroservices aufteilen. Das entstandene Produkt wird wahrscheinlich nicht funktionsf\u00e4hig sein. Bei der Trennung von Mikrodiensten ist es vorteilhaft, das bestehende Legacy neu zu schreiben, also in Code umzuwandeln, der uns gef\u00e4llt und besser auf die Gesch\u00e4ftsanforderungen in Bezug auf Funktionalit\u00e4t und Geschwindigkeit zugeschnitten ist.\n<p><i>Eine kleine Warnung:<\/i> Die Kosten f\u00fcr den \u00dcbergang zu Mikroservices sind recht erheblich. Allein die L\u00f6sung der Infrastrukturproblematik hat viel Zeit in Anspruch genommen. Daher, wenn Sie eine kleine Anwendung haben, die keine spezifische Skalierung erfordert, und wenn es nicht viele Kunden gibt, die um die Aufmerksamkeit und Zeit Ihres Teams k\u00e4mpfen, dann sind Mikroservices m\u00f6glicherweise nicht das, was Sie heute ben\u00f6tigen. Es ist ziemlich teuer. Wenn Sie mit Mikroservices beginnen, werden die Anfangskosten h\u00f6her sein, als wenn dasselbe Projekt mit der Entwicklung eines Monolithen begonnen wird. <\/p>\n<p>P.S. Eine emotionalere Erz\u00e4hlung (als ob sie pers\u00f6nlich an Sie gerichtet ist) \u2013 zu <noindex><a rel=\"nofollow\" href=\"https:\/\/www.youtube.com\/watch?v=qTNbx18DzpQ\">dem Link<\/a><\/noindex>. <br \/>\nHier ist die vollst\u00e4ndige Version des Vortrags.<\/li>\n<\/ul>\n<p>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/raiffeisenbank\/blog\/458404\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000. \u041f\u0435\u0440\u0432\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u044b\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 Visual Basic 6. \u0421 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u044f\u0437\u044b\u043a\u0435 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c, \u0442\u0430\u043a \u043a\u0430\u043a IDE [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":26858,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35906","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:07:29+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:07:29+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Der \u00dcbergang vom Monolithen zu Mikrodiensten: Geschichte und Praxis | ProHoster","description":"In diesem Artikel werde ich dar\u00fcber erz\u00e4hlen, wie das Projekt, an dem ich arbeite, von einem gro\u00dfen Monolithen zu einer Reihe von Mikrodiensten umgewandelt wurde. Das Projekt hat seine Geschichte schon vor langer Zeit begonnen, zu Beginn der 2000er Jahre.","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0435\u0440\u0435\u0445\u043e\u0434 \u043e\u0442 \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u043a \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u0430\u043c: \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0438 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430 | ProHoster","og:description":"\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043f\u0440\u043e\u0435\u043a\u0442, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u043b\u0441\u044f \u0438\u0437 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043c\u043e\u043d\u043e\u043b\u0438\u0442\u0430 \u0432 \u043d\u0430\u0431\u043e\u0440 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432. \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430\u0447\u0430\u043b \u0441\u0432\u043e\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0434\u0430\u0432\u043d\u043e, \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 2000.","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/perehod-ot-monolita-k-mikroservisam-istoriya-i-praktika","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:07:29+00:00","article:modified_time":"2019-10-31T19:07:29+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35906","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-02-09 17:04:56","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:54:38","updated":"2026-02-09 17:04:56","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/35906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=35906"}],"version-history":[{"count":1,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/35906\/revisions"}],"predecessor-version":[{"id":158582,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/35906\/revisions\/158582"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/26858"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=35906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=35906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=35906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}