project omega
Das letzte Webarchitekturmuster für Unternehmen, das Sie jemals brauchen werden. Bis zum nächsten.
TL;DR
Das Ziel besteht darin, die Entwicklererfahrung zu optimieren, indem Folgendes möglich ist:
- Entwickeln Sie sich lokal, als wäre es ein Monolith
- Als separate Microservices bereitstellen
- Simulieren Sie die Produktionsumgebung lokal mit Docker
Demo
project omega Proof of Concept – Microservices Monolith Hybrid
project omega Demo – Kubernetes-Microserves und Standalone-Container-Bereitstellung
Warum
Ich möchte beweisen, dass wir für Skalierbarkeit keine Abstriche bei der Entwicklereffizienz machen müssen. Weitere Diskussionen zu den Vor- und Nachteilen von Microservices und Monolithen finden Sie hier: Microservices und Monolithen.
Mein Eindruck ist, dass viele Branchenexperten uns glauben machen wollen, dass dies unsere drei wichtigsten Optionen sind:
- Monolith
- Mikrodienste
- „Hybrid“ (nicht wirklich ein Hybrid, sowohl ein Monolith als auch einige Microservices)
Ich möchte zeigen, dass wir uns für keine dieser Optionen entscheiden müssen. Mit ein wenig Kreativität können wir einen echten „Hybrid“ schaffen, der sowohl ein Monolith als auch eine Reihe von Mikrodiensten ist. Ich glaube nicht, dass wir mit meiner aktuellen Strategie alle Nachteile von Monolithen und Microservices beseitigen können, aber wir können viele der Schwachstellen beider beseitigen.
Was es nicht ist
- Ich versuche nicht, ein Framework zu erstellen (zumindest noch nicht ...). Ich baue nur als Experiment alle Legosteine, die ich habe, in einer anderen Konfiguration zusammen.
- Dies ist kein Gemeinschaftsprojekt. Ich beabsichtige, häufig und ohne Vorankündigung dramatische Änderungen vorzunehmen. Wenn Ihnen dieses Konzept interessant erscheint und Sie einen Beitrag leisten möchten, kontaktieren Sie mich zunächst.
Projektziele
- Erstellen Sie ein Muster, das für Projekte als kleine Einzelentwickler-Hobbyprojekte funktioniert und sich auch auf Dutzende oder sogar Hunderte von Entwicklern skalieren lässt, die an großen und komplexen Unternehmens-Webanwendungen arbeiten.
- Lokal entwickeln können, als wäre es ein Monolith:
- Ein Repository. Aus den gleichen Gründen entscheiden sich Unternehmen für einen Monorepo-Ansatz.
- Maximal 3 auszuführende Prozesse (Client-Benutzeroberfläche, Server, Docker-Abhängigkeiten mit Datenbank, Nachrichtenwarteschlange usw.). Wir möchten nicht, dass seitenweise Setup-Dokumente erstellt und ausgeführt werden.
- Kann als Microservices bereitgestellt werden.
- Sie können eine Produktionsumgebung mit Microservices simulieren, die in Docker-Containern ausgeführt werden.
- Extrem schnelle Einrichtungszeit. Alle Abhängigkeiten außer Node und .NET sollten als Docker-Abhängigkeiten enthalten sein (Datenbank, Nachrichtenwarteschlange usw.). Neue Benutzer sollten in der Lage sein, .NET und Node zu installieren, das Repo zu klonen und dann Installations- und Ausführungsbefehle auszuführen.
- Extrem schnelles Hot-Reload sowohl für den Client als auch für den Server in der Entwicklungsumgebung.
- Sie können die Anwendung unter Windows, Linux und Mac entwickeln und ausführen.
- Seien Sie in der Lage, schnell einen neuen Dienst einzurichten.
Tech-Stack
Der Tech-Stack ist für das High-Level-Konzept, das ich zu beweisen versuche, größtenteils irrelevant, aber für dieses Projekt werde ich Folgendes verwenden:
- .NET 5 für Dienste
- React-Frontend (einfache Create-React-App mit Typoskript)
- Docker
Konzepte auf hohem Niveau
Unternehmen mit großen Anwendungen werden immer mehr in Richtung Microservices gedrängt, um (unter anderem) horizontal skalieren zu können. Um das zu erreichen, schauen wir uns also etwa Folgendes an:
Hier ist eine weitere Version, die zeigt, wie die horizontale Skalierung implementiert werden könnte:
Sobald wir diesen Weg einschlagen, stehen wir vor einem echten Problem mit der lokalen Entwicklung. Es hängt wirklich davon ab, wie das Produkt beschaffen ist, wie viele Entwickler es gibt und wer wie oft an was arbeitet. Allerdings wird ein großer Teil der Unternehmen, die sich für Microservices entscheiden, in eine Situation geraten, in der Entwickler schwierige Entscheidungen darüber treffen müssen, wie sie ihre tägliche Entwicklung durchführen wollen. Das Ziel project omega besteht darin, zu zeigen, dass wir den Aufwand für die lokale Ausführung eines Dienstes eliminieren können, indem wir sie alle in einer Anwendung kombinieren, während sie lokal ausgeführt werden:
Hier ist die Ordnerstruktur:
Und so würde es aussehen, wenn es als Microservices bereitgestellt wird:
Jede Instanz verfügt über eine Kopie des gesamten Codes, führt jedoch nur die Initialisierung, Service-Endpunkt-Routen und Arbeitsprozesse für einen bestimmten Mikroservice aus.
Aus diesem Grund ist es so einfach, die Anwendung lokal als Monolith auszuführen, da wir einfach nach einer Umgebungsvariablen namens SERVICE_KEY
suchen oder, falls diese nicht vorhanden ist, alle Dienste initialisieren.
Beispiele für andere dienstspezifische Initialisierungen:
- Einrichtung der Abhängigkeitsinjektion
- Datenbankverbindungszeichenfolgen
- Datenbankmigrationen
- Initialisierung der Nachrichtenwarteschlange
- Richten Sie eine verteilte Cache-Konnektivität ein
- Einrichtung der Konnektivität anderer Cloud-Ressourcen
- API-Initialisierung von Drittanbietern
Wenn Startup aufgerufen wird, durchsucht es Assemblys nach Typen, die ProjectOmegaService
erben, erstellt eine Instanz und führt die Initialisierungslogik dieses Dienstes aus. Bei lokaler Ausführung werden sie alle ausgeführt.
Einrichtungsanweisungen
Voraussetzungen installieren:
- .NET 5
- Knoten
- Garn
- Docker
Beachten Sie, dass zum Ausführen der neuesten Docker-Version unter Windows möglicherweise einige zusätzliche Schritte erforderlich sind, wenn Sie dies eine Weile nicht getan haben, z. B. die Installation von WSL 2 und die Aktualisierung Ihrer WSL-Distribution. Befolgen Sie die Anweisungen auf der Docker-Website.
Schritte:
- Klonen Sie dieses Repo
- Führen Sie in einem Terminal vom Repo-Root aus
yarn run installAll
aus - Wenn Sie SQL Server auf einem anderen Port als 1434 ausführen möchten:
- Führen Sie
yarn run syncEnvFiles
aus - Ändern Sie
OMEGA_DEFAULT_DB_PORT
und OMEGA_MSSQL_HOST_PORT
in .env.server
- Starten Sie die Abhängigkeiten mit dem Befehl „
yarn run dockerDepsUpDetached
- Führen Sie DB-Migrationen beim ersten Mal aus, oder wenn Sie bei Datenbankaktualisierungen Änderungen von jemand anderem erhalten:
yarn run dbMigrate
- Führen Sie die App im lokalen Entwicklungsmodus mit einer dieser Optionen aus:
- Option 1:
yarn run both
(dies wird gleichzeitig verwendet, um die Befehle aus Option 2 auszuführen). - Option 2: 2 separate Terminals verwenden. In einem Terminal wird
yarn run client
und im anderen der yarn run server
ausgeführt
- Greifen Sie auf https://localhost:3000 zu (klicken Sie nach der https-Warnung)
Bevor Sie Unit-Tests zum ersten Mal mit dotnet test
ausführen oder nachdem Sie Unit-Tests zu einem neuen DB-Schema hinzugefügt haben:
- Starten Sie Abhängigkeiten, wenn sie nicht bereits mit
yarn run dockerDepsUpDetached
ausgeführt werden - Führen Sie
yarn run testDbMigrate
aus - Führen Sie dann
dotnet test
aus
So simulieren Sie Produktion und Microservices in Docker:
- Stellen Sie sicher, dass Docker-Abhängigkeiten mit
yarn run dockerDepsUpDetached
ausgeführt werden - Führen Sie in einem Terminal im Repo-Stammverzeichnis
yarn run dockerRecreateFull
aus - Greifen Sie auf https://localhost:3000 zu (klicken Sie nach der https-Warnung)
Nächste Schritte
- Protokollierung von Änderungen
- Experimentieren Sie mit dem Serilog JSON-Formatierer
- Fügen Sie Korrelations-IDs und andere Kontextinformationen zu Protokolleinträgen hinzu
- Fügen Sie zusätzliche Dokumentation hinzu
- Diagramme zur Funktionsweise der Docker-Simulation
- Docker-Abhängigkeiten
- Textbeschreibung, was es ist und wie es funktioniert
- Diagramme, wie Docker-Deps in den Entwicklungsprozess passen
- Routing-/Proxy-Dokumentation
- DB-Migrationen
- RPC-Test zwischen Diensten anstelle von HTTP-Rest-Aufrufen (vielleicht mit so etwas: https://github.com/aspnet/AspLabs/tree/main/src/GrpcHttpApi)
- Zur dienstübergreifenden Client-Basisklasse hinzufügen, um die Fehlerbehandlung und -protokollierung zu abstrahieren
- Auth-Implementierung
- Registrierung der Front-End-Site
- Dienst-zu-Dienst-Authentifizierung (OAuth?)
- Automatische Dokumentationsgenerierung (Swagger- und HTML-XML-Dokumentationsausgabe)
- Warteschlangeneinrichtung und Arbeitsprozessdienste
- Abstrakte Warteschlangendefinition (um die optionale Nutzung von Cloud-Diensten zu ermöglichen)
- Einfacher Dienst vom Typ Arbeitsprozess mit einer Ereignisschleife, die nach Nachrichten sucht
- RabbitMQ in docker-compose.deps.yml
- Die Basisimplementierung von RabbitMQ ist mit dem Worker-Prozessdienst verbunden
- Zusätzliche lokale Kubernetes-Demoarbeit
- Für die Datenbank muss wahrscheinlich gelernt werden, wie man ein persistentes Kubernetes-Volume verwendet, es sei denn, ich finde heraus, wie ich das Netzwerk anpassen kann, um die Host-Datenbank verfügbar zu machen
- Fügen Sie Seq hinzu oder machen Sie die Seq-Funktionalität optional und verwenden Sie sie nicht, wenn Sie sie in Kubernetes ausführen
- Metaprojekt/Skript zur Analyse der Lösung
- Analysieren Sie betroffene Dienste basierend auf geänderten Dateien (für die Granularität der Bereitstellung).
- Projektgerüst:
- Möglichkeit, eine neue Kopie des Projekts mit einem anderen Projektschlüssel als Omega für alle Projekt-/Verzeichnisnamen zu erstellen
- Möglichkeit, Docker-Container für ein neues Projekt zu starten und effektive Integrationstests durchzuführen, um eine erfolgreiche Erstellung neuer Projekte sicherzustellen
Sonstiges
Wenn Sie unter Linux entwickeln, kann beim Starten des Servers dieser Fehler auftreten:
System.AggregateException: Es sind ein oder mehrere Fehler aufgetreten. (Das konfigurierte Benutzerlimit (128) für die Anzahl der Inotify-Instanzen wurde erreicht, oder das prozessbezogene Limit für die Anzahl offener Dateideskriptoren wurde erreicht.)
Dies wird wahrscheinlich dadurch verursacht, dass zu viele Dateiüberwachungen von vscode verbraucht werden. Sie können Ihr inotify
Instanzlimit erhöhen (nicht nur das Überwachungslimit, das wahrscheinlich bereits in Ihrer Datei /etc/sysctl.conf
sehr hoch eingestellt ist), indem Sie diesen Befehl ausführen:
echo fs.inotify.max_user_instances=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
Andere Dokumentation
Kosten-Nutzen-Analyse von Entwurfsmustern: DesignPatternCostBenefit.md
Entwurfsmustervariationen: DesignPatternVariations.md
Entscheidungen: Decisions.md
Philosophien und Tiraden zur Softwareentwicklung: https://gist.github.com/mikey-t/3d5d6f0f5316abf9e74fb553be9fdef3