Entwerfen einer skalierbaren Partitionierungsstrategie für Azure Table Storage

In diesem Artikel werden das Partitionieren einer Tabelle in Azure Table Storage und Strategien erläutert, die Sie verwenden können, um eine effiziente Skalierbarkeit sicherzustellen.

Azure bietet Cloudspeicher, der hochverfügbar und hochgradig skalierbar ist. Das zugrunde liegende Speichersystem für Azure wird über eine Reihe von Diensten bereitgestellt, einschließlich Azure Blob Storage, Azure Table Storage, Azure Queue Storage und Azure Files.

Azure Table Storage ist für das Speichern strukturierter Daten konzipiert. Der Azure Storage-Dienst unterstützt eine unbegrenzte Anzahl von Tabellen. Jede Tabelle kann auf massive Ebenen skaliert werden und bietet Terabytes an physischem Speicher. Um Tabellen optimal nutzen zu können, müssen Sie Ihre Daten optimal partitionieren. In diesem Artikel werden Strategien erläutert, die Sie zum effizienten Partitionieren von Daten für Azure Table Storage verwenden können.

Tabellenentitäten

Tabellenentitäten stellen die Dateneinheiten dar, die in einer Tabelle gespeichert sind. Tabellenentitäten ähneln Zeilen in einer typischen relationalen Datenbanktabelle. Jede Entität definiert eine Auflistung von Eigenschaften. Jede Eigenschaft wird als Schlüssel-Wert-Paar durch ihren Namen, wert und den Datentyp des Werts definiert. Entitäten müssen die folgenden drei Systemeigenschaften als Teil der Eigenschaftenauflistung definieren:

  • PartitionKey: Die PartitionKey-Eigenschaft speichert Zeichenfolgenwerte, die die Partition identifizieren, zu der eine Entität gehört. Partitionen sind, wie wir später erläutern, von wesentlicher Bedeutung für die Skalierbarkeit der Tabelle. Entitäten mit demselben PartitionKey-Wert werden in derselben Partition gespeichert.

  • RowKey: Die RowKey-Eigenschaft speichert Zeichenfolgenwerte, die Entitäten innerhalb jeder Partition eindeutig identifizieren. PartitionKey und RowKey bilden zusammen den Primärschlüssel für die Entität.

  • Zeitstempel: Die Timestamp-Eigenschaft ermöglicht die Rückverfolgbarkeit für eine Entität. Ein Zeitstempel ist ein Datum/Uhrzeit-Wert, der Ihnen angibt, wann die Entität zuletzt geändert wurde. Ein Zeitstempel wird manchmal als Version der Entität bezeichnet. Änderungen an Zeitstempeln werden ignoriert, da der Tabellendienst den Wert für diese Eigenschaft während aller Einfüge- und Aktualisierungsvorgänge beibehält.

Primärschlüssel für Tabellen

Der Primärschlüssel für eine Azure-Entität besteht aus den kombinierten Eigenschaften PartitionKey und RowKey . Die beiden Eigenschaften bilden einen einzelnen gruppierten Index innerhalb der Tabelle. Die PartitionKey - und RowKey-Werte können bis zu 1024 Zeichen groß sein. Leere Zeichenfolgen sind ebenfalls zulässig. NULL-Werte sind jedoch nicht zulässig.

Der gruppierte Index sortiert nach PartitionKey in aufsteigender Reihenfolge und dann nach RowKey in aufsteigender Reihenfolge. Die Sortierfolge wird in allen Abfrageantworten berücksichtigt. Während der Sortierung werden lexikalische Vergleiche verwendet. Ein Zeichenfolgenwert von "111" wird vor dem Zeichenfolgenwert "2" angezeigt. In einigen Fällen kann die Sortierreihenfolge numerisch sein. Um in einer numerischen und aufsteigenden Reihenfolge zu sortieren, müssen Sie Zeichenfolgen mit fester Länge mit null aufgefüllten Zeichenfolgen verwenden. Im vorherigen Beispiel wird "002" vor "111" angezeigt.

Tabellenpartitionen

Partitionen stellen eine Auflistung von Entitäten mit den gleichen PartitionKey-Werten dar. Partitionen werden immer von einem Partitionsserver bereitgestellt. Jeder Partitionsserver kann eine oder mehrere Partitionen bereitstellen. Für jeden Paritionsserver gilt ein Ratenlimit bezüglich der Anzahl der Entitäten, die von einer Partition innerhalb eines Zeitraums verarbeitet werden können. Insbesondere hat eine Partition ein Skalierbarkeitsziel von 2.000 Entitäten pro Sekunde. Dieser Durchsatz kann bei minimaler Auslastung des Speicherknotens höher sein, wird aber gedrosselt, wenn der Knoten heiß oder aktiv wird.

Um das Konzept der Partitionierung besser zu veranschaulichen, zeigt die folgende Abbildung eine Tabelle, die eine kleine Teilmenge von Daten für Registrierungen von Fußrennenereignissen enthält. Die Abbildung zeigt eine konzeptionelle Ansicht der Partitionierung, bei der der PartitionKey drei verschiedene Werte enthält: den Namen des Ereignisses in Kombination mit drei Distanzen (Vollmarathon, Halbmarathon und 10 km). In diesem Beispiel werden zwei Partitionsserver verwendet. Server A enthält Registrierungen für die Halbmarathon- und 10 km-Distanzen. Server B enthält nur die vollständigen Marathondistanzen. Die RowKey-Werte werden angezeigt, um Kontext bereitzustellen, aber die Werte sind für dieses Beispiel nicht aussagekräftig.

Ein Diagramm, das eine Tabelle mit drei Partitionen
Eine Tabelle mit drei Partitionen

Skalierbarkeit

Weil eine Partition immer vom selben Partitionsserver verarbeitet wird und jeder Partitionsserver eine oder mehrere Partitionen verarbeiten kann, ist es von der Integrität des Servers abhängig, wie effizient die Entitäten verarbeitet werden. Server, die auf einen hohen Datenverkehr für ihre Partitionen stoßen, können möglicherweise keinen hohen Durchsatz gewährleisten. Wenn beispielsweise in der obigen Abbildung viele Anforderungen für "2011 New York City Marathon__Half" empfangen werden, kann Server A zu heiß werden. Um den Durchsatz des Servers zu erhöhen, führt das Speichersystem einen Lastenausgleich für die Partitionen auf die anderen Server aus. Infolgedessen wird der Verkehr über viele andere Server verteilt. Für einen optimalen Lastenausgleich des Datenverkehrs sollten Sie mehr Partitionen verwenden, damit Azure Table Storage die Partitionen auf mehr Partitionsserver verteilen kann.

Entitätsgruppentransaktionen

Eine Entitätsgruppentransaktion ist eine Gruppe von Speichervorgängen, die atomar für Entitäten implementiert werden, die denselben PartitionKey-Wert aufweisen. Wenn ein Speichervorgang in der Entitätsgruppe fehlschlägt, wird für alle Speichervorgänge in der Entität ein Rollback ausgeführt. Eine Entitätsgruppentransaktion besteht aus nicht mehr als 100 Speichervorgängen und darf nicht mehr als 4 MiB groß sein. Entitätsgruppentransaktionen bieten Azure-Tabellenspeicher mit einer begrenzten Form der Semantik der Atomarität, Konsistenz, Isolation und Dauerhaftigkeit (ACID), die von relationalen Datenbanken bereitgestellt wird.

Entitätsgruppentransaktionen verbessern den Durchsatz, da sie die Anzahl einzelner Speichervorgänge reduzieren, die an Azure Table Storage übermittelt werden müssen. Entitätsgruppentransaktionen bieten auch einen wirtschaftlichen Vorteil. Eine Entitätsgruppentransaktion wird als einzelner Speichervorgang abgerechnet, unabhängig davon, wie viele Speichervorgänge sie enthält. Da sich alle Speichervorgänge in einer Entitätsgruppentransaktion auf Entitäten mit demselben PartitionKey-Wert auswirken, kann die Notwendigkeit, Entitätsgruppentransaktionen zu verwenden, die Auswahl des PartitionKey-Werts steuern.

Bereichspartitionen

Wenn Sie eindeutige PartitionKey-Werte für Ihre Entitäten verwenden, gehört jede Entität in ihre eigene Partition. Wenn die von Ihnen verwendeten eindeutigen Werte den Wert erhöhen oder verringern, ist es möglich, dass Azure Bereichspartitionen erstellt. Bereichspartitionen gruppieren Entitäten mit sequenziellen, eindeutigen PartitionKey-Werten , um die Leistung von Bereichsabfragen zu verbessern. Ohne Bereichspartitionen muss eine Bereichsabfrage Partitions- oder Servergrenzen überschreiten, was die Abfrageleistung beeinträchtigen kann. Betrachten Sie eine Anwendung, die die folgende Tabelle verwendet, die einen steigenden Sequenzwert für PartitionKey aufweist:

PartitionKey Zeilenschlüssel
"0001" -
"0002" -
"0003" -
"0004" -
"0005" -
"0006" -

Azure kann die ersten drei Entitäten in einer Bereichspartition gruppieren. Wenn Sie eine Bereichsabfrage auf die Tabelle anwenden, die partitionKey als Kriterien verwendet und Entitäten von "0001" bis "0003" anfordert, kann die Abfrage effizient funktionieren, da die Entitäten von einem einzelnen Partitionsserver bereitgestellt werden. Es gibt keine Garantie, wann und wie eine Bereichspartition erstellt wird.

Das Vorhandensein von Bereichspartitionen für Ihre Tabelle kann sich auf die Leistung Ihrer Einfügevorgänge auswirken, wenn Sie Entitäten einfügen, die partitionKey-Werte erhöhen oder verringern. Das Einfügen von Entitäten mit steigenden PartitionKey-Werten wird als anfügegeschütztes Muster bezeichnet. Das Einfügen von Entitäten mit abnehmenden Werten wird als vorab eingestelltes Muster bezeichnet. Erwägen Sie, diese Art von Mustern nicht zu verwenden, da der Gesamtdurchsatz Ihrer Einfügeanforderungen durch einen einzelnen Partitionsserver begrenzt ist. Dies liegt daran, dass die erste und die letzte Partition (Bereichspartitionen) die geringsten und größten PartitionKey-Werte enthalten, wenn Bereichspartitionen vorhanden sind. Daher zielt das Einfügen einer neuen Entität, die einen sequenziell niedrigeren oder höheren PartitionKey-Wert aufweist, auf eine der Endpartitionen ab. Die folgende Abbildung zeigt einen möglichen Satz von Bereichspartitionen, die auf dem vorherigen Beispiel basieren. Wenn eine Gruppe von Entitäten "0007", "0008" und "0009" eingefügt würde, würden sie der letzten (orangenen) Partition zugewiesen.

Diagramm mit einer Reihe von Bereichspartitionen
Eine Reihe von Bereichspartitionen

Es ist wichtig zu beachten, dass es keine negativen Auswirkungen auf die Leistung gibt, wenn die Einfügevorgänge PartitionKey-Werte verwenden, die verstreuter sind.

Daten analysieren

Im Gegensatz zu einer Tabelle in einer relationalen Datenbank, die Sie zum Verwalten von Indizes verwenden können, können Tabellen in Azure Table Storage nur einen Index aufweisen. Ein Index in Azure Table Storage besteht immer aus den Eigenschaften PartitionKey und RowKey .

In einer Azure-Tabelle haben Sie nicht den Luxus, die Leistung Ihrer Tabelle zu optimieren, indem Sie weitere Indizes hinzufügen oder eine vorhandene Tabelle nach dem Rollout ändern. Sie müssen die Daten beim Entwerfen der Tabelle analysieren. Die wichtigsten Aspekte, die für eine optimale Skalierbarkeit und für die Abfrage- und Einfügeeffizienz zu berücksichtigen sind, sind die PartitionKey - und RowKey-Werte . In diesem Artikel wird hervorgehoben, wie Der Partitionsschlüssel ausgewählt wird , da er sich direkt auf die Partitionierung von Tabellen bezieht.

Festlegen der Partitionsgröße

Das Festlegen der Partitionsgröße bezieht sich auf die Anzahl der Entitäten, die eine Partition enthält. Wie wir unter Skalierbarkeit erläutern, bedeutet mehr Partitionen einen besseren Lastenausgleich. Die Granularität des PartitionKey-Werts wirkt sich auf die Größe der Partitionen aus. Wenn auf der gröberen Ebene ein einzelner Wert als PartitionSschlüssel verwendet wird, befinden sich alle Entitäten in einer einzelnen Partition, die sehr groß ist. Auf der kleinsten Ebene der Granularität kann der PartitionKey eindeutige Werte für jede Entität enthalten. Das Ergebnis ist, dass für jede Entität eine Partition vorhanden ist. Die folgende Tabelle zeigt die Vor- und Nachteile für den Bereich der Granularitäten:

PartitionKey-Granularität Partitionsgröße Vorteile Nachteile
Einzelwert Kleine Anzahl von Entitäten Batchtransaktionen sind mit jeder Entität möglich.

Alle Entitäten sind lokal und werden vom gleichen Speicherknoten aus bedient.
Einzelwert Große Anzahl von Entitäten Entitätsgruppentransaktionen können mit jeder Entität möglich sein. Weitere Informationen zu den Grenzwerten von Entitätsgruppentransaktionen finden Sie unter Durchführen von Entitätsgruppentransaktionen. Die Skalierung ist eingeschränkt.

Der Durchsatz ist auf die Leistung eines einzelnen Servers beschränkt.
Mehrere Werte Mehrere Partitionen

Partitionsgrößen hängen von der Entitätsverteilung ab.
Batchtransaktionen sind für einige Entitäten möglich.

Dynamische Partitionierung ist möglich.

Abfragen mit einzeler Anforderung sind möglich (keine Fortsetzungstoken).

Der Lastenausgleich auf mehr Partitionsserver ist möglich.
Eine sehr ungleiche Verteilung von Entitäten auf Partitionen kann die Leistung der größeren und aktiveren Partitionen einschränken.
Eindeutige Werte Viele kleine Partitionen Die Tabelle ist hochgradig skalierbar.

Bereichspartitionen können die Leistung partitionsübergreifender Bereichsabfragen verbessern.
Abfragen, die Bereiche umfassen, erfordern möglicherweise Besuche von mehr als einem Server.

Batchtransaktionen sind nicht möglich.

Nur anfüge- oder vorab eingestellte Muster wirken sich möglicherweise auf den Einfügedurchsatz aus.

Die Tabelle zeigt, wie sich die Skalierung auf PartitionKey-Werte auswirkt. Es empfiehlt sich, kleinere Partitionen zu bevorzugen, da sie einen besseren Lastenausgleich bieten. Größere Partitionen können in einigen Szenarien geeignet sein und sind nicht unbedingt nachteilig. Wenn Ihre Anwendung beispielsweise keine Skalierbarkeit erfordert, kann eine einzelne große Partition geeignet sein.

Ermitteln von Abfragen

Mit Abfragen werden Daten aus Tabellen abgerufen. Wenn Sie die Daten für eine Tabelle in Azure Table Storage analysieren, ist es wichtig, zu berücksichtigen, welche Abfragen von der Anwendung verwendet werden. Wenn eine Anwendung über mehrere Abfragen verfügt, müssen Sie diese möglicherweise priorisieren, obwohl Ihre Entscheidungen möglicherweise subjektiv sind. In vielen Fällen sind dominante Abfragen von anderen Abfragen erkennbar. Hinsichtlich der Leistung lassen sich die Abfragen in verschiedene Kategorien unterteilen. Da eine Tabelle nur einen Index aufweist, hängt die Abfrageleistung in der Regel mit den PartitionKey - und RowKey-Eigenschaften zusammen. Die folgende Tabelle zeigt die verschiedenen Arten von Abfragen und deren Leistungsbewertungen:

Abfragetyp PartitionKey-Übereinstimmung RowKey-Übereinstimmung Leistungsbewertung
Suche in Zeilenbereich Exact Partial Besser mit kleineren Partitionen.

Schlecht bei Partitionen, die sehr groß sind.
Suche in Partitionsbereich Partial Partial Gut, wenn eine kleine Anzahl von Partitionsservern berührt wird.

Schlimmer, wenn mehr Server berührt werden.
Suche in der gesamten Tabelle Teilweise, keine Teilweise, keine Schlimmer, wenn eine Teilmenge von Partitionen überprüft wird.

Am schlechtesten, wenn alle Partitionen überprüft werden.

Hinweis

Die in der Tabelle definierten Leistungsbewertungen sind relativ zueinander. Die Anzahl und Größe der Partitionen kann letztendlich die Leistung der Abfrage bestimmen. Beispielsweise kann eine Partitionsbereichsüberprüfung für eine Tabelle mit vielen großen Partitionen im Vergleich zu einer vollständigen Tabellenüberprüfung für eine Tabelle mit einigen kleinen Partitionen möglicherweise schlecht funktionieren.

Die in der vorherigen Tabelle aufgeführten Abfragetypen zeigen basierend auf ihren Leistungsbewertungen einen Fortschritt von den besten Arten von Abfragen, die verwendet werden sollen, bis hin zu den schlechtesten Typen. Punktabfragen sind die besten Abfragetypen, weil hier der gruppierte Index der Tabelle voll genutzt wird. Die folgende Punktabfrage verwendet die Daten aus der Registrierungstabelle für Fußrennen:

http://<account>.windows.core.net/registrations(PartitionKey=”2011 New York City Marathon__Full”,RowKey=”1234__John__M__55”)  
  

Wenn in der Anwendung mehrere Abfragen verwendet werden, können nicht alle Abfragen Punktabfragen sein. Was die Leistung betrifft, folgen Bereichsabfragen an zweiter Stelle nach den Punktabfragen. Es gibt zwei Arten von Bereichsabfragen: die Zeilenbereichsüberprüfung und die Partitionsbereichsüberprüfung. Bei der Suche in einem Zeilenbereich wird eine einzelne Partition angegeben. Da der Vorgang auf einem Einzelnen Partitionsserver erfolgt, sind Zeilenbereichsscans im Allgemeinen effizienter als Partitionsbereichsscans. Ein wichtiger Faktor für die Leistung von Zeilenbereichsscans ist jedoch die Selektivität einer Abfrage. Die Abfrageselektivität bestimmt, wie viele Zeilen iteriert werden müssen, um die übereinstimmenden Zeilen zu finden. Selektivere Abfragen sind bei der Suche in Zeilenbereichen effizienter.

Um die Prioritäten Ihrer Abfragen zu bewerten, berücksichtigen Sie die Anforderungen an Häufigkeit und Antwortzeit für jede Abfrage. Häufig ausgeführte Abfragen werden möglicherweise höher priorisiert. Eine wichtige, aber selten verwendete Abfrage kann jedoch niedrige Latenzanforderungen aufweisen, die sie in der Prioritätsliste höher rangieren könnten.

Wählen Sie den Wert PartitionKey aus.

Der Kern des Entwurfs einer beliebigen Tabelle ist die Skalierbarkeit, die Abfragen, die für den Zugriff verwendet werden, und die Anforderungen an den Speichervorgang. Die PartitionKey-Werte , die Sie auswählen, legen fest, wie eine Tabelle partitioniert wird, und den Typ der Abfragen, die Sie verwenden können. Speichervorgänge und insbesondere Einfügungen können sich auch auf Die Auswahl der PartitionKey-Werte auswirken. Die PartitionKey-Werte können von einzelnen Werten bis zu eindeutigen Werten reichen. Sie können auch mit mehreren Werten erstellt werden. Sie können Entitätseigenschaften verwenden, um den PartitionKey-Wert zu bilden. Oder die Anwendung kann den Wert berechnen. In den folgenden Abschnitten werden wichtige Überlegungen erläutert.

Entitätsgruppentransaktionen

Entwickler sollten zunächst überlegen, ob die Anwendung Entitätsgruppentransaktionen (Batchupdates) verwendet. Entitätsgruppentransaktionen erfordern, dass Entitäten denselben PartitionKey-Wert haben. Da Batchupdates für eine ganze Gruppe gelten, kann die Auswahl der PartitionKey-Werte eingeschränkt sein. Beispielsweise muss eine Banking-Anwendung, die Bargeldtransaktionen verwaltet, Bargeldtransaktionen atomar in die Tabelle einfügen können. Bartransaktionen stellen sowohl die Debit- als auch die Kreditseite dar und müssen netto null sein. Diese Anforderung bedeutet, dass die Kontonummer nicht als Teil des PartitionKey-Werts verwendet werden kann, da jede Seite der Transaktion unterschiedliche Kontonummern verwendet. Stattdessen kann eine Transaktions-ID die bessere Wahl sein.

Partitionen

Partitionsnummern und -größen wirken sich auf die Skalierbarkeit einer tabelle aus, die unter Last steht. Sie werden auch durch die Granularität der PartitionKey-Werte gesteuert. Es kann schwierig sein , den PartitionKey basierend auf der Partitionsgröße zu bestimmen, insbesondere wenn die Verteilung der Werte schwer vorherzusagen ist. Als gute Faustregel gilt, mehrere kleinere Partitionen zu verwenden. Viele Tabellenpartitionen erleichtern Azure Table Storage die Verwaltung der Speicherknoten, über die die Partitionen bereitgestellt werden.

Die Auswahl eindeutiger oder feinerer Werte für den PartitionKey führt zu kleineren, aber mehr Partitionen. Dies ist im Allgemeinen günstig, da das System einen Lastenausgleich für die vielen Partitionen ausführen kann, um die Last auf viele Partitionen zu verteilen. Allerdings sollten Sie berücksichtigen, wie sich das Vorhandensein vieler Partitionen auf Bereichsabfragen auswirkt, die über Partitionsgrenzen hinweg gehen. Diese Arten von Abfragen müssen mehrere Partitionen besuchen, um eine Abfrage zu erfüllen. Es ist möglich, dass die Partitionen auf viele Partitionsserver verteilt sind. Wenn eine Abfrage über eine Servergrenze hinweg geht, müssen Fortsetzungstoken zurückgegeben werden. Fortsetzungstoken geben die nächsten PartitionKey - oder RowKey-Werte an, um den nächsten Satz von Daten für die Abfrage abzurufen. Mit anderen Worten, Fortsetzungstoken stellen mindestens eine weitere Anforderung an den Dienst dar, was die Gesamtleistung der Abfrage beeinträchtigen kann.

Die Abfrageselektivität ist ein weiterer Faktor, der sich auf die Abfrageleistung auswirken kann. Die Abfrageselektivität ist ein Maß dafür, wie viele Zeilen für jede Partition iteriert werden müssen. Je selektiver eine Abfrage ist, desto effizienter ist die Abfrage bei der Rückgabe der gewünschten Zeilen. Die Gesamtleistung von Bereichsabfragen hängt möglicherweise von der Anzahl der Partitionsserver ab, die berührt werden müssen, oder davon, wie selektiv die Abfrage ist. Außerdem sollten Sie beim Einfügen von Daten in ihre Tabelle vermeiden, dass Nur-Anfüge- oder Voranfügemuster verwendet werden. Wenn Sie diese Muster verwenden, können Sie den Durchsatz Ihrer Einfügevorgänge einschränken, obwohl Sie kleine und viele Partitionen erstellen. Die Muster "Nur anfüge" und "Vorabstellen" werden unter Bereichspartitionen erläutert.

Abfragen

Wenn Sie die Abfragen kennen, die Sie verwenden, können Sie bestimmen, welche Eigenschaften für den PartitionKey-Wert zu berücksichtigen sind. Die Eigenschaften, die Sie in den Abfragen verwenden, sind Kandidaten für den PartitionKey-Wert . Die folgende Tabelle enthält eine allgemeine Richtlinie zum Bestimmen des PartitionKey-Werts :

Wenn die Entität... Aktion
über eine Schlüsseleigenschaft verfügt, Verwenden Sie es als PartitionKey.
über zwei Schlüsseleigenschaften verfügt, Verwenden Sie einen als PartitionKey und den anderen als RowKey.
mehr als zwei Schlüsseleigenschaften besitzt Verwenden Sie einen zusammengesetzten Schlüssel aus verketteten Werten.

Wenn mehr als eine ebenso dominante Abfrage vorhanden ist, können Sie die Informationen mehrmals einfügen, indem Sie unterschiedliche RowKey-Werte verwenden, die Sie benötigen. Ihre Anwendung verwaltet sekundäre (oder tertiäre) Zeilen. Sie können diese Art von Muster verwenden, um die Leistungsanforderungen Ihrer Abfragen zu erfüllen. Im folgenden Beispiel werden die Daten aus dem Beispiel für die Registrierung von Fußrennen verwendet. Es gibt zwei dominante Abfragen:

  • Query by bib number (Abfrage nach Startnummer)
  • Query by age (Abfrage nach Alter)

Um alle beide dominanten Abfragen zu unterstützen, fügen Sie zwei Zeilen als Entitätsgruppentransaktion ein. Die folgende Tabelle zeigt die Eigenschaften PartitionKey und RowKey für dieses Szenario. Die RowKey-Werte stellen ein Präfix für die Startnummer und das Alter bereit, damit die Anwendung zwischen den beiden Werten unterscheiden kann.

PartitionKey Zeilenschlüssel
2011 New York City Marathon__Full BIB:01234__John__M__55
2011 New York City Marathon__Full AGE:055__1234__John__M

In diesem Beispiel ist eine Entitätsgruppentransaktion möglich, da die PartitionKey-Werte identisch sind. Die Gruppentransaktion stellt die Atomarität des Einfügevorgangs bereit. Obwohl es möglich ist, dieses Muster mit unterschiedlichen PartitionKey-Werten zu verwenden, wird empfohlen, die gleichen Werte zu verwenden, um diesen Vorteil zu erzielen. Andernfalls müssen Sie möglicherweise zusätzliche Logik schreiben, um atomische Transaktionen sicherzustellen, die unterschiedliche PartitionKey-Werte verwenden.

Speichervorgänge

Tabellen in Azure Table Storage können nicht nur über Abfragen geladen werden. Es kann auch zu Lasten von Speichervorgängen wie Einfügungen, Updates und Löschvorgängen kommen. Überlegen Sie, welche Art von Speichervorgängen Sie für die Tabelle ausführen und mit welcher Rate. Wenn Sie diese Vorgänge selten ausführen, müssen Sie sich möglicherweise keine Gedanken darüber machen. Bei häufigen Vorgängen wie der Ausführung vieler Einfügungen in kurzer Zeit müssen Sie jedoch berücksichtigen, wie diese Vorgänge als Ergebnis der von Ihnen ausgewählten PartitionKey-Werte bereitgestellt werden. Wichtige Beispiele sind die musterbasierten Anfüge- und vorangestellten Muster. Die Muster "Nur anfüge" und "Vorabstellen" werden unter Bereichspartitionen erläutert.

Wenn Sie ein Anfügemuster oder ein vorangestelltes Muster verwenden, verwenden Sie für den PartitionKey bei nachfolgenden Einfügungen eindeutige auf- oder absteigende Werte. Wenn Sie dieses Muster mit häufigen Einfügevorgängen kombinieren, kann Ihre Tabelle die Einfügevorgänge nicht mit hoher Skalierbarkeit verarbeiten. Die Skalierbarkeit Ihrer Tabelle ist betroffen, da Azure die Vorgangsanforderungen nicht auf andere Partitionsserver lastenausgleichen kann. In diesem Fall sollten Sie die Verwendung zufälliger Werte in Betracht ziehen, z. B. GUID-Werte. Dann können Ihre Partitionsgrößen klein bleiben und während Speichervorgängen weiterhin den Lastenausgleich beibehalten.

Belastungstests für Tabellenpartitionen

Wenn der PartitionKey-Wert komplex ist oder Vergleiche mit anderen PartitionKey-Zuordnungen erfordert, müssen Sie möglicherweise die Leistung der Tabelle testen. Mit dem Test sollte die Leistung der Partition unter Spitzenbelastungen untersucht werden.

So führen Sie einen Belastungstest durch

  1. Erstellen Sie eine Testtabelle.
  2. Laden Sie die Testtabelle mit Daten, sodass sie Entitäten mit dem PartitionKey-Wert enthält, den Sie als Ziel verwenden.
  3. Verwenden Sie die Anwendung, um Spitzenlasten für die Tabelle zu simulieren. Verwenden Sie den PartitionKey-Wert aus Schritt 2 als Ziel für eine einzelne Partition. Dieser Schritt unterscheidet sich für jede Anwendung, aber die Simulation sollte alle erforderlichen Abfragen und Speichervorgänge enthalten. Möglicherweise müssen Sie die Anwendung so anpassen, dass sie auf eine einzelne Partition ausgerichtet ist.
  4. Prüfen Sie den Durchsatz der GET- und PUT-Vorgänge in der Tabelle.

Zur Prüfung des Durchsatzes vergleichen Sie die Ist-Werte mit dem angegebenen Grenzwert für eine einzelne Partition auf einem einzelnen Server. Partitionen sind auf 2.000 Entitäten pro Sekunde beschränkt. Wenn der Durchsatz 2.000 Entitäten pro Sekunde für eine Partition überschreitet, kann der Server in einer Produktionseinstellung zu heiß ausgeführt werden. In diesem Fall sind die PartitionKey-Werte möglicherweise zu grob, sodass nicht genügend Partitionen vorhanden sind oder die Partitionen zu groß sind. Möglicherweise müssen Sie den PartitionKey-Wert ändern, damit die Partitionen auf weitere Server verteilt werden.

Lastenausgleich

Der Lastenausgleich auf Partitionsebene erfolgt, wenn eine Partition zu heiß wird. Wenn eine Partition zu heiß ist, arbeitet die Partition, insbesondere der Partitionsserver, über ihre Zielskalierbarkeit hinaus. Für Azure Storage hat jede Partition ein Skalierbarkeitsziel von 2.000 Entitäten pro Sekunde. Der Lastenausgleich erfolgt auch auf der DFS-Ebene (Distributed File System).

Der Lastenausgleich auf der DFS-Ebene befasst sich mit E/A-Last und liegt außerhalb des Rahmens dieses Artikels. Der Lastenausgleich auf Partitionsebene erfolgt nicht sofort, nachdem das Skalierbarkeitsziel überschritten wurde. Stattdessen wartet das System einige Minuten, bevor der Lastenausgleichsprozess gestartet wird. Dadurch wird sichergestellt, dass die Partition tatsächlich überlastet ist. Es ist nicht erforderlich, Partitionen mit generierter Last zu primen, die den Lastenausgleich auslöst, da das System die Aufgabe automatisch ausführt.

Wenn eine Tabelle mit einer bestimmten Last grundiert wurde, kann das System möglicherweise die Partitionen basierend auf der tatsächlichen Auslastung ausgleichen, was zu einer erheblich anderen Verteilung der Partitionen führt. Anstatt Partitionen zu primieren, sollten Sie Code schreiben, der das Timeout und die Server-Ausgelastet-Fehler behandelt. Die Fehler werden zurückgegeben, wenn das System einen Lastenausgleich hat. Durch die Behandlung dieser Fehler mithilfe einer Wiederholungsstrategie kann Ihre Anwendung Spitzenlasten besser verarbeiten. Wiederholungsstrategien werden im folgenden Abschnitt ausführlicher besprochen.

Wenn ein Lastenausgleich erfolgt, ist die Partition für einige Sekunden offline. Während des Offlinezeitraums wird die Partition vom System einem anderen Partitionsserver zugewiesen. Es ist wichtig zu beachten, dass Ihre Daten nicht von den Partitionsservern gespeichert werden. Stattdessen verarbeiten die Partitionsserver Entitäten von der DFS-Ebene. Da Ihre Daten nicht auf Partitionsebene gespeichert werden, ist das Verschieben von Partitionen auf verschiedene Server ein schneller Prozess. Diese Flexibilität schränkt die Ausfallzeiten, die bei Ihrer Anwendung auftreten können, erheblich ein.

Wiederholungsstrategie

Es ist wichtig, dass Ihre Anwendung Fehler bei Speichervorgängen behandelt, um sicherzustellen, dass Keine Datenupdates verloren gehen. Einige Fehler erfordern keine Wiederholungsstrategie. Beispielsweise profitieren Updates, die den Fehler 401 Nicht autorisiert zurückgeben, nicht von der Wiederholung des Vorgangs, da sich der Anwendungszustand wahrscheinlich nicht zwischen Wiederholungen ändert, die den Fehler 401 beheben. Fehler wie Server busy oder Timeout beziehen sich jedoch auf die Lastenausgleichsfeatures von Azure, die Tabellenskalierbarkeit bieten. Wenn die Speicherknoten, die Ihre Entitäten bedienen, heiß werden, gleicht Azure die Last aus, indem Partitionen auf andere Knoten verschoben werden. Während dieser Zeit kann auf die Partition nicht zugegriffen werden, was zu Fehlern beim Ausgelasteten Server oder Timeout führt. Schließlich wird die Partition wieder aktiviert, und die Updates werden fortgesetzt.

Eine Wiederholungsstrategie eignet sich für Server-Ausgelastete Fehler oder Timeoutfehler. In den meisten Fällen können Sie Fehler der 400-Ebene und einige Fehler auf 500 Ebenen aus der Wiederholungslogik ausschließen. Fehler, die ausgeschlossen werden können, sind 501 Nicht implementiert und 505 HTTP-Version nicht unterstützt. Anschließend können Sie eine Wiederholungsstrategie für Fehler mit bis zu 500 Ebenen implementieren, z. B. Server busy (503) und Timeout (504).

Sie können aus drei gängigen Wiederholungsstrategien für Ihre Anwendung wählen:

  • Kein Wiederholungsversuch: Es wird kein Wiederholungsversuch unternommen.
  • Behobener Backoff: Der Vorgang wird N-mal mit einem konstanten Backoffwert wiederholt.
  • Exponentieller Backoff: Der Vorgang wird N-mal mit einem exponentiellen Backoffwert wiederholt.

Die Keine-Wiederholungen-Strategie ist eine einfache (und ausweichende) Art der Fehlerbehandlung von Vorgängen. Eine Strategie ohne Wiederholung ist jedoch nicht sehr nützlich. Wenn keine Wiederholungsversuche vorgeschrieben werden, besteht offensichtlich das Risiko, dass Daten nach dem Fehlschlagen von Vorgängen nicht ordnungsgemäß gespeichert werden. Eine bessere Strategie ist die Verwendung der Fixed Backoff-Strategie. bietet die Möglichkeit, Wiederholungsvorgänge mit der gleichen Backoffdauer durchzuführen.

Die Strategie ist jedoch nicht für die Verarbeitung hochgradig skalierbarer Tabellen optimiert. Wenn viele Threads oder Prozesse auf die gleiche Dauer warten, können Konflikte auftreten. Eine empfohlene Wiederholungsstrategie ist eine Strategie, die ein exponentielles Backoff verwendet, bei dem jeder Wiederholungsversuch länger als der letzte Versuch ist. Er ähnelt dem Kollisionsvermeidungsalgorithmus, der in Computernetzwerken wie Ethernet verwendet wird. Bei der Strategie mit der exponenziellen Wartezeit wird ein Zufallsfaktor eingesetzt, um zusätzliche Varianz für das resultierende Intervall bereitzustellen. Die Wartezeit wird dann durch Minimal- und Maximalwerte beschränkt. Mit der folgenden Formel kann der nächste Wartezeitwert mit einem exponenziellen Algorithmus berechnet werden:

y = Rand(0,8z, 1,2z)(2x-1

y = Min(zmin + y, zmax

Hierbei gilt:

z = Standardwartezeit in Millisekunden

zmin = Vorgabe für minimale Wartezeit in Millisekunden

zmax = Vorgabe für maximale Wartezeit in Millisekunden

x = Anzahl der Wiederholungsversuche

y = Wartezeit in Millisekunden

Die Multiplikatoren 0,8 und 1,2, die in der Funktion Rand (zufällig) verwendet werden, erzeugen eine zufällige Varianz des Standardbackoffs innerhalb von ±20 % des ursprünglichen Werts. Der ±20 %-Bereich ist für die meisten Wiederholungsstrategien akzeptabel und verhindert weitere Kollisionen. Die Formel kann mithilfe des folgenden Codes implementiert werden:

int retries = 1;  
  
// Initialize variables with default values  
var defaultBackoff = TimeSpan.FromSeconds(30);  
var backoffMin = TimeSpan.FromSeconds(3);  
var backoffMax = TimeSpan.FromSeconds(90);  
  
var random = new Random();  
  
double backoff = random.Next(  
    (int)(0.8D * defaultBackoff.TotalMilliseconds),   
    (int)(1.2D * defaultBackoff.TotalMilliseconds));  
backoff *= (Math.Pow(2, retries) - 1);  
backoff = Math.Min(  
    backoffMin.TotalMilliseconds + backoff,   
    backoffMax.TotalMilliseconds);  
  

Zusammenfassung

Eine Anwendung in Azure Table Storage kann eine große Menge an Daten speichern, da Table Storage Partitionen auf vielen Speicherknoten verwaltet und neu zuweisen kann. Sie können die Skalierbarkeit einer Tabelle über die Datenpartitionierung steuern. Planen Sie voraus, wenn Sie ein Tabellenschema definieren, um sicherzustellen, dass Sie effiziente Partitionierungsstrategien implementieren. Analysieren Sie insbesondere die Anforderungen, Daten und Abfragen der Anwendung, bevor Sie PartitionKey-Werte auswählen. Jede Partition kann anderen Speicherknoten neu zugewiesen werden, wenn das System auf Datenverkehr reagiert. Verwenden Sie einen Partitionsbelastungstest, um sicherzustellen, dass die Tabelle über die richtigen PartitionKey-Werte verfügt . Dieser Test hilft Ihnen, zu ermitteln, wann Partitionen zu heiß sind, und hilft Ihnen dabei, die erforderlichen Partitionsanpassungen vorzunehmen.

Verwenden Sie eine Wiederholungsstrategie mit Backoff, um sicherzustellen, dass Ihre Anwendung zeitweilige Fehler behandelt und Ihre Daten beibehalten werden. Die Standardwiederherstellungsrichtlinie, die von der Azure Storage-Clientbibliothek verwendet wird, verfügt über ein exponentielles Backoff, das Konflikte vermeidet und den Durchsatz Ihrer Anwendung maximiert.