Sharding-Muster

Einen Datenspeicher in einen Satz horizontaler Partitionen oder Shards unterteilen Dieser Ansatz kann die Skalierbarkeit verbessern, wenn Sie große Datenmengen speichern und darauf zugreifen.

Kontext und Problem

Ein Datenspeicher auf einem einzelnen Server hat die folgenden Einschränkungen:

  • Speicherplatz: Ein Datenspeicher für eine große Cloudanwendung kann ein großes Datenvolumen enthalten, das im Laufe der Zeit wächst. Ein Server stellt eine begrenzte Menge an Datenträgerspeicher bereit, und Sie können vorhandene Datenträger durch größere ersetzen oder weitere Datenträger hinzufügen, wenn Datenvolumes wachsen. Das System erreicht schließlich ein Limit, bei dem Sie die Speicherkapazität auf einem einzelnen Server nicht erhöhen können.

  • Computerressourcen: Eine Cloudanwendung muss eine große Anzahl gleichzeitiger Benutzer unterstützen, die abfragen für den Datenspeicher ausführen. Ein einzelner Server bietet möglicherweise nicht genügend Rechenleistung für diese Last, was zu erweiterten Reaktionszeiten und Timeouts führt. Sie können Arbeitsspeicher- oder Upgradeprozessoren hinzufügen, aber das System erreicht ein Limit, in dem Sie die Computeressourcen nicht weiter erhöhen können.

  • Netzwerkbandbreite: Die Häufigkeit, mit der ein einzelner Server Anforderungen empfangen und Antworten senden kann, beschränkt die Leistung des Datenspeichers. Das Volumen des Netzwerkdatenverkehrs kann die Kapazität der Netzwerkverbindung überschreiten, was zu fehlgeschlagenen Anforderungen führt.

  • Geografie: Rechtliche, Compliance- oder Leistungsanforderungen erfordern möglicherweise, dass Sie Benutzerdaten in derselben geografischen Region wie die Benutzer speichern. Wenn Sich Benutzer über Länder/Regionen erstrecken, können Sie möglicherweise nicht alle Daten der Anwendung in einem einzigen Datenspeicher speichern.

Um diese Einschränkungen vorübergehend zu verschieben, können Sie vertikal skalieren, indem Sie Festplattenkapazität, Verarbeitungsleistung, Arbeitsspeicher und Netzwerkverbindungen hinzufügen. Eine Cloudanwendung, die eine große Anzahl von Benutzern und hohen Datenmengen unterstützen muss, muss horizontal skaliert werden.

Lösung

Den Datenspeicher in horizontale Partitionen oder Shards unterteilen Jeder Shard weist dasselbe Schema auf, enthält jedoch eine eigene separate Teilmenge der Daten. Jeder Shard ist ein vollständiger Datenspeicher, der Daten für viele Entitäten unterschiedlicher Typen enthalten kann. Ein Shard wird auf einem Server ausgeführt, der als Speicherknoten fungiert.

Dieses Muster hat folgende Vorteile:

  • Sie können das System skalieren, indem Sie weitere Shards auf zusätzlichen Speicherknoten hinzufügen.

  • Ein System kann vorgefertigte Hardware anstelle spezieller und teurer Computer für jeden Speicherknoten verwenden.

  • Sie können Konflikte reduzieren und die Leistung verbessern, indem Sie die Workload auf mehrere Shards verteilen.

  • In der Cloud können Shards physisch in der Nähe der Benutzer sein, die auf die Daten zugreifen.

Wenn Sie einen Datenspeicher in Shards unterteilen, entscheiden Sie, welche Daten in den einzelnen Shards platziert werden sollen. Jeder Shard enthält in der Regel Elemente, die nach einem oder mehreren Datenattributen gruppiert sind. Diese Attribute bilden den Shardschlüssel, manchmal auch als Partitionsschlüssel bezeichnet.

Durch das Sharding werden die Daten physisch angeordnet. Wenn eine Anwendung Daten speichert und abruft, wird sie durch die Sharding-Logik an den entsprechenden Shard geleitet. Sie können diese Logik im Datenzugriffscode der Anwendung oder im Datenspeichersystem implementieren, wenn sie Sharding transparent unterstützt.

Das Abstrahieren der physischen Position der Daten in der Shardinglogik ermöglicht die Kontrolle darüber, welche Shards welche Daten enthalten. Sie können auch Daten zwischen Shards migrieren, ohne die Anwendungsgeschäftslogik zu ändern, wenn Sie Daten neu verteilen müssen, z. B. wenn Shards unausgewogen werden. Der Kompromiss ist der zusätzliche Datenzugriffsaufwand, um den Standort jedes Datenelements während des Abrufs zu ermitteln.

Shard-Schlüsselauswahl

Der Shardschlüssel ist die wichtigste Entwurfsentscheidung in einem shardierten System. Wenn Sie einen Shardschlüssel ändern möchten, nachdem Sie ihn ausgewählt haben, müssen Sie in der Regel alle Daten zu einem neuen Shard-Layout migrieren, bei dem es sich um einen kostspieligen und riskanten Vorgang in einem Livesystem handelt. Treffen Sie diese Entscheidung sorgfältig, bevor Sie Code schreiben.

Ein effektiver Shardschlüssel ist unveränderlich, hat hohe Kardinalität, verteilt Daten und lädt gleichmäßig und richtet sich an Ihre dominanten Abfragemuster, sodass die meisten Anforderungen gegen einen einzelnen Shard aufgelöst werden. Vermeiden Sie monoton steigende Werte (autoincrement integers and sequential timestamps), Attribute mit niedriger Kardinalität (Booleans und kleine Enumerationssätze) und veränderliche Attribute, die sich häufig ändern. Diese Attribute führen zu Hotspots oder kostspieligem Datentransfer zwischen Shards.

Wenn kein einzelnes Attribut diese Kriterien erfüllt, definieren Sie einen zusammengesetzten Shardschlüssel, indem Sie zwei oder mehr Attribute kombinieren. Wenn Abfragen Daten nach Attributen abrufen müssen, die nicht Teil des Shardschlüssels sind, verwenden Sie ein Muster wie das Indextabellenmuster , um sekundäre Nachschlagevorgänge bereitzustellen.

Weitere Informationen zum Auswählen von Partitionsschlüsseln in Azure-Diensten finden Sie unter Datenpartitionierungsleitfaden und Datenpartitionierungsstrategien.

Sharding-Strategien

Verwenden Sie eine der folgenden Strategien, wenn Sie den Shardschlüssel auswählen und entscheiden, wie Daten über Shards verteilt werden sollen. Sie benötigen keine 1:1-Korrespondenz zwischen Shards und den Servern, auf denen sie gehostet werden. Ein einzelner Server kann mehrere Shards hosten.

Nachschlage-Sharding-Strategie

In der Nachschlagestrategie, auch als verzeichnisbasierte Strategie bezeichnet, implementiert die Shardinglogik eine Zuordnung, die eine Datenanforderung an die Shard weitergibt, die diese Daten enthält, indem der Shardschlüssel verwendet wird. In einer mehrinstanzenfähigen Anwendung können Sie alle Daten für einen Mandanten zusammen in einem Shard speichern, indem Sie die Mandanten-ID als Shardschlüssel verwenden. Mehrere Mandanten teilen möglicherweise dieselbe Shard, aber die Daten für einen einzelnen Mandanten werden nicht über mehrere Shards verteilt. Das folgende Diagramm zeigt das Sharding von Mandantendaten auf Basis von Mandanten-IDs.

Diagramm, das Mandantendaten basierend auf Mandanten-IDs zeigt

Die Zuordnung zwischen Shardschlüsselwerten und physischem Speicher kann direkt sein, wobei jeder Shard-Schlüsselwert einer physischen Partition zugeordnet ist. Eine flexiblere Technik ist die virtuelle Partitionierung, bei der Shardschlüsselwerte virtuellen Shards zugeordnet sind, und das System diese virtuellen Shards dann weniger physischen Partitionen zuordnet. Eine Anwendung sucht Daten mithilfe eines Shardschlüsselwerts, der auf einen virtuellen Shard verweist, und das System ordnet virtuelle Shards transparent physischen Partitionen zu. Die Zuordnung zwischen einem virtuellen Shard und einer physischen Partition kann sich ändern, ohne dass Anwendungscodeänderungen erforderlich sind.

Bereichsbasierte Shardingstrategie

Die bereichsbasierte Strategie gruppiert verwandte Elemente in derselben Shard und ordnet sie nach sequenziellem Shardschlüssel an. Diese Strategie unterstützt Anwendungen, die häufig Gruppen von Elementen mithilfe von Bereichsabfragen abrufen. Bereichsabfragen geben einen Satz von Datenelementen für einen Shardschlüssel zurück, der in einen bestimmten Bereich fällt.

Wenn eine Anwendung beispielsweise regelmäßig alle Bestellungen finden muss, die in einem bestimmten Monat getätigt wurden, können Sie die Daten schneller abrufen, wenn Sie alle Bestellungen für einen Monat in Datums- und Uhrzeitreihenfolge in derselben Shard speichern. Wenn Sie jede Bestellung in einem anderen Shard speichern, muss die Anwendung sie einzeln abrufen, indem sie viele Punktabfragen ausführt. Das folgende Diagramm zeigt sequenzielle Sätze oder Bereiche von Daten, die in Shards gespeichert sind.

Diagramm, das sequenzielle Sätze oder Bereiche von Daten zeigt, die in Shards gespeichert sind.

In diesem Beispiel ist der Shardschlüssel ein zusammengesetzter Schlüssel, der den Bestellmonat als das wichtigste Element enthält, gefolgt von dem Bestelltag und der Uhrzeit. Neubestellungen werden natürlich so sortiert, wie sie erstellt und zu einer Shard hinzugefügt werden.

Einige Datenspeicher unterstützen zweiteilige Shardschlüssel. Ein Partitionsschlüssel identifiziert den Shard, und ein Zeilenschlüssel identifiziert ein Element innerhalb der Shard eindeutig. Der Shard speichert Daten in der Regel in der Zeilenschlüsselreihenfolge. Für Elemente, die Bereichsabfragen benötigen und gruppiert werden müssen, können Sie einen Shardschlüssel verwenden, der denselben Wert für den Partitionsschlüssel aufweist, aber einen eindeutigen Wert für den Zeilenschlüssel.

Hashbasierte sharding-Strategie

Die Hash-basierte Strategie reduziert die Wahrscheinlichkeit von Hotspots, die Shards sind, die eine unverhältnismäßige Menge an Last erhalten. Diese Strategie verteilt Daten über Shards hinweg, um die Größe der einzelnen Shards und die durchschnittliche Last, auf die jeder Shard trifft, auszugleichen. Die Sharding-Logik berechnet den Shard für die Speicherung eines Elements auf Grundlage eines Hashs von mindestens einem Attribut der Daten. Die ausgewählte Hashfunktion sollte Daten gleichmäßig über die Shards verteilen. Das folgende Diagramm zeigt die Aufteilung von Mandantendaten basierend auf dem Hash der Mandanten-IDs.

Diagramm, das das Sharding von Mandantendaten basierend auf einem Hash von Mandanten-IDs zeigt.

Um den Vorteil der Hashstrategie gegenüber anderen Shardingstrategien zu verstehen, überlegen Sie, wie eine mehrinstanzenfähige Anwendung, die neue Mandanten sequenziell registriert, die Mandanten Shards im Datenspeicher zuweisen kann. Wenn Sie die Bereichsstrategie verwenden, werden die Daten für Mandanten 1 bis n in Shard A gespeichert, die Daten für Mandanten n+1 bis m werden in Shard B gespeichert, und spätere Mandantenbereiche werden aufeinander folgende Shards zugeordnet. Wenn die zuletzt registrierten Mandanten auch die aktivsten sind, finden die meisten Datenaktivitäten in einigen Shards statt, was zu Hotspots führen kann. Im Gegensatz dazu weist die Hashstrategie Mandanten auf der Grundlage eines Hashs ihrer Mandanten-ID Shards zu. Der Hash verteilt normalerweise sequenzielle Mandanten über verschiedene Shards und sorgt so für eine ausgeglichene Lastverteilung. Das vorherige Diagramm zeigt diesen Ansatz für Mandanten 55 und 56.

Geografische Aufteilung-Strategie

Die geografische Strategie teilt Daten basierend auf ihrem geografischen Ursprung oder der vorgesehenen Verbrauchsregion den Shards zu. In vielen Workloads werden Benutzer und die von ihnen generierten Daten in bestimmten Regionen konzentriert. Behördliche Anforderungen wie Datenhaltungsgesetze können erfordern, dass bestimmte Daten in einer bestimmten Gerichtsbarkeit verbleiben. Auch ohne regulatorische Faktoren reduziert das Platzieren von Daten nahe bei den Benutzern, die am häufigsten darauf zugreifen, die Netzwerklatenz für Lese- und Schreibvorgänge.

Diagramm, das Sharding-Daten basierend auf der Geographie der Anwendungsinstanz zeigt.

In dieser Strategie leiten Sie den Shard-Schlüssel von einem geografischen Attribut wie dem Land/der Region des Benutzers, der ursprünglichen Rechenzentrumsregion oder einem regionalen Mandantenbezeichner ab. Sie hosten jeden Shard in der Infrastruktur innerhalb dieser geografischen Grenze oder binden ihn daran.

Eine Anwendung, die Kunden in Nordamerika, Europa und Asia-Pacific bedient, kann beispielsweise dreiHardgruppen verwalten, eine Gruppe in jeder entsprechenden Azure-Region. Eine europäische Anwendung, die nur europäischen Nutzern dient, leitet eine Anforderung an die Europa-Shard weiter. Dieser Ansatz verringert die Latenz und erfüllt die Anforderungen an die Datenhaltung.

Das geografische Sharding birgt das Risiko einer ungleichmäßigen Datenverteilung. Wenn sich die meisten Ihrer Benutzer in einer Region befinden, trägt die Shard dieser Region einen unverhältnismäßigen Anteil der Last und des Speichers. Sie können Geo-Sharding mit einer anderen Strategie kombinieren, z. B. Hash oder Lookup, innerhalb jeder Region, um die Last gleichmäßig über mehrere Shards innerhalb desselben geografischen Gebiets zu verteilen.

Vorteile und Überlegungen für jede Strategie

Die vier Shardingstrategien haben die folgenden Vorteile und Überlegungen:

  • Die Nachschlagestrategie bietet mehr Kontrolle über die Shardkonfiguration. Virtuelle Shards verringern die Auswirkungen des Rebalancierens, da Sie neue physische Partitionen hinzufügen können, um die Arbeitslast auszugleichen. Sie können die Zuordnung zwischen einem virtuellen Shard und seinen physischen Partitionen ändern, ohne dass sich der Anwendungscode auswirkt. Das Nachschlagen vonHardstandorten erhöht den Aufwand.

  • Die Bereichsstrategie ist einfach zu implementieren und funktioniert gut mit Bereichsabfragen. Bereichsabfragen können mehrere Datenelemente aus einem einzelnen Shard in einem Vorgang abrufen. Die Datenverwaltung ist einfacher. Sie können z. B. Aktualisierungen pro Zeitzone basierend auf lokalen Lademustern planen, wenn Benutzer in derselben Region einen Shard teilen. Diese Strategie verteilt die Last jedoch nicht gleichmäßig über die Shards. Rebalancing ist schwierig und verringert möglicherweise keine ungleiche Last, wenn sich die meisten Aktivitäten auf benachbarte Shard-Schlüssel konzentrieren.

  • Die Hashstrategie bietet eine bessere Chance auf gleichmäßige Daten und Lastenverteilung. Sie können Anforderungen direkt weiterleiten, indem Sie die Hashfunktion verwenden, ohne eine Karte beizubehalten. Das Berechnen des Hashs führt zu einem zusätzlichen Aufwand. Das Rebalancing ist ohne konsistentes Hashing schwierig.

  • Die geografische Strategie erfüllt die Anforderungen an die Datenhaltung und Souveränität, die andere Strategien nicht inhärent erfüllen. Die Lese- und Schreiblatenz wird reduziert, wenn Benutzer auf Daten in ihrer Region zugreifen. Geografisches Sharding kann jedoch erhebliche Daten- und Lastungleichgewichte erzeugen, wenn Benutzerpopulationen nicht gleichmäßig auf Regionen verteilt sind. Abfragen, die Regionen umfassen, z. B. globale Berichte, müssen Daten aus allen geografischen Shards abrufen und eine höhere Latenz verursachen. Kombinieren Sie geografisches Sharding mit einer anderen Strategie innerhalb jeder Region, wenn Sie sowohl Compliance als auch gleichmäßige Lastverteilung benötigen.

Die meisten sharding-Systeme implementieren einen dieser Ansätze, aber Sie sollten auch die Geschäftsanforderungen Ihrer Anwendung und deren Datennutzungsmuster berücksichtigen. Zum Beispiel in einer mandantenfähigen Anwendung:

  • Sie können Daten je nach Arbeitslast partitionieren. Trennen Sie die Daten von Mandanten mit hoher Volatilität in separaten Shards, um die Datenzugriffsgeschwindigkeit für andere Mandanten zu verbessern.

  • Sie können Daten basierend auf dem Standort des Mandanten aufteilen. Nehmen Sie Mandantendaten in einer bestimmten geografischen Region während der regionalen Schwachlastzeiten offline, während Mandantendaten in anderen Regionen während ihrer Geschäftszeiten online bleiben.

  • Weisen Sie hochwertigen Mietern ihre eigenen dedizierten, leicht belasteten Shards zu. Niedrigwertige Mandanten können dichtere Shard-Packungen teilen.

  • Speichern Sie Daten für Mandanten, die eine starke Datenisolation und Datenschutz auf separaten Servern benötigen.

Skalierungs- und Datenbewegungsvorgänge für jede Strategie

Jede Shardingstrategie bietet unterschiedliche Funktionen und Komplexitätsstufen, um das Hoch- und Herunterskalieren, die Datenverschiebung und die Zustandserhaltung zu verwalten.

  • Die Nachschlagestrategie ermöglicht Skalierungs- und Datenbewegungsvorgänge auf Benutzerebene, entweder online oder offline. So verschieben Sie Daten:

    1. Halten Sie einige oder alle Benutzeraktivitäten in der Regel während der schwachen Zeiten an.

    2. Verschieben Sie die Daten in die neue virtuelle Partition oder physische shard.

    3. Aktualisieren Sie die Zuordnungen.

    4. Ungültigmachen oder Aktualisieren jeglicher Caches, die diese Daten enthalten.

    5. Fortsetzen der Benutzeraktivität.

    Sie können diesen Vorgang häufig zentral verwalten. Für die Suchstrategie muss der Systemzustand hochgradig zwischenspeicherbar und replika-freundlich sein.

  • Die Bereichsstrategie schränkt Skalierungs- und Datenverschiebungsvorgänge ein, da Sie Daten über Shards teilen und zusammenführen müssen, in der Regel, während ein Teil oder der gesamte Datenspeicher offline ist. Wenn Sie Daten verschieben, um Shards neu auszubalancieren, vermeiden Sie möglicherweise keine ungleiche Belastung, wenn sich die meisten Aktivitäten auf benachbarte Shardschlüssel oder Datenbezeichner innerhalb desselben Bereichs konzentrieren. Die Bereichsstrategie könnte auch erfordern, den Zustand zu verwenden, um Bereiche physischen Partitionen zuzuordnen.

  • Die Hashstrategie erschwert Skalierungs- und Datenverschiebungsvorgänge. Die Partitionsschlüssel sind Hashes der Shardschlüssel oder Datenbezeichner. Mit einer Standard-Hashfunktion wie hash(key) mod N führt das Hinzufügen oder Entfernen eines Shards dazu, dass die meisten Schlüssel neu zugewiesen werden und eine umfangreiche Datenmigration ausgelöst wird. Durch das Anordnen des Hashbereichs wird diese Auswirkung durch konsistentes Hashing reduziert, sodass nur ein kleiner Teil der Schlüssel verschoben wird, wenn sich die Shardanzahl ändert. Die Hashstrategie erfordert keine Wartung eines separaten Zuordnungszustands.

  • Die geografische Strategie verknüpft skalierungsvorgänge direkt mit der regionalen Infrastrukturbereitstellung. Durch das Hinzufügen von Kapazitäten in einer Region wird die Last in einer anderen Region nicht erleichtert. Regulatorische Anforderungen, die geografisches Sharding vorschreiben, können auch die Datenbewegung über geografische Grenzen einschränken. In jeder Region verwendet die Skalierung die sekundäre Strategie, die Daten über die Shards dieser Region verteilt.

Probleme und Überlegungen

Berücksichtigen Sie die folgenden Punkte, wenn Sie sich für die Implementierung dieses Musters entscheiden:

  • Verwenden Sie Sharding komplementär zu anderen Formen der Partitionierung, z. B. vertikale Partitionierung und funktionale Partitionierung. Ein einzelner Shard kann z. B. vertikal partitionierte Entitäten enthalten, und Sie können eine funktionale Partition als mehrere Shards implementieren. Weitere Informationen finden Sie unter Horizontale, vertikale und funktionale Datenpartitionierung.

  • Halten Sie Shards ausgeglichen, damit sie alle ein ähnliches Eingabe-/Ausgabevolumen (E/A) verarbeiten können. Daten-Ungleichgewicht entsteht im Laufe der Zeit, wenn Datensätze eingefügt und gelöscht werden, was zu Hotspots führt. Planen Sie eine regelmäßige Neuausbalancierung.

    Das Rebalancing verschiebt Daten zwischen Shards und verursacht häufig Ausfallzeiten oder verringerten Durchsatz. Um weniger häufig ausgleichen zu können, verwenden Sie virtuelle Partitionen. Zuordnen vieler logischer Partitionen zu weniger physischen Shards. Wenn ein Shard überladen ist, verteilen Sie ihre virtuellen Partitionen auf neue physische Shards, ohne das gesamte Dataset erneut zu implementieren. Azure Cosmos DB verwendet diesen Ansatz, um das Partitionsschema von der physischen Infrastruktur zu entkoppeln.

    Bevorzugen Sie viele kleine Scherben vor wenigen großen. Kleinere Shards migrieren schneller, ausgleichen die Last gleichmäßiger und bieten mehr Flexibilität für die Datenumverteilung.

  • Verwenden Sie stabile Daten für den Shard-Schlüssel. Wenn sich der Shardschlüssel ändert, müssen Sie möglicherweise das entsprechende Datenelement zwischen Shards verschieben, wodurch der Aktualisierungsvorgangsaufwand erhöht wird. Vermeiden Sie, den Shardschlüssel auf potenziell veränderliche Informationen zu basieren. Wählen Sie Attribute aus, die unveränderlich sind oder natürlich einen Schlüssel bilden.

  • Stellen Sie sicher, dass Shard-Schlüssel eindeutig sind. Zum Beispiel sollten Sie vermeiden, Felder mit automatischer Inkrementierung als Shard-Schlüssel zu verwenden. In einigen Systemen können autoinkrementierte Felder nicht über Shards hinweg koordiniert werden, was dazu führen kann, dass Elemente in unterschiedlichen Shards denselben Shardschlüssel aufweisen.

    Hinweis

    Autoinkrementierte Werte in anderen Feldern, die keine Shardschlüssel sind, können auch Probleme verursachen. Wenn Sie beispielsweise autoinkrementierte Felder verwenden, um eindeutige IDs zu generieren, werden möglicherweise zwei verschiedene Elemente in unterschiedlichen Shards dieselbe ID zugewiesen.

  • Teilen Sie die Daten in Shards auf, um die am häufigsten ausgeführten Abfragen zu optimieren. Möglicherweise können Sie keinen Shardschlüssel entwerfen, der den Anforderungen jeder Abfrage mit den Daten entspricht. Erstellen Sie bei Bedarf sekundäre Indextabellen, um Abfragen zu unterstützen, die Daten nach Attributen abrufen, die nicht Teil des Shardschlüssels sind. Weitere Informationen finden Sie unter Indextabellenmuster.

  • Entwerfen Sie Ihren Shardschlüssel und Das Datenmodell so, dass die meisten Vorgänge auf einen einzelnen Shard festgelegt sind. Abfragen, die nur auf einen einzelnen Shard zugreifen, sind effizienter als Abfragen, die Daten aus mehreren Shards abrufen. Denormalisieren Sie Ihre Daten, um verwandte Entitäten, wie Kunden und deren Bestellungen, die häufig zusammen abgefragt werden, im selben Shard zu organisieren, um die Anzahl separater Abfragen zu verringern.

    Quershardabfragen fügen Latenz, Ressourcenverbrauch und Komplexität hinzu. Wenn eine Anwendung Daten aus mehreren Shards abrufen muss, verwenden Sie parallele Fanoutabfragen, die gleichzeitig für jeden Shard ausgeführt werden, und aggregieren Sie die Ergebnisse. Selbst bei Parallelität bestimmt der langsamste Shard die Gesamtlatenz.

    Tipp

    Wenn eine Entität in einem Shard auf eine Entität in einem anderen Shard verweist, schließen Sie den Shardschlüssel für die zweite Entität als Teil des Schemas für die erste Entität ein. Dieser Ansatz kann die Leistung von Abfragen verbessern, die auf verwandte Daten über Shards verweisen.

  • Überdenken Sie Ihren Shard-Schlüssel oder ob Sharding Ihren Anforderungen entspricht, wenn Ihre Arbeitslast eine starke transaktionale Integrität zwischen Shard-Grenzen erfordert. Cross-shard-Transaktionen stellen Herausforderungen dar. Verteilte Koordinationsprotokolle, wie z. B. das Zwei-Phasen-Commit, erhöhen die Latenz, führen Fehlermodi ein und reduzieren den Durchsatz. Die meisten shardisierten Systeme vermeiden verteilte Transaktionen und setzen stattdessen auf letztendliche Konsistenz. In diesem Modell aktualisiert sich jedes Shard unabhängig, wobei die Anwendung temporäre Inkonsistenzen bewältigt.

  • Stellen Sie sicher, dass die für jeden Shard-Speicherknoten verfügbaren Ressourcen die Skalierbarkeitsanforderungen hinsichtlich der Datengröße und des Durchsatzes bewältigen können. Weitere Informationen finden Sie unter Datenpartitionierungsstrategien.

  • Ziehen Sie in Betracht, Referenzdaten auf alle Shards zu replizieren. Wenn eine Abfrage für einen Shard auch auf statische oder langsam verschobene Daten verweist, fügen Sie diese Daten dem Shard hinzu. Die Anwendung kann dann alle Daten für die Abfrage abrufen, ohne einen Roundtrip zu einem separaten Datenspeicher vorzunehmen.

    Hinweis

    Wenn sich Referenzdaten in mehreren Shards ändern, muss das System diese Änderungen über alle Shards hinweg synchronisieren. Einige Inkonsistenzen können auftreten, während diese Synchronisierung ausgeführt wird. Entwerfen Sie Ihre Anwendungen so, dass diese Inkonsistenz toleriert wird.

  • Sharded-Systeme multiplizieren die Betriebsbelastung. Berücksichtigen Sie diese Bedenken:

    • Überwachung: Sie müssen Metriken und Protokolle über alle Shards hinweg aggregieren, um eine vollständige Ansicht der Systemintegrität zu erhalten.

    • Sicherung und Wiederherstellung: Sie müssen jede Shard unabhängig sichern und Wiederherstellen-Verfahren entwerfen, um die Konsistenz zwischen Shards zu gewährleisten. Eine Wiederherstellung zu einem bestimmten Zeitpunkt eines Shards kann zu Unstimmigkeiten mit anderen Shards führen.

    • Schemaänderungen: Sie müssen Änderungen der Datendefinitionssprache (Data Definition Language, DDL) für jeden Shard koordinieren.

    Sie können diese Aufgaben mithilfe von Skripts oder anderen Automatisierungslösungen implementieren.

  • Sie können Shards geolocieren, um ihre Daten in der Nähe der Anwendungsinstanzen zu platzieren, die sie verwenden. Dieser Ansatz kann die Leistung verbessern, erfordert jedoch eine zusätzliche Planung für Vorgänge, die auf mehrere Shards an verschiedenen Standorten zugreifen müssen.

Wann Sie dieses Muster verwenden sollten

Tipp

Bevor Sie eine benutzerdefinierte sharding-Ebene entwerfen, bestimmen Sie, welche Sharding-Verantwortlichkeiten Ihre Datenplattform bereits verarbeitet. Einige Dienste verwalten Sharding vollständig. Beispielsweise verteilt Azure Cosmos DB Daten über physische Partitionen, verarbeitet Splits und leitet Abfragen ohne Anwendungsbeteiligung weiter. Andere Dienste verwalten teilweise sharding. Azure SQL-Datenbank bietet z. B. flexible Datenbanktools für die Verwaltung von Shardkarten und datenabhängiges Routing, aber Sie entwerfen den Shardschlüssel und verwalten geteilte Vorgänge. Verwenden Sie das Sharding-Muster, wenn Sie die Sharding-Logik selbst erstellen und ausführen.

Verwenden Sie dieses Muster in folgenden Fällen:

  • Das Gesamte Datenvolume überschreitet die Speicherkapazität einer einzelnen Datenbankinstanz, und keine option für die vertikale Skalierung behebt den Ausfall.

  • Der Transaktionsdurchsatz oder die Abfragekonkurrenz überschreitet das, was eine einzelne Instanz leisten kann, und Lesereplikate beseitigen den Engpass nicht, da auch die Schreiblast hoch ist.

    Hinweis

    Sharding verbessert die Leistung und Skalierbarkeit eines Systems und kann auch die Verfügbarkeit verbessern. Ein Fehler in einer Partition verhindert nicht unbedingt, dass eine Anwendung auf Daten in anderen Partitionen zugreift. Und ein Operator kann Wartung oder Wiederherstellung einer Partition durchführen, ohne alle Daten nicht verfügbar zu machen. Weitere Informationen finden Sie unter Datenpartitionierungsleitfaden.

  • Regulatorische oder Compliance-Anforderungen fordern, dass bestimmte Datenuntergruppen in bestimmten geografischen Zuständigkeiten gespeichert werden und keine Bereitstellung in einer einzigen Region alle Anforderungen erfüllen kann.

  • Für unterschiedliche Mandanten oder Kundensegmente sind physische Datenisolation aus Sicherheits-, Leistungs- oder vertraglichen Gründen erforderlich.

    In Szenarien wie diesen wird das Shardingmuster manchmal über herkömmliche Datenspeicher hinaus angewendet. Beispielsweise könnte ein DNS-Zonenverwaltungssystem von Team, Umgebung oder Region abgeshardt werden, um den Strahlradius von DNS-Änderungen zu reduzieren und klare Besitzergrenzen festzulegen. In diesem Zusammenhang ist die primäre Motivation die operative Segmentierung und nicht skalierbarkeit. Weitere Informationen finden Sie unter Sharding private DNS-Zonen.

Sharding führt zu erheblicher und dauerhafter Komplexität in Ihre Datenarchitektur. Diese Komplexität wirkt sich auf Entwicklung, Vorgänge, Tests, Abfrageentwurf und Fehlerwiederherstellung für die Lebensdauer des Systems aus.

Dieses Muster ist möglicherweise nicht geeignet, wenn:

  • Ihr Datenvolumen und der Durchsatz passen in eine einzelne Datenbankinstanz, auch bei projiziertem Wachstum. Die vertikale Skalierung behält die Einfachheit der Abfrage und die Transaktionsintegrität bei.

  • Ihr Engpass ist das Lesevolume, nicht das Schreibvolume oder die Speicherkapazität. Lesereplikate und Caching-Schichten können den Lesedatenverkehr auslagern, ohne die durch Sharding eingeführte Komplexität bei abteilungsübergreifenden Abfragen.

  • Ihr Datenbankmodul unterstützt Partitionierung auf Tabellenebene, die Ihren Leistungsanforderungen entspricht. Für die Partitionierung innerhalb einer einzelnen Instanz sind nicht mehrere Server oder Routinglogik erforderlich.

  • Ihre dominanten Abfragemuster erfordern entitätsübergreifende Verknüpfungen, Multientitätstransaktionen oder Aggregationen vollständiger Datasets. Sharding macht diese Vorgänge teuer, und der Aufwand für Fanoutabfragen und die verteilte Koordination kann die Skalierungsvorteile übersteigen.

Workloadentwurf

Bewerten Sie, wie Sie das Sharding-Muster im Entwurf einer Workload verwenden, um die in den Azure Well-Architected Framework-Säulen behandelten Ziele und Prinzipien zu erfüllen. Die folgende Tabelle enthält Anleitungen dazu, wie dieses Muster die Ziele jeder Säule unterstützt.

Säule So unterstützt dieses Muster die Säulenziele
Zuverlässigkeitsentwurfsentscheidungen helfen Ihrer Arbeitsauslastung, ausfallsicher zu werden und sicherzustellen, dass sie nach auftreten eines Fehlers wieder in einen voll funktionsfähigen Zustand versetzt wird. Daten und Verarbeitung sind auf den Shard beschränkt, so dass eine Fehlfunktion in einem Shard auf diesen Shard beschränkt bleibt.

- Datenpartitionierung
- RE:07 Selbsterhaltung
Die Kostenoptimierung konzentriert sich auf die Erhaltung und Verbesserung der Kapitalrendite Ihres Workloads. Ein System, das Shards implementiert, profitiert oft von der Verwendung mehrerer Instanzen von weniger teuren Rechen- oder Speicherressourcen anstelle einer einzigen teureren Ressource. In vielen Fällen können Sie mit dieser Konfiguration Geld sparen.

- CO:07 Komponentenkosten
Performance Efficiency hilft Ihrem Workload durch Optimierungen bei Skalierung, Daten und Code, die Anforderungen effizient zu erfüllen . Wenn Sie Sharding in Ihrer Skalierungsstrategie verwenden, sind Daten und Verarbeitung für jeden Shard isoliert, sodass Anforderungen nur für Ressourcen innerhalb ihrer zugewiesenen Shard konkurrieren. Sie können auch Sharding verwenden, um die Daten nach geografischen Gesichtspunkten zu optimieren.

- PE:05 Skalierung und Partitionierung
- PE:08 Datenleistung

Wenn dieses Muster Kompromisse innerhalb einer Säule einführt, sollten Sie sie gegen die Ziele der anderen Säulen berücksichtigen.

Beispiel

Betrachten Sie eine Website, die eine umfangreiche Sammlung von Informationen über veröffentlichte Bücher weltweit anzeigt. Die Anzahl möglicher Bücher, die in dieser Workload katalogisiert sind, und die typischen Abfrage- und Verwendungsmuster überschreiten, was eine einzelne relationale Datenbank verarbeiten kann. Der Workload-Architekt entscheidet sich, die Daten über mehrere Datenbankinstanzen hinweg zu shardieren, indem die statische ISBN der Bücher als Shardschlüssel verwendet wird. Insbesondere verwendet der Architekt die Prüfziffer (0 - 10) der ISBN, die 11 mögliche logische Shards mit ziemlich ausgewogener Datenverteilung bereitstellt.

Zunächst ordnet der Architekt die 11 logischen Shards in drei physische Shard-Datenbanken zu. Bei diesem ansatz für virtuelle Partitionen werden viele logische Partitionen weniger physischen Knoten zugeordnet. Der Architekt verwendet den Lookup-Sharding-Ansatz und speichert die Schlüssel-zu-Server-Zuordnung in einer Shard-Kartendatenbank.

Diagramm, das eine Sharded SQL-Datenbankarchitektur für eine Buchkataloganwendung zeigt.

Azure App Service ist als Buchkatalogwebsite bezeichnet. Sie stellt eine Verbindung mit mehreren SQL-Datenbankinstanzen und einer Azure AI Search-Instanz dar. Eine der Datenbanken wird als ShardMap-Datenbank bezeichnet. Sie enthält eine Beispieltabelle, die einen Teil der Zuordnungstabelle widerspiegelt, welche weiter unten in diesem Artikel aufgeführt wird. Die Tabelle enthält drei Shard-Datenbankinstanzen: bookdbshard0, bookdbshard1 und bookdbshard2. Die anderen Datenbanken enthalten identische Beispielauflistungen von Tabellen darunter. Die Tabellen enthalten Bücher, LibraryOfCongressCatalog und einen Indikator für weitere Tabellen. Die KI-Suche wird für die facettierte Navigation und die Websitesuche verwendet. Verwaltete Identität ist dem App-Dienst zugeordnet.

Suchen der Shardzuordnung

Die Shardzuordnungsdatenbank enthält folgende Shardzuordnungstabelle und -daten.

SELECT ShardKey, DatabaseServer
FROM BookDataShardMap
| ShardKey | DatabaseServer |
|----------|----------------|
|        0 | bookdbshard0   |
|        1 | bookdbshard0   |
|        2 | bookdbshard0   |
|        3 | bookdbshard1   |
|        4 | bookdbshard1   |
|        5 | bookdbshard1   |
|        6 | bookdbshard2   |
|        7 | bookdbshard2   |
|        8 | bookdbshard2   |
|        9 | bookdbshard0   |
|       10 | bookdbshard1   |

Beispiel-Website-Code: Zugriff auf einen einzelnen Shard

Die Website weiß nicht, wie viele physische Sharddatenbanken vorhanden sind (in diesem Fall drei) oder die Logik, die einem Shardschlüssel eine Datenbankinstanz zuordnet. Es weiß nur, dass die Prüfziffer der ISBN eines Buchs der Shardschlüssel ist. Die Website verfügt über Lesezugriff auf die Shard-Zuordnungsdatenbank und über Lese-/Schreibzugriff auf alle Sharddatenbanken. In diesem Beispiel verwendet die Website die vom System verwaltete Identität des Azure App Service-Hosts für die Autorisierung, wodurch geheime Schlüssel aus Verbindungszeichenfolgen entfernt werden.

Die Website ist mit den folgenden Verbindungszeichenfolgen entweder in einer appsettings.json Datei konfiguriert, wie in diesem Beispiel gezeigt, oder über App Service-App-Einstellungen.

{
  ...
  "ConnectionStrings": {
    "ShardMapDb": "Data Source=tcp:<database-server-name>.database.windows.net,1433;Initial Catalog=ShardMap;Authentication=Active Directory Default;App=Book Site v1.5a",
    "BookDbFragment": "Data Source=tcp:SHARD.database.windows.net,1433;Initial Catalog=Books;Authentication=Active Directory Default;App=Book Site v1.5a"
  },
  ...
}

Der folgende Code zeigt, wie die Website eine Aktualisierungsabfrage für den Datenbankshardpool der Workload ausführt.

...

// All data for this book is stored in a shard based on the book's ISBN check digit,
// which is converted to an integer 0 - 10 (special value 'X' becomes 10).
int isbnCheckDigit = book.Isbn.CheckDigitAsInt;

// Establish a pooled connection to the database shard for this specific book.
using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: isbnCheckDigit, cancellationToken))
{
  // Update the book's Library of Congress catalog information.
  SqlCommand cmd = sqlConn.CreateCommand();
  cmd.CommandText = @"UPDATE LibraryOfCongressCatalog
                         SET ControlNumber = @lccn,
                             ...
                             Classification = @lcc
                       WHERE BookID = @bookId";

  cmd.Parameters.AddWithValue("@lccn", book.LibraryOfCongress.Lccn);
  ...
  cmd.Parameters.AddWithValue("@lcc", book.LibraryOfCongress.Lcc);
  cmd.Parameters.AddWithValue("@bookId", book.Id);

  await cmd.ExecuteNonQueryAsync(cancellationToken);
}

...

Im vorherigen Beispielcode sollte bei book.Isbn978-8-1130-1024-6isbnCheckDigit der Wert 6 sein. Der OpenShardConnectionForKeyAsync(6) Aufruf wird in der Regel mithilfe eines Cache-Aside-Ansatzes implementiert. Wenn zwischengespeicherte Shard-Informationen für Shardschlüssel 6 nicht verfügbar sind, fragt die Methode die durch die ShardMapDb Verbindungszeichenfolge identifizierte Shardzuordnungsdatenbank ab. Die Methode ruft den Wert "bookdbshard2 " entweder aus dem Anwendungscache oder der Sharddatenbank ab und ersetzt ihn SHARD in der BookDbFragment Verbindungszeichenfolge. Anschließend stellt die Methode eine gepoolte Verbindung mit bookdbshard2.database.windows.net her, öffnet sie und gibt sie an den aufrufenden Code zurück. Der Code aktualisiert dann den vorhandenen Datensatz in dieser Datenbankinstanz.

Beispiel für Website-Code: Zugriff auf mehrere Shards

In dem seltenen Fall, dass die Website eine direkte Abfrage über Shards hinweg erfordert, führt die Anwendung eine parallele Fan-out-Abfrage über alle Shards hinweg aus.

...

// Retrieve all shard keys.
var shardKeys = shardedDatabaseConnections.GetAllShardKeys();

// Run the query in a fan-out style against each shard in the shard list.
Parallel.ForEachAsync(shardKeys, async (shardKey, cancellationToken) =>
{
  using (SqlConnection sqlConn = await shardedDatabaseConnections.OpenShardConnectionForKeyAsync(key: shardKey, cancellationToken))
  {
    SqlCommand cmd = sqlConn.CreateCommand();
    cmd.CommandText = @"SELECT ...
                          FROM ...
                         WHERE ...";

    SqlDataReader reader = await cmd.ExecuteReaderAsync(cancellationToken);

    while (await reader.ReadAsync(cancellationToken))
    {
      // Collect the results into a thread-safe data structure.
    }

    reader.Close();
  }
});

...

Als Alternative zu Quershardabfragen kann diese Workload einen extern verwalteten Index in Azure AI Search für die Websitesuche oder die facettierte Navigation verwenden.

Hinzufügen von Shardinstanzen

Das Workload-Team weiß, dass, wenn der Datenkatalog oder seine gleichzeitige Nutzung erheblich wächst, sie möglicherweise mehr als drei Datenbankinstanzen benötigen. Das Workloadteam erwartet nicht, Dass Datenbankserver dynamisch hinzugefügt werden, und sie akzeptieren Arbeitsauslastungsausfallzeiten, wenn ein neuer Shard online kommt. Um eine neue Shard-Instanz online zu bringen, müssen sie Daten aus vorhandenen Shards in den neuen Shard verschieben und die Shard-Kartentabelle aktualisieren. Mit diesem relativ statischen Ansatz kann die Workload die Shardschlüsseldatenbankzuordnung im Websitecode sicher zwischenspeichern.

Die Logik des Shardschlüssels in diesem Beispiel weist eine Obergrenze von 11 physischen Shards auf. Wenn das Workloadteam durch die Lastschätzung bestimmt, dass sie letztendlich mehr als 11 Datenbankinstanzen benötigen, müssen sie eine invasive Änderung an der Shard-Schlüssellogik vornehmen. Diese Änderung umfasst eine sorgfältige Planung von Codeänderungen und datenmigrationen in die neue Schlüssellogik.

SDK-Funktionalität

Statt benutzerdefinierten Code für die Shardverwaltung und das Abfragerouting an SQL-Datenbankinstanzen zu schreiben, bewerten Sie die flexible Datenbankclientbibliothek. Diese Bibliothek unterstützt die Shardzuordnungsverwaltung, die datenabhängige Abfrageweiterleitung und shardübergreifende Abfragen in C# und Java.

Nächster Schritt

  • Konsistenzstufen in Azure Cosmos DB: Das Verteilen von Daten über Shards hinweg führt zu Konsistenzkonflikten. In diesem Artikel wird das Spektrum der Konsistenzmodelle, von starken bis zu eventualen, und ihre Auswirkungen auf Verfügbarkeit und Latenz beschrieben.
  • Horizontale, vertikale und funktionale Datenpartitionierung: In diesem Artikel werden weitere Strategien für die Partitionierung von Daten in der Cloud beschrieben, um die Skalierbarkeit zu verbessern, die Konflikte zu reduzieren und die Leistung zu optimieren.
  • Indextabellenmuster: Manchmal können nicht alle Abfragen allein durch die Gestaltung des Shardschlüssels unterstützt werden. Eine Anwendung kann das Indextabellenmuster verwenden, um Daten aus einem großen Datenspeicher abzurufen, indem sie einen anderen Schlüssel als den Shardschlüssel angeben.
  • Materialisiertes Ansichtsmuster: Um die Leistung einiger Abfragevorgänge aufrechtzuerhalten, können Sie materialisierte Ansichten erstellen, die Daten aggregieren und zusammenfassen, insbesondere, wenn Sie diese Daten über Shards verteilen.