Kapitel 4. Dienste und Daten

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Wenn du deine Anwendung auf eine servicebasierte Architektur umstellst, ist es besonders wichtig, dass du darauf achtest, wo du Daten und Zustände innerhalb deiner Anwendung speicherst.

Zustandslose Dienste - Dienste ohne Daten

Zustandslose Dienste sind Dienste, die keine eigenen Daten und keinen eigenen Zustand verwalten. Der gesamte Zustand und alle Daten, die der Dienst benötigt, um seine Aktionen auszuführen, werden in der an den Dienst gesendeten Anfrage übergeben (oder referenziert).

Zustandslose Dienste bieten einen großen Vorteil bei der Skalierung. Da sie zustandslos sind, ist es in der Regel ein Leichtes, zusätzliche Serverkapazitäten zu einem Dienst hinzuzufügen, um ihn vertikal und horizontal zu skalieren. Wenn dein Dienst keinen Zustand beibehält, hast du maximale Flexibilität, wie und wann du deinen Dienst skalieren kannst.

Außerdem werden bestimmte Caching-Techniken auf dem Frontend des Dienstes möglich, wenn der Cache sich nicht um den Zustand des Dienstes kümmern muss. Durch dieses Caching kannst du höhere Skalierungsanforderungen mit weniger Ressourcen bewältigen.

Natürlich können nicht alle Dienste zustandslos gemacht werden, aber für die Dienste, die zustandslos sein können, ist das ein großer Vorteil für die Skalierbarkeit.

Zustandsbezogene Dienste - Dienste mit Daten

Wenn du Daten speichern musst, liegt es angesichts der Ausführungen im vorangegangenen Abschnitt nahe, sie in so wenigen Diensten und Systemen wie möglich zu speichern. Es könnte sinnvoll sein, alle deine Daten nahe beieinander zu halten, um den Platzbedarf der Dienste zu reduzieren, die deine Daten kennen und verwalten müssen.

Nichts könnte weiter von der Wahrheit entfernt sein.

Stattdessen solltest du deine Daten so weit wie möglich lokalisieren. Lasse die Dienste und Datenspeicher nur die Daten verwalten, die sie für die Erfüllung ihrer Aufgaben benötigen. Andere Daten sollten auf anderen Servern und in anderen Datenspeichern gespeichert werden, näher bei den Diensten, die diese Daten benötigen.

Die Lokalisierung von Daten auf diese Weise bietet ein paar Vorteile:

Geringere Größe der einzelnen Datensätze

Da deine Daten auf verschiedene Datensätze aufgeteilt werden, ist jeder Datensatz kleiner. Ein kleinerer Datensatz bedeutet weniger Interaktion mit den Daten, was die Skalierbarkeit der Datenbank erleichtert. Das nennt man funktionale Partitionierung. Du teilst deine Daten nach funktionalen Gesichtspunkten auf, nicht nach der Größe des Datensatzes.

Lokalisierter Zugang

Wenn du auf Daten in einer Datenbank oder einem Datenspeicher zugreifst, greifst du häufig auf alle Daten in einem bestimmten Datensatz oder einer Reihe von Datensätzen zu. Oft werden viele dieser Daten für eine bestimmte Interaktion nicht benötigt. Indem du mehrere reduzierte Datensätze verwendest, reduzierst du die Menge nicht benötigter Daten in deinen Abfragen.

Optimierte Zugriffsmethoden

Indem du deine Daten in verschiedene Datensätze aufteilst, kannst du den für jeden Datensatz geeigneten Datenspeichertyp optimieren. Braucht ein bestimmter Datensatz einen relationalen Datenspeicher? Oder ist ein einfacher Schlüssel/Wert-Datenspeicher ausreichend?

Wenn du deine Daten den Diensten zuordnest, die die Daten nutzen, entsteht eine skalierbarere Lösung und eine leichter zu verwaltende Architektur, die es dir ermöglicht, deine Datenanforderungen leichter zu erweitern, wenn deine Anwendung wächst.

Datenpartitionierung

Datenpartitionierung kann viele Dinge bedeuten. In diesem Zusammenhang bedeutet es die Aufteilung von Daten eines bestimmten Typs in Segmente auf der Grundlage eines Schlüssels oder einer Kennung innerhalb der Daten. Oft werden mehrere Datenbanken genutzt, um größere Datenmengen oder Daten, auf die häufiger zugegriffen wird, als eine einzelne Datenbank verarbeiten kann, zu speichern.

Es gibt noch andere Arten der Datenpartitionierung (z. B. die oben erwähnte funktionale Partitionierung); in diesem Abschnitt konzentrieren wir uns jedoch auf das schlüsselbasierte Partitionierungsschema.

Ein einfaches Beispiel für eine Datenpartitionierung ist die Aufteilung aller Daten für eine Anwendung nach Konten, so dass sich alle Daten für Konten, deren Name mit A-D beginnt, in einer Datenbank befinden, alle Daten für Konten, deren Name mit E-K beginnt, in einer anderen Datenbank und so weiter (siehe Abbildung 4-1).1 Dies ist ein sehr einfaches Beispiel, aber die Datenpartitionierung wird von Anwendungsentwicklern häufig verwendet, um die Anzahl der Benutzer, die gleichzeitig auf die Anwendung zugreifen können, sowie die Größe des Datensatzes selbst drastisch zu erhöhen.

Example of data partitioning by account name
Abbildung 4-1. Beispiel für eine Datenpartitionierung nach Kontonamen

Generell solltest du die Partitionierung von Daten wann immer möglich vermeiden. Warum? Nun, wenn du Daten auf diese Weise partitionierst, stößt du auf mehrere potenzielle Probleme:

Komplexität der Anwendung

Du erhöhst die Komplexität deiner Anwendung , weil du jetzt erst feststellen musst, wo deine Daten gespeichert sind, bevor du sie tatsächlich abrufen kannst.

Partitionsübergreifende Abfragen

Du entfernst die Möglichkeit, Daten über mehrere Partitionen hinweg abzufragen. Dies ist besonders bei Abfragen zur Geschäftsanalyse nützlich.

Schiefe Partitionsnutzung

Die sorgfältige Wahl des Partitionsschlüssels ist entscheidend. Wenn du den falschen Schlüssel wählst, kannst du die Nutzung deiner Datenbankpartitionen verzerren, so dass einige Partitionen heißer und andere kälter laufen, was die Effektivität der Partitionierung verringert und die Verwaltung und Wartung deiner Datenbank erschwert. Dies wird in Abbildung 4-2 veranschaulicht.

Repartitionierung

Gelegentlich ist eine Repartitionierung notwendig , um den Datenverkehr zwischen den Partitionen effektiv auszugleichen. Je nach gewähltem Schlüssel und der Art und Größe des Datensatzes kann sich dies als äußerst schwierige Aufgabe erweisen, eine extrem gefährliche Aufgabe (Datenmigration) und in manchen Fällen sogar eine fast unmögliche Aufgabe.

Im Allgemeinen ist der Kontoname oder die Konto-ID fast immer ein schlechter Partitionsschlüssel (dennoch ist er einer der am häufigsten gewählten Schlüssel). Das liegt daran, dass sich die Größe eines einzelnen Kontos im Laufe seiner Lebensdauer ändern kann. Sieh dir Abbildung 4-2 an. Ein Konto fängt vielleicht klein an und passt daher leicht in eine Partition mit einer großen Anzahl kleiner Konten. Wenn es jedoch im Laufe der Zeit wächst, kann die einzelne Partition bald nicht mehr in der Lage sein, die gesamte Last angemessen zu bewältigen, und du musst die Partition neu aufteilen, um die Kontonutzung besser auszugleichen. Wenn ein einzelnes Konto zu groß wird, kann es sogar größer werden, als es in eine einzelne Partition passt, was dazu führt, dass dein gesamtes Partitionierungsschema fehlschlägt, weil kein Rebalancing dieses Problem lösen kann.

Example of accounts overrunning data partitions
Abbildung 4-2. Beispiel für die Überschreitung von Datenpartitionen durch Konten

Ein besserer Partitionsschlüssel wäre einer, der zu möglichst gleich großen Partitionen führt. Das Wachstum der Partitionen sollte so unabhängig und einheitlich wie möglich sein, wie in Abbildung 4-3 dargestellt. Wenn eine Neupartitionierung erforderlich ist, dann nur, weil alle Partitionen gleichmäßig gewachsen und zu groß für die Datenbank geworden sind.

Ein potenziell nützliches Partitionierungsschema besteht darin, einen Schlüssel zu verwenden, der eine große Anzahl kleiner Elemente erzeugt. Anschließend ordnest du diese kleinen Partitionen einer größeren partitionierten Datenbank zu. Wenn dann eine Neupartitionierung erforderlich ist, kannst du die Zuordnung einfach aktualisieren und einzelne kleine Elemente in neue Partitionen verschieben, ohne dass das gesamte System neu partitioniert werden muss. Die Auswahl und Verwendung von geeigneten Partitionsschlüsseln ist eine Kunst für sich.

Example of consistently sized partitioned elements
Abbildung 4-3. Beispiel für einheitlich große aufgeteilte Elemente

Rechtzeitiger Umgang mit Wachstumsschmerzen

Bei den meisten modernen Anwendungen wachsen die Anforderungen an den Datenverkehr, der Umfang und die Komplexität der Anwendungen selbst sowie die Anzahl der Mitarbeiter, die an den Anwendungen arbeiten. Oft ignorieren wir diese Wachstumsschmerzen und warten, bis der Schmerz eine bestimmte Schwelle erreicht hat, bevor wir versuchen, ihn in den Griff zu bekommen. Zu diesem Zeitpunkt ist es jedoch meist zu spät. Der Schmerz hat ein ernsthaftes Ausmaß erreicht, und viele einfache Techniken, die ihn lindern könnten, stehen dir nicht mehr zur Verfügung.

Wenn wir bei der Architektur unserer Anwendung nicht bedenken, wie sie wachsen kann, bevor wir sie skalieren, werden wir uns in Architekturentscheidungen verstricken, die uns daran hindern können, sie so zu skalieren, wie es unser Geschäft erfordert.

Stattdessen solltest du bei der Entwicklung und Gestaltung deiner neuen Anwendung und bei Änderungen an deinen bestehenden Anwendungen bedenken, wie sich diese Änderungen auf mögliche Skalierungen in der Zukunft auswirken werden. Wie viel Spielraum für Skalierung hast du eingeplant? Wo ist die erste Skalierungsgrenze, auf die du stoßen wirst? Was passiert, wenn du diese Grenze erreichst? Wie kannst du darauf reagieren und das Hindernis beseitigen, ohne die Anwendung grundlegend umzugestalten?

Wenn du darüber nachdenkst, wie deine Anwendung wachsen wird, lange bevor sie diese schmerzhaften Ausmaße annimmt, kannst du vielen Problemen zuvorkommen und deine Anwendungen so entwickeln und verbessern, dass sie diese Wachstumsschmerzen sicher bewältigen können.

1 Ein wahrscheinlicherer Mechanismus für eine kontobasierte Partitionierung wäre die Partitionierung nach einer Kontokennung und nicht nach dem Kontonamen. Die Verwendung des Kontonamens macht dieses Beispiel jedoch einfacher zu verstehen.

Get Architecting for Scale, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.