(0) exportieren Drucken
Alle erweitern

Entwerfen einer Strategie für die skalierbare Partitionierung des Azure-Tabellenspeichers

Letzte Aktualisierung: August 2014

Autor: http://msdn.microsoft.com/de-de/library/hh307529.aspx

Referenzbild

Weitere Informationen zu RBA Consulting.

Zusammenfassung In diesem Artikel werden Themen zur Partitionierung einer Azure-Tabelle und die Strategien erörtert, mit denen eine effiziente Skalierbarkeit sichergestellt werden kann.

Azure stellt zuverlässigen Datenspeicher bereit, der stets verfügbar und hoch skalierbar ist. Das zugrunde liegende Speichersystem für Azure wird durch eine Gruppe von Objektabstraktionen, die häufig als Dienste bezeichnet werden und den Tabellen-, BLOB- und Warteschlangendienst umfassen. Jeder dieser Dienste kann einen Großteil Ihrer Entwicklungsanforderungen unterstützen. Wenn in Ihrer Anwendung strukturierte Daten gespeichert werden müssen, stellt die Azure-Tabelle die beste Option dar. Der Azure-Speicherdienst unterstützt eine unbeschränkte Anzahl von Tabellen, und jede Tabelle kann extrem skaliert werden. Eine Tabelle kann automatisch so skaliert werden, dass darin Milliarden von Entitäten gespeichert werden können, die Terabyte physischen Speichers darstellen. Um alle Vorteile der Tabellen nutzen zu können, sollten die Daten mit optimalen PartitionKey-Werten partitioniert werden. In diesem Artikel werden Strategien untersucht, mit denen Sie Daten für den Azure-Tabellenspeicher effizient partitionieren können.

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

  • PartitionKey: Die PartitionKey-Eigenschaft enthält Zeichenfolgenwerte, welche die Partition definieren, zu der eine Entität gehört. Das bedeutet, dass Entitäten mit dem gleichen PartitionKey-Wert zur selben Partition gehören. Wie später besprochen wird, spielen Partitionen eine zentrale Rolle für die Skalierbarkeit einer Tabelle.

  • RowKey: Die RowKey-Eigenschaft enthält Zeichenfolgenwerte, welche die Entitäten in jeder Partition eindeutig identifizieren.

  • Timestamp: Die Timestamp-Eigenschaft ermöglicht die Rückverfolgbarkeit einer Entität. Diese Eigenschaft enthält einen Zeitstempel, d. h. einen DateTime-Wert mit der Angabe des Zeitpunkts, zu dem die Entität zuletzt geändert wurde. Der Timestamp-Wert wird manchmal auch als Version der Entität bezeichnet. Änderungen der Timestamp-Werte werden ignoriert, weil der Tabellendienst den Wert dieser Eigenschaften während aller Einfüge- und Aktualisierungsvorgänge verwaltet.

Der Primärschlüssel einer Datenbanktabelle definiert die Spalten, welche die einzelnen Zeilen jeweils eindeutig identifizieren. Dasselbe gilt für Azure-Tabellen. Der Primärschlüssel einer Azure-Tabelle besteht aus den Eigenschaften PartitionKey und RowKey, die einen gruppierten Index in der Tabelle bilden. Die Eigenschaften PartitionKey und RowKey können jeweils bis zu 1 KB Zeichenfolgenwerte speichern. Leere Zeichenfolgen sind ebenfalls zulässig, NULL-Werte dagegen nicht. Der gruppierte Index wird in aufsteigender Reihenfolge nach der PartitionKey-Eigenschaft und dann ebenfalls in aufsteigender Reihenfolge nach der RowKey-Eigenschaft sortiert. Die Sortierfolge wird in allen Abfrageantworten berücksichtigt. Während der Sortierung werden lexikalische Vergleiche verwendet. Daher erscheint der Zeichenfolgenwert "111" vor dem Zeichenfolgenwert "2". In manchen Fällen soll die Reihenfolge numerisch sein. Um in numerischer und aufsteigender Reihenfolge sortieren zu können, müssen Zeichenfolgen fester Länge, die mit Nullen aufgefüllt sind, verwendet werden. Im vorigen Beispiel wird "002" verwendet, damit der Wert vor "111" erscheint.

Partitionen stellen eine Auflistung von Entitäten mit den gleichen PartitionKey-Werten dar. Partitionen werden immer von einem Partitionsserver verarbeitet, und jeder Partitionsserver kann eine oder mehrere Partitionen verarbeiten. 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 gilt für eine Partition ein Skalierbarkeitsziel von 500 Entitäten pro Sekunde. Dieser Durchsatz kann bei minimaler Arbeitsauslastung des Speicherknotens höher sein, wird jedoch gedrosselt, wenn der Speicherknoten überlastet oder sehr aktiv wird. Um das Konzept der Partitionierung besser zu veranschaulichen, wird in der folgenden Abbildung eine Tabelle dargestellt, die eine kleine Teilmenge von Daten zur Registrierung von Wettlaufveranstaltungen enthält. Es wird eine konzeptuelle Sicht der Partitionierung gezeigt, wobei die PartitionKey-Eigenschaft drei verschiedene Werte mit dem Namen und die Distanz der Veranstaltung enthält. In diesem Beispiel sind zwei Partitionsserver vorhanden. Server A enthält die Registrierungen für den Halbmarathon und die 10-km-Laufstrecken, während Server B nur die Marathonstrecken enthält. Die RowKey-Werte werden gezeigt, um den Kontext bereitzustellen, sie sind in diesem Beispiel aber nicht von Bedeutung.

Referenzbildschirm

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, bei denen hoher Verkehr für ihre Partitionen auftritt, können möglicherweise nicht permanent einen hohen Durchsatz aufrechterhalten. Wenn beispielsweise in der obigen Abbildung viele Anforderungen für "2011 New York City Marathon__Half" eingehen, dann könnte Server A überlastet 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. Um einen optimalen Lastenausgleich des Verkehrs zu erreichen, sollten Sie mehrere Partitionen verwenden, weil der Azure-Tabellendienst die Partitionen dann auf mehrere Partitionsserver verteilen kann.

Eine Entitätsgruppentransaktion ist ein Satz von Speichervorgängen, der atomar für Entitäten mit demselben PartitionKey-Wert implementiert wird. Wenn ein Speicherungsvorgang in der Entitätsgruppe fehlschlägt, dann werden alle Speichervorgänge für die Gruppe rückgängig gemacht. Eine Entitätsgruppentransaktion umfasst nie mehr als 100 Speichervorgänge und hat eine Maximalgröße von 4 MB. Durch Entitätsgruppentransaktionen erhält der Azure-Tabellendienst eine begrenzte Form der ACID-Semantik (Atomarität, Konsistenz, Isolation, Dauerhaftigkeit) von relationalen Datenbanken. Entitätsgruppentransaktionen verbessern den Durchsatz, da sie die Anzahl einzelner Speicheroperationen verringern, die an den Azure-Tabellendienst übermittelt werden müssen. Sie bieten auch einen wirtschaftlichen Vorteil, weil eine Entitätsgruppentransaktion als einzelner Speichervorgang in Rechnung gestellt wird, unabhängig davon, wie viele Speichervorgänge die Transaktion umfasst. Da alle zu einer Entitätsgruppentransaktion gehörigen Speichervorgänge Entitäten mit demselben PartitionKey-Wert betreffen, kann der Wunsch, Entitätsgruppentransaktionen zu verwenden, für die Wahl des PartitionKey-Werts maßgeblich sein.

Wenn Sie für Entitäten eindeutige PartitionKey-Werte verwenden, dann gehört jede Entität zu einer eigenen Partition. Wenn die von Ihnen verwendeten eindeutigen Werte stetig zunehmen oder abnehmen, dass erstellt Azure möglicherweise Bereichspartitionen. Bereichspartitionen dienen zur Gruppierung von Entitäten mit aufeinander folgenden eindeutigen PartitionKey-Werten, damit Bereichsabfragen schneller ausgeführt werden. Ohne Bereichspartitionen müssten für eine Bereichsabfrage Werte über Partitions- oder Servergrenzen hinweg durchsucht werden, und dies könnte sich nachteilig auf die Abfrageleistung auswirken. Betrachten Sie beispielsweise eine Anwendung, die folgende Tabelle mit einem zunehmenden Sequenzwert für PartitionKey enthält.

 

PartitionKey

RowKey

"0001"

-

"0002"

-

"0003"

-

"0004"

-

"0005"

-

"0006"

-

Azure kann die ersten drei Entitäten in einer Bereichspartition zusammenfassen. Wenn Sie eine Bereichsabfrage auf diese Tabelle anwenden, in der PartitionKey als Kriterium verwendet und die Entitäten von "0001" bis "0003" abgefragt werden, dann wird die Abfrage wahrscheinlich effizient ausgeführt, weil die Entitäten von einem Partitionsserver verarbeitet werden. Es ist nicht garantiert, wann und wie eine Bereichspartition erstellt wird.

Beim Einfügen von Entitäten mit steigenden oder fallenden PartitionKey-Werten kann die Geschwindigkeit der Einfügevorgänge dadurch beeinflusst werden, ob Bereichspartitionen für die Tabelle vorhanden sind. Das Einfügen von Entitäten mit zunehmenden PartitionKey-Werten wird auch Nur-Anhängen-Muster und das Einfügen von Entitäten mit abnehmenden PartitionKey-Werten wird auch Nur-Voranstellen-Muster genannt. Sie sollten in Betracht ziehen, auf die Verwendung dieser Muster zu verzichten, weil der allgemeine Durchsatz von Einfügevorgängen dadurch auf einen einzigen Partitionsserver beschränkt wird. Der Grund hierfür ist, dass beim Vorhandensein von Bereichspartitionen die erste und die letzte (Bereichs-) Partition die kleinsten bzw. größten PartitionKey-Werte enthalten. Daher kann eine neue Entität mit einem sequenziell niedrigeren oder höheren PartitionKey-Wert nur an einer der Endpartitionen eingefügt werden. In der nachfolgenden Abbildung wird eine mögliche Gruppe von Bereichspartitionen für das obige Beispiel dargestellt. Wenn die Entitäten "0007", "0008" und "0009" als Gruppe eingefügt werden sollen, dann würden sie der letzten (orangen) Partition zugewiesen.

Referenzbildschirm

Beachten Sie unbedingt, dass die Leistung nicht beeinträchtigt wird, wenn für Einfügevorgänge unzusammenhängende PartitionKey-Werte verwendet werden.

Im Gegensatz zu einer Tabelle in relationalen Datenbanken, bei der Sie die Indizes verwalten können, können Azure-Tabellen nur einen Index besitzen, der immer aus den Eigenschaften PartitionKey und RowKey besteht. Sie können die Leistung der Tabelle nicht optimieren, indem Sie weitere Indizes hinzufügen oder einen vorhandenen Index ändern, nachdem die Tabelle bereitgestellt wurde. Daher müssen Sie die Daten bereits beim Entwurf der Tabelle analysieren. Im Hinblick auf optimale Skalierbarkeit sowie Abfrage- und Einfügeeffizienz sind vor allem die PartitionKey- und RowKey-Werte zu betrachten. Dieser Artikel konzentriert sich stärker auf die Wahl der PartitionKey-Werte, weil sich diese direkt auf die Partitionierung der Tabelle auswirkt.

Das Festlegen der Partitionsgröße bezieht sich auf die Anzahl der Entitäten, die eine Partition enthält. Wie bereits im Abschnitt "Skalierbarkeit" erwähnt, haben mehr Partitionen einen besseren Lastenausgleich zur Folge. Die Granularität des PartitionKey-Werts wirkt sich auf die Größe der Partitionen aus. Auf der gröbsten Stufe wird ein einzelner Wert als PartitionKey verwendet, sodass sich alle Entitäten in einer einzigen sehr großen Partition befinden. Umgekehrt kann die PartitionKey-Eigenschaft auf der am feinsten unterteilten Stufe für jede Entität einen eindeutigen Wert enthalten. Dies hätte das Ergebnis, dass es für jede Entität eine Partition gibt. Die folgende Tabelle zeigt die Vor- und Nachteile der verschiedenen Granularitäten.

 

PartitionKey-Granularität

Partitionsgröße

Vorteile

Nachteile

Einzelner Wert

Kleine Anzahl von Entitäten

Batchtransaktionen sind mit jeder Entität möglich

Alle Entitäten sind lokal und werden vom selben Speicherknoten verarbeitet

 

Einzelner Wert

Große Anzahl von Entitäten

Entitätsgruppentransaktionen sind u. u. mit jeder Entität möglich. Weitere Informationen zu den Grenzen der Entitätsgruppentransaktionen finden Sie unter http://msdn.microsoft.com/de-de/library/dd894038.aspx.

Die Skalierung ist eingeschränkt.

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

Mehrere Werte

Es sind mehrere Partitionen vorhanden.

Die Partitionsgröße hängt von der Verteilung der Entitäten ab.

Batchtransaktionen sind bei manchen Entitäten möglich.

Dynamische Partitionierung ist möglich.

Einzelanforderungsabfragen sind möglich (keine Fortsetzungstoken)

Lastenausgleich zwischen mehreren Partitionsservern ist möglich

Eine äußerst ungleichmäßige Verteilung der Entitäten über die Partitionen hinweg kann die Leistung von größeren und aktiveren Partitionen beschränken.

Eindeutige Werte

Es gibt viele kleine Partitionen.

Die Tabelle ist äußerst skalierbar.

Bereichspartitionen können die Leistung von partitionsübergreifenden Bereichsabfragen verbessern.

Abfragen, die Bereiche umfassen, können Suchläufe auf mehreren Servern erfordern.

Batchtransaktionen sind nicht möglich.

Nur-Anhängen- oder Nur-Voranstellen-Muster können sich auf den Durchsatz von Einfügevorgängen auswirken.

Diese Tabelle zeigt, wie sich die PartitionKey-Werte auf die Skalierung auswirken. Es empfiehlt sich, kleinere Partitionen zu verwenden, weil sie einen besseren Lastenausgleich ermöglichen. Größere Partitionen können in manchen Szenarien angemessen sein und sind nicht unbedingt nachteilig. Wenn Ihre Anwendung z. B. keine Skalierbarkeit erfordert, dann keine ein einzelne große Partition zweckmäßig sein.

Mit Abfragen werden Daten aus Tabellen abgerufen. Beim Analysieren der Daten für eine Azure-Tabelle muss unbedingt berücksichtigt werden, welche Abfragen in der Anwendung verwendet werden. Wenn eine Anwendung mehrere Abfragen enthält, sollten diese priorisiert werden, selbst wenn Ihre Entscheidung nicht ganz objektiv sein mag. Meist sind dominante Abfragen von anderen Abfragen unterscheidbar. Hinsichtlich der Leistung lassen sich die Abfragen in verschiedene Kategorien unterteilen. Weil eine Tabelle nur einen Index hat, hängt die Abfrageleistung in der Regel von den Eigenschaften PartitionKey und RowKey ab. Die folgende Tabelle bietet einen Überblick über die verschiedenen Abfragetypen und deren Leistungsbewertungen.

 

Abfragetyp

PartitionKey-Übereinstimmung

RowKey-Übereinstimmung

Leistungsbewertung

Point

Genau

Genau

Optimal

Suche in Zeilenbereich

Genau

Teilweise

Besser bei kleinen Partitionen

Schlecht bei sehr großen Partitionen

Suche in Partitionsbereich

Teilweise

Teilweise

Gut, wenn eine kleine Anzahl von Partitionsserver beteiligt ist

Schlechter, wenn mehr Server beteiligt sind

Suche in der gesamten Tabelle

Teilweise, keine

Teilweise, keine

Schlechter, wenn eine Teilmenge der Partitionen durchsucht wird

Am schlechtesten, wenn alle Partitionen durchsucht werden

noteHinweis
Die in der Tabelle definierten Leistungsbewertungen sind relativ zueinander. Die Anzahl und Größe der Partitionen kann schlussendlich die Abfrageleistung bestimmen. Beispielsweise kann die Suche in einem Partitionsbereich für eine Tabelle mit vielen und großen Partitionen ein schlechteres Leistungsverhalten haben als die Suche in der gesamten Tabelle bei einer Tabelle mit wenigen oder kleinen Partitionen.

Die in dieser Tabelle aufgeführten Abfragetypen sind vom Abfragetyp mit der besten Leistungsbewertung bis zum Abfragetyp mit der schlechtesten Leistungsbewertung angeordnet. Punktabfragen sind die besten Abfragetypen, weil hier der gruppierte Index der Tabelle voll genutzt wird. Die folgende Punktabfrage verwendet die Daten aus der Wettlaufregistierungstabelle.

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 Suche im Zeilenbereich und die Suche im Partitionsbereich. Bei der Suche in einem Zeilenbereich wird eine einzelne Partition angegeben. Weil der Vorgang auf einem einzelnen Partitionsserver ausgeführt wird, ist die Suche in einem Zeilenbereich in der Regel effizienter als die Suche in einem Partitionsbereich. Ein wichtiger Faktor für die Leistung von Suchen in einem Zeilenbereich ist, wie selektiv eine Abfrage ist. 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, müssen Sie die Anforderungen an die Häufigkeit und Antwortzeit jeder Abfrage berücksichtigen. Abfragen, die häufig ausgeführt werden, können eine höhere Priorität erhalten. Allerdings kann eine wichtige, aber selten ausgeführte Abfrage eine geringe Wartezeit erfordern, sodass sie in der Prioritätsliste einen Platz weiter oben belegt.

Der Entwurf jeder Tabelle basiert im Kern auf der Skalierbarkeit der Tabelle, den Abfragen, mit denen auf die Tabelle zugegriffen wird, und den Anforderungen an die Speichervorgänge. Die von Ihnen gewählten PartitionKey-Werte bestimmen, wie die Tabelle partitioniert und welcher Typ von Abfragen verwendet werden kann. Speichervorgänge, insbesondere Einfügevorgänge, können sich ebenfalls auf die Wahl der PartitionKey-Werte auswirken. Die PartitionKey-Werte können von einem Einzelwert bis zu eindeutigen Werten reichen und können auch aus mehreren Werten bestehen. Entitätseigenschaften können zusammen den PartitionKey-Wert bilden. Zudem kann der Wert von der Anwendung berechnet werden.

Entwickler sollten zunächst berücksichtigen, ob in der Anwendung Entitätsgruppentransaktionen (Stapelaktualisierungen) verwendet werden. Entitätsgruppentransaktionen erfordern, dass Entitäten denselben PartitionKey-Wert besitzen. Weil die Stapelaktualisierungen für eine gesamte Gruppe ausgeführt werden, kann Auswahl der möglichen PartitionKey-Werte zudem begrenzt sein. Beispielsweise muss eine Banking-Anwendung, die Bargeldtransaktionen verwaltet, Bargeldtransaktionen atomar in die Tabelle einfügen können. Der Grund hierfür ist, dass Bargeldtransaktionen sowohl eine Soll- als auch eine Guthabenseite haben, die sich netto gegeneinander aufrechnen müssen. Diese Anforderung hat zur Folge, dass die Kontonummer nicht Teil des PartitionKey-Werts sein kann, weil für jede Seite der Transaktion verschiedene Kontonummern verwendet werden. Stattdessen bietet sich eine Transaktions-ID eher an.

Die Anzahl und Größe der Partitionen wirken sich auf die Skalierbarkeit einer belasteten Tabelle aus und werden durch die Granularität der PartitionKey-Werte gesteuert. Es kann schwierig sein, den PartitionKey-Wert anhand der Partitionsgröße zu bestimmen, insbesondere wenn die Werteverteilung schwer vorhersagbar ist. Als gute Faustregel gilt, mehrere kleinere Partitionen zu verwenden. Wenn mehrere Tabellenpartitionen vorhanden sind, kann der Azure-Tabellenspeicherdienst die Speicherknoten, in denen die Partitionen verarbeitet werden, leichter verwalten.

Die Wahl eindeutiger oder feiner differenzierter PartitionKey-Werte ergibt viele kleinere Partitionen. Dies ist im Allgemeinen vorteilhaft, weil das System einen Lastenausgleich zwischen diesen Partitionen durchführen und die Last auf viele Partitionen verteilen kann. Allerdings sollten Sie berücksichtigen, wie sich das Vorhandensein vieler Partitionen auf Bereichsabfragen auswirkt, die über Partitionsgrenzen hinweg gehen. Für diesen Abfragetyp müssen mehrere Partitionen zur Beantwortung der Abfrage besucht werden. Es ist möglich, dass die Partitionen über 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, mit denen der nächste Satz von Daten für die Abfrage abgerufen werden kann. Mit anderen Worten, Fortsetzungstoken stellen mindestens eine weitere Anforderungen an den Dienst dar, und dies kann die Gesamtleistung der Abfrage beeinträchtigen. 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 werden die gewünschten Zeilen zurückgegeben. Die Gesamtleistung von Bereichsabfragen kann von der Anzahl der Partitionsserver, die abgefragt werden müssen, und von der Selektivität der Abfrage abhängen. Außerdem sollten Sie die Nur-Anhängen- oder Nur-Voranstellen-Muster beim Einfügen von Daten in Tabellen vermeiden. Die Verwendung eines solchen Musters kann den Durchsatz der Einfügevorgänge selbst dann beschränken, wenn kleine und viele Partitionen erstellt werden. Die Nur-Anhängen- oder Nur-Voranstellen-Muster werden im Abschnitt "Bereichspartitionen" besprochen.

Wenn Sie wissen, welche Abfragen Sie verwenden werden, können Sie bestimmen, welche Eigenschaften Sie als PartitionKey-Werte in Betracht ziehen müssen. Die Eigenschaften, die in den Abfragen verwendet werden, sind Kandidaten für PartitionKey. Die folgende Tabelle enthält allgemeine Richtlinien zur Bestimmung der PartitionKey-Werte.

 

Wenn die Entität...

Aktion

über eine Schlüsseleigenschaft verfügt,

verwenden Sie diese als PartitionKey

über zwei Schlüsseleigenschaften verfügt,

verwenden Sie eine als PartitionKey und die andere als RowKey

mehr als zwei Schlüsseleigenschaften besitzt

verwenden Sie einen zusammengesetzten Schlüssel aus verketteten Werten

Wenn es mehrere gleichermaßen dominante Abfragen gibt, können Sie die Informationen bei Bedarf mehrmals mit verschiedenen RowKey-Werten einfügen. Die sekundären (oder tertiären usw.) Zeilen werden von der Anwendung verwaltet. Diese Muster ermöglicht es Ihnen, die Leistungsanforderungen der Abfragen zu erfüllen. Im folgenden Beispiel werden die Daten aus dem Wettlaufregistrierungsbeispiel verwendet. Es enthält zwei dominante Abfragen. Sie lauten wie folgt:

  • 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 veranschaulicht 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 diese beiden Werte unterscheiden kann.

 

PartitionKey

RowKey

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 die Entitätsgruppentransaktion möglich, weil die PartitionKey-Werte gleich sind. Die Gruppentransaktion sorgt für die Unteilbarkeit des Einfügevorgangs. Es ist zwar möglich, dieses Muster mit verschiedenen PartitionKey-Werten zu verwenden, allerdings wird empfohlen, dieselben Werte zu verwenden, um diesen Vorteil zu erzielen. Andernfalls müssen Sie zusätzliche Logik schreiben, um unteilbare Transaktionen mit verschiedenen PartitonKey-Werten sicherzustellen.

Azure-Tabellen müssen nicht nur Abfragen, sondern auch Speichervorgänge, z. B. Einfügungen, Aktualisierungen und Lösungen, bewältigen. Sie müssen berücksichtigen, welche Art von Speichervorgängen mit welcher Häufigkeit in der Tabelle ausgeführt werden. Wenn diese Vorgänge selten ausgeführt werden, müssen Sie sie u. U. nicht weiter beachten. Bei sehr häufigen Vorgängen, z. B. vielen Einfügungen innerhalb kurzer Zeit, müssen Sie betrachten, wie diese Vorgänge infolge der von Ihnen gewählten PartitionKey-Werte verarbeitet werden. Ein wichtiges Beispiel sind die Nur-Anhängen- oder Nur-Voranstellen-Muster. Diese Muster wurden im vorigen Abschnitt "Bereichspartitionen" erläutert. Wenn das Nur-Anhängen- oder Nur-Voranstellen-Muster verwendet wird, bedeutet dies, dass Sie bei nachfolgenden Einfügungen eindeutige aufsteigende oder absteigende Werte als PartitionKey verwenden. Wenn Sie dieses Muster mit häufigen Einfügevorgängen kombinieren, dann können die Einfügevorgänge in der Tabelle nicht mit hoher Skalierbarkeit verarbeitet werden. Die Skalierbarkeit der Tabelle wird beeinflusst, weil Azure für die Vorgangsanforderungen keinen Lastenausgleich mit anderen Partitionsservern durchführen kann. Daher sollten Sie in diesem Fall die Verwendung von Zufallswerten in Betracht ziehen, z. B. GUID-Werte. Dies ermöglicht kleine Partitionen und gleichzeitig die Durchführung eines Lastenausgleichs während Speichervorgängen.

Wenn der PartitionKey-Wert komplex ist oder mit anderen PartitionKey-Zuordnungen verglichen werden muss, müssen Sie die Tabellenleistung 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 gewünschten PartitionKey-Wert enthält.

  3. Verwenden Sie die Anwendung, um Spitzenbelastungen der Tabelle zu simulieren, und zielen Sie mit dem PartitionKey aus Schritt 2 auf eine einzelne Partition ab. Dieser Schritt ist von Anwendung zu Anwendung verschieden, die Simulation sollte jedoch alle notwendigen Abfragen und Speichervorgänge enthalten. Die Anwendung muss möglicherweise manipuliert werden, damit sie eine einzelne Partition verwendet.

  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 500 Entitäten pro Sekunde beschränkt. Wenn der Durchsatz für eine Partition 500 Entitäten pro Sekunde überschreitet, kann der Server in einer Produktionsumgebung überlastet werden. In diesem Fall sind die PartitionKey-Werte möglicherweise zu grob, sodass nicht genug Partitionen vorhanden sind oder die vorhandenen Partitionen zu groß sind. Sie müssen den PartitionKey-Wert u. U. so verändern, dass die Partitionen über mehrere Server verteilt werden können.

Auf der Partitionsebene tritt ein Lastenausgleich auf, wenn eine Partition überlastet ist, also wenn die Belastung er Partition, genauer gesagt des Partitionsservers, die Zielskalierbarkeit überschreitet. Beim Azure-Speicher gilt für jede Partition ein Skalierbarkeitsziel von 500 Entitäten pro Sekunde. Der Lastenausgleich tritt auch auf der DFS-Ebene oder der Ebene des verteilten Dateisystems auf. Der Lastenausgleich auf der DFS-Ebene betrifft die E/A-Last und ist nicht Gegenstand dieses Artikels. Der Lastenausgleich auf Partitionsebene tritt nicht unmittelbar nach der Überschreitung des Skalierbarkeitsziels auf. Stattdessen wartet das System einige Minuten lang, bevor mit dem Lastenausgleich begonnen wird. Dadurch wird sichergestellt, dass die Partition tatsächlich überlastet ist. Es ist nicht notwendig, Partitionen mit generierten Lasten, die einen Lastenausgleich bewirken, vorzubereiten, weil das System diese Aufgabe automatisch ausführt. Es ist möglich, dass eine Tabelle mit einer bestimmten Last vorbereitet wird und das System dann für die Partitionen anhand der tatsächlichen Last einen Lastenausgleich durchführt, der in einer ganz anderen Verteilung der Partitionen resultiert. Statt Partitionen vorzubereiten, sollten Sie Code schreiben, der Timeout-Fehler und Fehler wegen ausgelasteter Server behandelt. Diese Fehler werden gemeldet, wenn das System einen Lastenausgleich ausführt. Ihre Anwendung kann Spitzenlasten besser bewältigen, wenn Sie mit einer Wiederholungsstrategie auf diese Fehler reagieren. Wiederholungsstrategien werden im folgenden Abschnitt ausführlicher besprochen. Während der Durchführung des Lastenausgleichs ist die Partition einige Sekunden lang offline. Während dieser Offline-Periode weist das System die Partition einem anderen Partitionsserver zu. Beachten Sie unbedingt, dass die Daten nicht von den Partitionsservern gespeichert werden. Stattdessen verarbeiten die Partitionsserver Entitäten von der DFS-Ebene. Weil die Daten nicht auf der Partitionsebene gespeichert werden, können Partitionen schnell auf andere Server verschoben werden. Dadurch werden Ausfallzeiten der Anwendung, sofern vorhanden, stark begrenzt.

Ihre Anwendung muss Fehler bei Speichervorgängen so behandeln, dass keine Datenaktualisierungen verloren gehen. Für manche Fehler ist keine Wiederholungsstrategie erforderlich. Beispielsweise ist bei Aktualisierungen, die den Fehlercode 401 für unbefugte Zugriffe zurückgeben, das Wiederholen nicht vorteilhaft, weil sich der Anwendungsstatus zwischen den Wiederholungsversuchen zum Beheben des Fehlers 401 wahrscheinlich nicht ändern wird. Allerdings stehen bestimmte Fehler, z. B. "Server ausgelastet" oder "Timeout" im Zusammenhang mit den Lastenausgleichsfunktionen von Azure, die Hochverfügbarkeit bereitstellen. Wenn der Speicherknoten, der die Entitäten bedient, überlastet ist, führt Azure einen Lastenausgleich durch, indem Partitionen zu anderen Knoten verschoben werden. Während dieses Zeitraums kann u. U. nicht auf die Partition zugegriffen werden, woraus die Fehler "Server ausgelastet" oder "Timeout" resultieren. Schließlich wird die Partition wieder aktiviert, und die Aktualisierungen können fortgesetzt werden. Die Wiederholungsstrategie eignet sich für Fehler, die durch ausgelastete Server oder Timeouts verursacht werden. In den meisten Fällen können Sie Fehler mit 400-Fehlercode und einige Fehler mit 500-Fehlercode, z. B. Fehler 501 "Nicht implementiert" oder 505 "HTTP-Version wird nicht unterstützt" aus der Wiederholungslogik ausschließen und eine Wiederholungsstrategie für bestimmte 500-Fehler implementieren, wie "Server ausgelastet" (503) der "Timeout" (504).

Es gibt drei gängige Wiederholungsstrategien, die Sie für Ihre Anwendung verwenden können. Es folgt eine Liste dieser Wiederholungsstrategien samt Beschreibungen:

  • Nicht Wiederholen: Es wird kein Wiederholungsversuch unternommen

  • Wiederholungen mit fester Wartezeit: Der Vorgang wird n Male mit einem konstanten Wert für die Wartezeit zwischen den Versuchen wiederholt.

  • Wiederholungen mit exponenzieller Wartezeit: Der Vorgang wird n Male mit einem exponenziellen Wert für die Wartezeit zwischen den Versuchen wiederholt.

Die Keine-Wiederholungen-Strategie ist eine einfache (und ausweichende) Art der Fehlerbehandlung von Vorgängen. Allerdings ist sie nicht sehr hilfreich. Wenn keine Wiederholungsversuche vorgeschrieben werden, besteht offensichtlich das Risiko, dass Daten nach dem Fehlschlagen von Vorgängen nicht ordnungsgemäß gespeichert werden. Daher besteht eine bessere Strategie darin, Wiederholungen mit fester Wartezeit zu verwenden, sodass die Vorgänge nach der gleichen Wartezeit wiederholt werden können. Diese Strategie ist allerdings nicht optimal für hoch skalierbare Tabellen geeignet, weil viele Threads oder Prozesse über denselben Zeitraum hinweg warten müssen und Konflikte auftreten können. Die empfohlene Wiederholungsstrategie verwendet eine exponenzielle Wartezeit, wobei jeder Wiederholungsversuch länger als der letzte Versuch ist. Sie ähnelt dem Konfliktwarnungsalgorithmus, der in Computernetzwerken, z. B. 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

Erläuterungen:

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 in der Rand-Funktion verwendeten Faktoren 0,8 und 1,2 erzeugen eine Varianz zufälliger Größe der Standardwartezeit innerhalb ±20 % des Originalwerts. Der Bereich ±20 % ist für die meisten Wiederholungsstrategien akzeptabel und verhindert weitere Konflikte. Die Formel kann mit dem folgenden Code 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);


Wenn Sie eine Anwendung mit der verwalteten Azure-Bilbliothek erstellen, können Sie die in der Speicherclientbibliothek enthaltenen Wiederholungsrichtlinien nutzen. Der Wiederholungsmechanismus der Bibliothek ermöglicht es Ihnen auch, die Funktionalität durch benutzerdefinierte Wiederholungsrichtlinien zu erweitern. Die RetryPolicies-Klasse im Microsoft.WindowsAzure.StorageClient-Namespace stellt statische Methoden bereit, die ein RetryPolicy-Objekt zurückgeben. Das RetryPolicy-Objekt wird in der TableServiceContext-Klasse in Verbindung mit der SaveChangesWithRetries-Methode verwendet. Die von TableServiceContext-Objekten verwendete Standardrichtlinie ist eine Instanz der RetryExponential-Klasse, die mithilfe von RetryPolicies.DefaultClientRetryCount-Werten und RetryPolicies.DefaultClientBackoff-Werten erstellt wird. Der folgende Code zeigt, wie eine TableServiceContext-Klasse mit einer anderen RetryPolicy-Instanz erstellt wird.

class MyTableServiceContext : TableServiceContext
{
    public MyTableServiceContext(string baseAddress, CloudStorageAccount account)
        : base(baseAddress, account)
    {
        int retryCount = 5; // Default is 3
        var backoff = TimeSpan.FromSeconds(45); // Default is 30 seconds

        RetryPolicy = RetryPolicies.RetryExponential(retryCount, backoff);
    }
    ...
}

Der Azure-Tabellenspeicher erlaubt Anwendungen, riesige Datenmengen zu speichern, weil Partitionen über viele verschiedene Speicherknoten hinweg verwaltet und neu zugewiesen werden. Sie können die Skalierbarkeit einer Tabelle über die Datenpartitionierung steuern. Planen Sie langfristig, wenn Sie ein Tabellenschema definieren, um effiziente Partitionierungsstrategien sicherzustellen. Insbesondere sollten Sie die Anforderungen, die Daten und Abfragen der Anwendung analysieren, bevor Sie PartitionKey-Werte auswählen. Jede Partition kann anderen Speicherknoten zugewiesen werden, während das System auf den Datenverkehr reagiert. Stellen Sie unter Verwendung eines Partitionsbelastungstests sicher, dass die Tabelle über die richtigen PartitionKey-Werte verfügt. Anhand dieses Tests können Sie erkennen, wann Partitionen überlastet sind, und die Partition entsprechend anpassen. Um sicherzustellen, dass die Anwendung zeitweilig auftretende Fehler handhaben kann und dass die Daten dauerhaft gespeichert werden, sollte eine Wiederholungsstrategie mit Wartezeit eingesetzt werden. Die Azure-Speicherclientbibliothek verwendet standardmäßig eine Wiederholungsrichtlinie mit exponenzieller Wartezeit, mit der Konflikte vermieden und der Durchsatz der Anwendung maximiert wird.

Anzeigen:
© 2014 Microsoft