Erfahren Sie, wie Sie eine skalierbare Softwarearchitektur erstellen, die mit Ihrer Webanwendung wächst. Entdecken Sie praktische Strategien, Cloud-Tipps, Einblicke in den Tech-Stack und Beispiele aus der Praxis aus JavaScript- und .NET-Projekten.
A QUICK SUMMARY – FOR THE BUSY ONES
Analysieren Sie vor der Implementierung von Änderungen die Kennzahlen, um echte Engpässe zu identifizieren. Vermeiden Sie vorzeitige Optimierungen, indem Sie mit Daten auf hoher Ebene beginnen und sich auf granulare Erkenntnisse beschränken. Dadurch wird sichergestellt, dass Ihre Korrekturen zielgerichtet und wirksam sind.
Cloud-Plattformen bieten eine kostengünstige, flexible Skalierung mit Pay-as-you-go-Modellen und automatischen Skalierungsfunktionen. Rechtliche und datenschutzrechtliche Einschränkungen können jedoch in seltenen Fällen eine Einrichtung vor Ort erforderlich machen.
Wenn Sie noch nicht bereit für Microservices sind, bieten modulare Monolithen das Beste aus beiden Welten — die Einfachheit von Monolithen mit skalierbarer Modularität — ohne den vollen Overhead verteilter Systeme.
TABLE OF CONTENTS
Viele Technologieführer können sich mit dieser Geschichte identifizieren — Sie wählen einen Tech-Stack, der perfekt zu Ihrer Anwendung in der Anfangsphase zu passen scheint — er ist kostengünstig, schnell bereitzustellen und einfach zu verwalten. Mit der Erweiterung der Nutzerbasis zeigt die Plattform jedoch erste Anzeichen einer Überlastung. Die Ladezeiten der Apps nehmen zu und bei Ihren Benutzern treten immer mehr Ausfallzeiten auf. Die horizontale Skalierung wird ebenfalls zu einer großen Herausforderung.
Es ist schwierig, den besten Weg zu finden, um voranzukommen. Die gute Nachricht ist, wir sind hier um zu helfen.
In diesem Artikel teilen wir unsere Meinung zur Erstellung einer skalierbaren Softwarearchitektur, die auf unserer Erfahrung beim Erstellen von JavaScript- und .NET-basierten Webanwendungsprojekten basiert.
Aus unserer Erfahrung bevor Sie irgendeine Form von Strategie oder Lösung zur Lösung von Problemen implementieren, sollten Sie sich mit deren Daten befassen, beginnt mit einem allgemeinen Überblick und taucht dann in einen detaillierteren Look ein. Auf diese Weise können Sie vermeiden, sich zu früh im Prozess mit der Optimierung zu befassen und sich auf reale, tatsächliche Probleme zu konzentrieren.
Einmal standen wir vor einer Situation, in der wir einen komplexen Prozess im System hatten, der im Wesentlichen das Rückgrat der gesamten Anwendung war. Es verursachte viele Probleme und war äußerst ineffizient, was sich — wie Sie sich vorstellen können — auf den Aufgabenablauf auswirkte. Anstatt Nutzer anzulocken, hielt es sie davon ab, die Plattform zu nutzen.
Wir wussten, dass sich die Dinge ändern mussten, aber bevor wir Änderungen vornahmen, definierten wir eine Reihe von Kennzahlen, um herauszufinden, worauf wir uns konzentrieren sollten. Wir haben angefangen, Dinge zu beobachten, zum Beispiel, wie lange bestimmte Teile des Prozesses gedauert haben. Auf diese Weise haben wir einen komplexen Prozess in messbare Zahlen unterteilt, mit denen wir arbeiten konnten.
Dieser Ansatz war wertvoll, da er uns half, die größten Engpässe zu erkennen. Darüber hinaus konnten wir bei der Implementierung von Änderungen oder Korrekturen überprüfen, ob wir uns in die richtige Richtung bewegten.
Unabhängig davon, für welche Strategie Sie sich entscheiden, müssen Sie sie in der Praxis validieren, um sicherzustellen, dass sie einen echten Mehrwert bietet. Deshalb ist es wichtig, Kennzahlen zu haben, bevor Sie Änderungen vornehmen.
Aus rein technischer Sicht In der Cloud ist die Skalierung in der Regel einfacher. Diese Dienste bieten im Vergleich zu lokalen Lösungen einen effizienteren und flexibleren Skalierungsansatz, da sie einem Pay-as-you-go-Ansatz folgen.
Mit einer skalierbaren Softwarearchitektur können Sie Ihre Infrastruktur schnell an sich ändernde Anforderungen anpassen, ohne die Vorabkosten und den Wartungsaufwand physischer Hardware zu tragen. Das bedeutet, dass Sie bei Verkehrsspitzen hochskalieren können (denken Sie an Black Friday für E-Commerce-Plattformen) und in ruhigeren Zeiten herunterskalieren und so Ihren Ressourcenverbrauch und Ihre Kosten optimieren.
Allerdings werden nicht alle Unternehmen aufgrund rechtlicher Einschränkungen wie Datenschutz- und Sicherheitsrichtlinien in der Lage sein, ihre Infrastruktur in der Cloud aufrechtzuerhalten. Es ist zwar selten, aber manchmal ist es einfacher, sicherer und erschwinglicher, sich auf eine Infrastruktur vor Ort zu verlassen. Wenn das nicht Ihr Geschäftsszenario ist, empfehlen wir Ihnen dringend, sich für die Cloud zu entscheiden.
Es ist wichtig zu verstehen, wie das System funktioniert, und sich seine Spezifikationen anzusehen. Leistungskennzahlen sind sicherlich wichtig, aber Es ist auch wichtig zu erkennen, dass einige Teile einer Anwendung selten verwendet werden. Beispielsweise müssen Sie Finanzberichte möglicherweise nur einmal alle sechs Monate oder einmal im Jahr erstellen.
In einem solchen Fall ist es nicht sinnvoll, diese Funktionalität im Kernteil der Anwendung beizubehalten. Stattdessen könnten wir es in einen eigenständigen Dienst oder einen anderen Teil der Anwendung aufteilen.
Dieser Ansatz ermöglicht es uns, besser zu verstehen, wann und wie wir bestimmte Funktionen nutzen werden. Nicht jede Anwendung wird täglich auf einfache Weise verwendet. Manchmal müssen Sie einen Prozess auslösen, der mehrere Stunden läuft, um die erforderlichen Ergebnisse zu erzielen. Wenn dies Teil der Hauptanwendung wäre, könnte es Ressourcen verbrauchen, die andere Funktionen benötigen, was zu Problemen führen würde, nicht weil es langsam ist, sondern weil es Ressourcen für andere Aufgaben beansprucht.
Sie werden wahrscheinlich Situationen erleben, in denen die Nachfrage nach Ihrem System plötzlich steigt — sei es das oben erwähnte Beispiel von Black Friday, wenn Sie ein E-Commerce-Unternehmen sind, oder Benutzer, die am Zahltag auf ihre Bankkonten zugreifen. In jedem Fall benötigen Sie Mechanismen, die Ihnen helfen, die Leistung auch bei Verkehrsspitzen aufrechtzuerhalten und gleichzeitig die Kosten für „ruhigere“ Zeiten zu optimieren.
Ohne einen Cloud-basierten Ansatz müssten wir buchstäblich zusätzliche Server kaufen, nur um sie anschließend herunterzufahren. Black Friday ist zwar ein Extremfall, aber eine skalierbare Softwarearchitektur ermöglicht die Anpassung an unterschiedliche Geschäftskontexte und -strategien und gewährleistet so eine nahtlose Skalierbarkeit bei schwankenden Anforderungen.
Cloud-Lösungen unterstützen dies erheblich, denn anstatt sich die Mühe zu machen, Hardware zu bestellen, einen Administrator hinzuzuziehen und sich um den gesamten Einrichtungsaufwand zu kümmern, wir können einfach in wenigen Minuten skalieren. Der Unterschied in Leichtigkeit und Effizienz ist unvergleichlich.
Die automatische Skalierung passt die Ressourcen Ihrer Web-Apps automatisch an den aktuellen Bedarf an. Damit können Sie wichtige Kennzahlen wie CPU-Auslastung, Speicherverbrauch oder Anforderungsraten überwachen und bei Bedarf Instanzen hinzufügen/entfernen.
Die Wahl des richtigen Tech-Stacks ist entscheidend für die Skalierbarkeit, aber die Verwendung von Microservices oder das Erstellen von APIs in einer Technologie wie Go ist beispielsweise nicht immer die beste Wahl. Unserer Meinung nach reichen beliebte Lösungen wie Singlethread-Node.js oder monolithische Architekturen oft für eine skalierbare Softwarearchitektur aus, insbesondere wenn das Team Erfahrung in diesem Bereich hat.
Der Schlüssel ist zu Passen Sie die Technologie an die Fähigkeiten des Teams und die tatsächlichen Bedürfnisse des Projekts an, um einen klaren, gut strukturierten und sicheren Code zu gewährleisten. Es ist wichtig, sich daran zu erinnern, dass jede Strategie mit zusätzlichen Kosten verbunden ist — oft erhebliche Kosten wie Wartung, zukünftige Entwicklung oder Teamtraining.
Sie sollten nicht in die Falle tappen, bestimmte Strategien anzuwenden, nur weil sie im Trend liegen. Trends haben immer ihren Preis. Auch wenn eine Strategie auf Ihre Kennzahlen abgestimmt ist und ein Problem löst, bringt sie auch neue Herausforderungen mit sich. Sie können sie nicht „einfach“ implementieren und erwarten, dass sie funktioniert, ohne mögliche Konsequenzen zu berücksichtigen.
Im Fall von Nischen-Programmiersprachen oder Microservices könnten diese aufgrund eines komplexeren Implementierungsprozesses und einer geringeren Marktbeliebtheit in Form hoher Kosten auftreten (was die Suche nach Go-Entwicklern schwierig macht).
In der Zwischenzeit könnten Microservices Herausforderungen bei der Bereitstellung, der Kommunikation zwischen Diensten, der Infrastruktur und der Wartung mit sich bringen. Es könnte auch zu Kompromissen in Bezug auf lokale Entwicklung, Latenz und Datenkonsistenz kommen.
Prisma, eine bekannte Bibliothek im JavaScript- und TypeScript-Ökosystem, kann als warnendes Beispiel dafür dienen, sich mit einer Technologie zu beschäftigen, die nicht ideal zu ihnen passt. Vor einiger Zeit entschieden sich die Gründer der Plattform für Rust (was viel Aufsehen erregte) und schrieben ihre Engine in der Sprache um. Vor Kurzem haben sie jedoch ihren Kurs geändert und sind zu TypeScript zurückgekehrt.
Es stellte sich heraus, dass Rust zwar unglaublich schnell und effizient ist, aber auch erhebliche Herausforderungen mit sich brachte — vor allem in Bezug auf die Wartbarkeit. Wir gehen davon aus, dass entweder niemand wusste, wie man damit richtig umgeht, oder die vermeintlichen Leistungssteigerungen waren in der Praxis nicht so wirksam.
Wenn ein Unternehmen bereits über ein etabliertes Team von Spezialisten verfügt, ist es oft sinnvoller, eine Sprache oder Technologie zu wählen, die das Team kennt. Wenn uns beispielsweise ein Kunde bei Brainhub wegen der Entwicklung einer Anwendung anspricht, möchten wir ihn in der Regel darüber informieren, warum es besser ist, etwas zu verwenden, mit dem sowohl sein Team als auch der Markt bereits vertraut sind.
Was nützt es schließlich, eine Sprache oder ein Ökosystem zu verwenden, das theoretisch um 10% effizienter ist, wenn es viel schwieriger ist, qualifizierte Spezialisten zu finden? Nur weil wir anfangen, in einer ultraeffizienten Sprache zu schreiben oder ein solches Ökosystem verwenden, das wir nicht vollständig verstehen, heißt das nicht, dass wir tatsächlich eine hohe Effizienz erreichen werden.
Erfahrung und Fachwissen sind weitaus wichtiger als bloße theoretische Optimierung. Ein A-Player, selbst in einer relativ langsamen Sprache oder Technologie, ist in der Regel viel produktiver als jemand, der mit einem neuen, unbekannten Stack zu kämpfen hat.
Beim Sharding werden große Datensätze in kleinere, besser verwaltbare Teile, sogenannte Shards, aufgeteilt, die jeweils auf verschiedenen Datenbankservern gespeichert sind. Das verbessert die Datenbankleistung indem Lese- und Schreibvorgänge auf mehrere Server verteilt werden.
Sie können beispielsweise eine Benutzerdatenbank nach Regionen teilen, um sicherzustellen, dass Abfragen für eine Region keinen einzelnen Server überlasten. Dies ermöglicht eine horizontale Skalierung und reduziert die Belastung einer einzelnen Datenbankinstanz.
Failover-Systeme stellen sicher, dass wenn eine Komponente (z. B. ein Server oder eine Datenbank) ausfällt, übernimmt eine andere Komponente automatisch und mit minimaler Unterbrechung. Redundanz beinhaltet die Aufrechterhaltung doppelter Systeme oder Server, die das Primärsystem widerspiegeln.
Einige Beispiele hierfür sind mehrere Rechenzentren oder Cloud-Regionen, die sicherstellen, dass, wenn eine ausfällt, die andere die Last bewältigen kann. Dies erhöht die Verfügbarkeit und verhindert Betriebsunterbrechungen aufgrund von Ausfällen.
Wenn eine monolithische Architektur nicht mehr ausreicht, um mit der Skalierbarkeit der App Schritt zu halten, stehen Führungskräfte oft vor dem Dilemma, ob sie alles in sich aufnehmen und einen Microservice-Ansatz verfolgen sollten. Gleichzeitig befürchten sie jedoch, dass sie es nicht schnell genug integrieren können und Schwierigkeiten haben werden, es zu verwalten.
Dies ist ein mehrstufiges Problem. Einerseits stimmt es, dass es schwierig wird, ein monolithisches Altsystem zu warten oder zu skalieren, und es erfordert Modularität ist der richtige Schritt. Andererseits kann eine groß angelegte Umstellung auf Microservices (insbesondere, wenn Sie sich aufgrund der Beliebtheit dafür entscheiden, nicht aufgrund der nachgewiesenen Eignung für das Projekt) zu unnötiger Komplexität und Kosten führen.
Ein modularer Monolith kann eine praktikable Alternative sein. Er ermöglicht die unkomplizierte Bereitstellung eines Monolithen und bietet gleichzeitig die Flexibilität und Skalierbarkeit von Microservices. Dies macht es zur idealen Wahl für Unternehmen, die ältere Systeme modernisieren möchten, ohne die zusätzliche betriebliche Komplexität einer vollständigen Microservices-Architektur in Kauf nehmen zu müssen.
Modulare Monolithen schützen Sie vor Szenarien, in denen Sie von Anfang an Microservices erstellen, das System auf eine bestimmte Art und Weise unterteilen, nur um zu erkennen, dass einige Komponenten tatsächlich als Teil desselben Konzepts zusammengehören.
Wenn wir diese architektonischen Entscheidungen zu früh treffen, wird es später deutlich schwieriger, Dienste zusammenzuführen, als sie zum richtigen Zeitpunkt aufzuteilen.
Wir empfehlen, unseren speziellen Beitrag am modulare Monolith-Architektur eine Lektüre, um mehr über den Ansatz zu erfahren.
Die Wahrheit ist, dass Cloud-Rechnungen schnell in die Höhe schnellen können, wenn Sie Ihre Ausgaben nicht richtig verwalten. Die meisten Cloud-Anbieter bieten ein kostenloses Kontingent an, mit dem Sie eine begrenzte Anzahl von Diensten nutzen können, z. B. das Hosten einer App oder einer Datenbank, ohne etwas zu bezahlen. Dies ist eine großartige Option für den Einstieg. Wenn Ihre App also noch nicht ganz produktionsbereit ist, ist dies auf jeden Fall eine Überlegung wert.
Eine weitere Option für Startups ist AWS Startup Credits. AWS investiert in Startups, indem es ihnen virtuelle Kredite gewährt — manchmal bis zu 100.000$. Startups können diese Credits verwenden, bevor sie beginnen, für Dienstleistungen zu bezahlen. Diese Strategie fördert jedoch auch die Bindung an einen Anbieter, da sich Unternehmen mit der kostenlosen Nutzung der AWS-Services vertraut machen. Aus Sicht des Anbieters ist diese Taktik genial, aber sie bedeutet, dass Startups die Credits mit Bedacht einsetzen müssen, da sonst die potenziellen Wechselkosten enorm sein werden.
Unser Rat an Sie: Verfolgen Sie Ihre Ressourcennutzung und überprüfen Sie, ob Sie wirklich alles benötigen, was Sie bereitgestellt haben. Es ist, als würden Sie sich für ein Autowaschanlagenpaket entscheiden — Sie können je nach Bedarf etwas oder viel ausgeben. Vermeiden Sie es einfach, für Kapazität, die Sie nicht nutzen, zu viel zu bezahlen, z. B. das Hosten einer Infrastruktur für eine Million Benutzer, wenn Sie nur 10.000 haben.
Kennzahlen und Überwachung sind wichtig, aber ebenso wichtig ist es, die Ergebnisse zu analysieren und sie zur Umsetzung von Verbesserungen zu nutzen. Wir sahen uns mit einer Situation konfrontiert, in der es um einen zentralen Datenanalyseprozess ging, der zwar die Nutzer einbeziehen sollte, aber das dauerte zu lange und führte stattdessen zu Frustration.
Wir haben damit begonnen, Kennzahlen zu verfolgen und den Engpass zu identifizieren. Die naheliegende Lösung bestand darin, den Prozess in einen anderen Dienst aufzuteilen oder ihn in der Cloud zu skalieren, aber das wären teure Korrekturen gewesen. Manchmal sind die naheliegendsten Lösungen nicht unbedingt die besten.
Stattdessen haben wir einen einfacheren Ansatz gewählt, der sich als effektiv und kosteneffizient erwiesen hat. Ursprünglich klickte der Benutzer auf „Analysieren“ und sah einen Ladebildschirm, bis der Vorgang abgeschlossen war, was lange dauerte. Als wir das Problem untersuchten, stellten wir fest, dass es nicht die Länge des Prozesses an sich war, die das Problem war. Es ging eher darum, den Endbenutzer darüber zu informieren, dass es eine Weile dauern würde, bis seine Anfrage abgeschlossen ist. Deshalb beschlossen wir, diese Herausforderung anzugehen, indem wir die Benutzer darüber informierten, dass die Analyse im Hintergrund läuft und dass sie eine Benachrichtigung erhalten würden, wenn sie fertig ist. Dadurch konnten sie die App weiter verwenden, ohne sich festgefahren zu fühlen.
Diese Änderung verbesserte die Benutzererfahrung ohne kostspielige architektonische Änderungen.
Was können wir aus dieser Situation lernen? Manchmal sind die naheliegendsten Lösungen nicht unbedingt die besten. Es ist nicht nur wichtig, Engpässe zu erkennen, sondern auch zu verstehen, was die Nutzer wirklich betrifft. Oft können die Optimierung der Benutzererfahrung und die Anpassung der Arbeitsabläufe das Problem genauso effektiv lösen wie technische Änderungen.
Diese Vorgehensweise hilft dabei, potenzielle Schwächen und Skalierbarkeitsengpässe bei starker Nutzung aufzudecken, bevor der reale Datenverkehr beeinträchtigt wird. Zunächst einmal ist es wichtig zu definieren, was „starke Nutzung“ eigentlich bedeutet für Ihr Unternehmen. Dazu gehört die Festlegung klarer Maßstäbe.
In einem Projekt, an dem wir gearbeitet haben, haben wir beispielsweise mit einer Nutzerbasis von 10.000 begonnen. Wir wussten, dass das Unternehmen in diesem Jahr sechs neue Kunden gewinnen wollte, was rund 50.000 zusätzliche Nutzer einbringen würde. Mit einer solchen Schätzung waren wir in der Lage, anhand dieser Zielzahl zu testen — und sie sogar noch weiter zu steigern. Wir überprüften auch, was bei 100.000 passieren würde, um uns auf ein unerwartetes Wachstum vorzubereiten.
Ein weiterer wichtiger Aspekt ist die Analyse der Nutzungsmuster der Anwendung, was mit der zuvor erwähnten automatischen Skalierung zusammenhängt. In Polen beispielsweise skalieren Banken am 10. eines jeden Monats automatisch, weil sie wissen, dass sich die Leute massenhaft einloggen, um zu überprüfen, ob ihre Gehälter eingegangen sind, oder um Rechnungen zu bezahlen. Sie können die Ressourcen auch an die Tageszeit oder die Region anpassen.
Durch die Untersuchung des Nutzerverhaltens können wir Spitzennutzungszeiten vorhersehen und die Ressourcenzuweisung entsprechend optimieren.
Effizienz beim Datenbankdesign beginnt mit der grundlegenden Frage, den richtigen Datenbanktyp für Ihre individuellen Bedürfnisse auszuwählen. Wenn auf Ihrer Website beispielsweise häufig Suchleisten verwendet werden, könnten Sie auf NoQSL setzen oder Lesemodelle/materialisierte Ansichten implementieren, um „vorgefertigte“ Antworten zu liefern, anstatt die Zahlen für jede Anfrage zu berechnen. Wir empfehlen, komplexe Joins oder umfangreiche Lese-/Schreiboperationen sparsam zu verwenden, da sie die Leistung bei steigendem Datenvolumen beeinträchtigen können.
Komplexe Verknüpfungen kommen ins Spiel, wenn wir schnell Fragen beantworten müssen wie:“Wie viele Bestellungen hat ein bestimmter Benutzer aufgegeben?“. Wenn diese Abfrage jedoch wiederholt ausgeführt wird — möglicherweise Tausende oder sogar Millionen Mal am Tag — wird es ineffizient, sie jedes Mal von Grund auf neu zu berechnen.
Stattdessen können wir den Wert vorab berechnen und speichern, anstatt komplexe Berechnungen und Datenabrufe bei Bedarf durchzuführen.
Hier funktioniert das Caching gut, um solche sich wiederholenden Anfragen zu verarbeiten. Ein gutes Beispiel könnten die Benzinpreise auf der Website einer Tankstelle sein — sie könnte nur einmal täglich mit neuen Daten aktualisiert werden, um den neuen Marktpreis anzuzeigen. Anstatt Anfragen zu verarbeiten und für jeden Benutzer dieselben Daten bereitzustellen, zeigen Sie denselben Wert an, sodass Ihre Datenbank nicht belastet wird.
Wenn Sie der Meinung sind, dass ein modularer Monolith die richtige Wahl ist, um Ihre skalierbare Softwarearchitektur zu unterstützen, dann lesen Sie unseren Artikel, in dem die Verwendung von beschrieben wird Microservices und Monolithen (oder eine Mischung aus beiden Ansätzen) im Detail.
Our promise
Every year, Brainhub helps 750,000+ founders, leaders and software engineers make smart tech decisions. We earn that trust by openly sharing our insights based on practical software engineering experience.
Authors
Read next
Popular this month