Optimieren Ihrer Azure Cosmos DB-Anwendung mit Ratenbegrenzung

In diesem Artikel wird eine Methodik zur Ratenbegrenzung von Anforderungen an Azure Cosmos DB für Entwickler beschrieben. Die Implementierung dieses Musters kann Fehler reduzieren und die Gesamtleistung für Workloads verbessern, die den bereitgestellten Durchsatz der Zieldatenbank oder des Zielcontainers überschreiten.

Anforderungen, die den bereitgestellten Durchsatz in Azure Cosmos DB überschreiten, können zu vorübergehenden Fehlern wie TooManyRequests, Timeout und ServiceUnavailable führen. In der Regel werden diese Anforderungen erfolgreich wiederholt, wenn Kapazität verfügbar ist. Diese Vorgehensweise kann jedoch zu einer großen Anzahl von Anforderungen führen, die dem Fehlerpfad im Code folgen, was in der Regel zu einem geringeren Durchsatz führt.

Eine optimale Systemleistung, gemessen an Kosten und Zeit, kann erreicht werden, indem der clientseitige Workloaddatenverkehr mit dem serverseitigen bereitgestellten Durchsatz abgeglichen wird.

Betrachten Sie das folgende Szenario:

  • Sie erstellen ein Azure Cosmos DB-Konto mit 20.000 RU/Sekunde.
  • Ihre Anwendung verarbeitet einen Erfassungsauftrag, der 10.000 Datensätze enthält, die jeweils 10 Anforderungseinheiten (Request Units, RUs) kosten. Die erforderliche Gesamtkapazität für diesen Auftrag beträgt 100.000 RU.
  • Sie senden einen Gesamtauftrag an Azure Cosmos DB und erwarten eine große Zahl vorübergehender Fehler und einen großen Puffer mit Anforderungen, die wiederholt werden müssen. Dieser Zustand ist darauf zurückzuführen, dass die Gesamtzahl der für den Auftrag benötigten Anforderungseinheiten (100.000) wesentlich größer als das bereitgestellte Maximum (20.000) ist. Ungefähr 2.000 Datensätze werden von der Datenbank angenommen, ungefähr 8.000 werden jedoch abgelehnt. Bei der Wiederholung senden Sie ungefähr 8.000 Datensätze an Azure Cosmos DB, von denen ungefähr 2.000 angenommen werden, usw. Sie sollten davon ausgehen, dass bei diesem Muster ungefähr 30.000 Datensätze anstelle von 10.000 Datensätzen gesendet werden.
  • Sie entscheiden sich stattdessen dafür, diese Anforderungen gleichmäßig über fünf Sekunden zu senden. Sie sollten jetzt keine Fehler und einen insgesamt schnelleren Durchsatz erwarten, da jeder Batch bei oder unter dem bereitgestellten Maximalwert von 20.000 liegt.

Die Verteilung der Anforderungen auf einen größeren Zeitraum kann durch die Einfügen eines Ratenbegrenzungsmechanismus im Code erreicht werden.

Die für einen Container bereitgestellten RUs werden gleichmäßig auf die Anzahl der physischen Partitionen verteilt. Wenn Azure Cosmos DB im vorherigen Beispiel zwei physische Partitionen bereitgestellt hätte, würde jede Partition 10.000 RU erfassen.

Weitere Informationen zu Anforderungseinheiten finden Sie unter Anforderungseinheiten in Azure Cosmos DB. Weitere Informationen zum Schätzen der Anzahl von RUs, die von Ihrer Workload verbraucht werden, finden Sie in den Überlegungen zu Anforderungseinheiten. Weitere Informationen zum Partitionieren von Azure Cosmos DB finden Sie unter Partitionierung und horizontale Skalierung in Azure Cosmos DB.

Methodik

Eine Methode zum Implementieren der Ratenbegrenzung könnte wie folgt aussehen:

  1. Erstellen Sie ein Anwendungsprofil, damit Sie über Daten zu den verwendeten Schreib- und Leseanforderungen verfügen.
  2. Definieren Sie alle Indizes.
  3. Füllen Sie die Sammlung mit einer angemessenen Menge von Daten (z. B. Beispieldaten). Wenn zu erwarten ist, dass die Anwendung normalerweise Millionen von Datensätzen umfasst, müssen Sie Millionen von Datensätzen vorsehen.
  4. Erstellen Sie maßgebliche Dokumente, und notieren Sie die RU-Kosten.
  5. Führen Sie maßgebliche Abfragen aus, und notieren Sie die RU-Kosten.
  6. Implementieren Sie basierend auf Ihren Ergebnissen eine Funktion in der Anwendung, um die Kosten einer bestimmten Anforderung zu ermitteln.
  7. Implementieren Sie einen Mechanismus zur Ratenbegrenzung in Ihrem Code, um sicherzustellen, dass die Summe aller Vorgänge, die in einer Sekunde an Azure Cosmos DB gesendet werden, den bereitgestellten Durchsatz nicht überschreitet.
  8. Führen Sie einen Auslastungstest für die Anwendung durch, und vergewissern Sie sich, dass der bereitgestellte Durchsatz nicht überschritten wird.
  9. Testen Sie die RU-Kosten regelmäßig erneut, und aktualisieren Sie die Kostenfunktion je nach Bedarf.

Indizierung

Im Gegensatz zu anderen SQL- und NoSQL-Datenbanken, die Sie vielleicht kennen, indiziert die Standardindizierungsrichtlinie von Azure Cosmos DB für neu erstellte Container jede Eigenschaft. Jede indizierte Eigenschaft erhöht die RU-Kosten für Schreibvorgänge.

Die Standardindizierungsrichtlinie kann die Latenz in Systemen mit hoher Leselast senken, in denen die Abfragefilterbedingungen gleichmäßig auf alle gespeicherten Felder verteilt sind. Davon können beispielsweise Systeme profitieren, bei denen Azure Cosmos DB die meiste Zeit für die Bereitstellung von Ad-hoc-Suchvorgängen aufwendet, die von Endbenutzern erstellt werden.

Sie sollten nach Möglichkeit Eigenschaften, die nie durchsucht werden, aus der Indizierung ausschließen. Das Entfernen von Eigenschaften aus dem Index kann die Gesamtleistung des Systems (Kosten und Zeit) für Systeme mit hohem Schreibaufwand und Datensatzabrufmuster mit stärkeren Einschränkungen verbessern.

Vor der Messung von Kosten sollten Sie extra eine geeignete Indexrichtlinie für Ihre Anwendungsfälle konfigurieren. Wenn Sie Indizes später ändern, müssen Sie auch alle Kostenberechnungen erneut ausführen.

Wenn Sie ein System, das sich in Entwicklung befindet, mit einer Last testen, die den typischen Abfragen während Normal- und Spitzenzeiten entspricht, können Sie die am besten geeignete Indizierungsrichtlinie ermitteln.

Weitere Informationen zur Indizes finden Sie in den Indizierungsrichtlinien für Azure Cosmos DB.

Messen der Kosten

Beim Messen der Kosten gibt es einige wichtige Konzepte:

  • Berücksichtigen Sie alle Faktoren, die sich auf die RU-Nutzung auswirken (siehe Beschreibung in den Überlegungen zu Anforderungseinheiten).
  • Alle Lese- und Schreibvorgänge in Ihrer Datenbank oder Ihrem Container teilen sich denselben bereitgestellten Durchsatz.
  • Die RU-Nutzung erfolgt unabhängig von den verwendeten Azure Cosmos DB-APIs.
  • Die Partitionsstrategie für eine Sammlung kann erhebliche Auswirkungen auf die Kosten eines Systems haben. Weitere Informationen finden Sie unter Partitionieren und horizontales Skalieren in Azure Cosmos DB.
  • Verwenden Sie maßgebliche Dokumente und maßgebliche Abfragen.
    • Dies sind Dokumente und Abfragen, die Ihrer Meinung nach im operativen System auftreten werden.
    • Die beste Möglichkeit, diese maßgeblichen Dokumente und Abfragen zu erhalten, besteht darin, die Verwendung der Anwendung zu instrumentieren. Es ist stets besser, eine datengesteuerte Entscheidung zu treffen.
  • Messen Sie die Kosten in regelmäßigen Abständen.
    • Indexänderungen, die Größe der Indizes kann sich auf die Kosten auswirken.
    • Es ist hilfreich, einen wiederholbaren (vielleicht sogar automatisierten) Test für repräsentative Dokumente und Abfragen zu erstellen.
    • Achten Sie darauf, dass die maßgeblichen Dokumente und Abfragen noch maßgeblich sind.

Die Methode zum Ermitteln der Kosten einer Anforderung ist für jede API verschieden:

Schreibanforderungen

Die Kosten von Schreibvorgängen sind in der Regel leicht vorherzusagen. Sie fügen Datensätze ein und dokumentieren die von Azure Cosmos DB gemeldeten Kosten.

Wenn es Dokumente unterschiedlicher Größe und/oder Dokumente gibt, die unterschiedliche Indizes verwenden, ist es wichtig, alle Arten von Dokumenten zu messen. Sie werden vielleicht feststellen, dass die Kosten der repräsentativen Dokumente nahe beieinander liegen, sodass Sie einen einzelnen Wert für alle Schreibvorgänge zuweisen können. Wenn Sie beispielsweise Kosten von 13,14 RU, 16,01 RU und 12,63 RU ermittelt haben, können Sie für die Kosten einen Mittelwert von 14 RU verwenden.

Leseanforderungen

Die Vorhersage der Kosten von Abfragevorgängen kann aus den folgenden Gründen schwieriger sein:

  • Wenn das System benutzerdefinierte Abfragen unterstützt, müssen Sie die eingehenden Abfragen den repräsentativen Abfragen zuordnen, um die Kosten zu ermitteln. Dieser Prozess kann verschiedene Formen annehmen:
    • Es ist vielleicht möglich, die Abfragen exakt zuzuordnen. Wenn es keine direkte Übereinstimmung gibt, müssen Sie möglicherweise die repräsentative Abfrage finden, die am ähnlichsten ist.
    • Vielleicht stellen Sie fest, dass Sie die Kosten basierend auf den Merkmalen der Abfrage berechnen können. Sie könnten beispielsweise feststellen, dass jede Klausel der Abfrage bestimmte Kosten verursacht oder dass eine indizierte Eigenschaft „x“ kostet, während eine nicht indizierte Eigenschaft „y“ kostet usw.
  • Die Anzahl der Ergebnisse kann variieren. Solange Sie keine Statistiken haben, können Sie die RU-Auswirkungen der zurückgegebenen Payload nicht vorhersagen.

Wahrscheinlich können Sie keine Einzelkosten für Abfragevorgänge verwenden, sondern lediglich eine Funktion, die die Abfrage auswertet und die Kosten berechnet. Wenn Sie die API für NoSQL verwenden, können Sie die tatsächlichen Kosten des Vorgangs auswerten und ermitteln, wie genau Ihre Schätzung war (die Optimierung dieser Schätzung kann sogar automatisch im Code erfolgen).

Handhabung vorübergehender Fehler

Die Anwendung benötigt aus den folgenden Gründen weiterhin eine Behandlung vorübergehender Fehler – auch wenn Sie einen Mechanismus zur Ratenbegrenzung implementieren:

  • Die tatsächlichen Kosten einer Anforderung können von den projizierten Kosten abweichen.
  • Vorübergehende Fehler können aus anderen Gründen als TooManyRequests auftreten.

Durch die geeignete Implementierung eines Mechanismus zur Ratenbegrenzung in der Anwendung wird die Anzahl vorübergehender Fehler jedoch erheblich reduziert.

In diesem Artikel werden zwar die clientseitige Koordination und Batchverarbeitung von Workloads beschrieben, es gibt jedoch auch andere Verfahren, mit denen der Gesamtdurchsatz des Systems verwaltet werden kann.

Automatische Skalierung

Bei per Autoskalierung bereitgestelltem Durchsatz ermöglicht Azure Cosmos DB das Skalieren des Durchsatzes (RU/s) Ihrer Datenbank oder Ihres Containers automatisch und sofort. Der Durchsatz wird basierend auf der Nutzung skaliert, ohne dass dadurch Verfügbarkeit, Latenz, Durchsatz oder Leistung der Workload beeinträchtigt werden.

Mittels Autoskalierung bereitgestellter Durchsatz eignet sich gut für unternehmenskritische Workloads, die über variable oder unvorhersehbare Datenverkehrsmuster verfügen und Service Level Agreements (SLAs) für hohe Leistung und Skalierbarkeit erfordern.

Weitere Informationen zur automatischen Skalierung finden Sie unter Erstellen von Azure Cosmos DB-Containern und -Datenbanken mit automatisch skaliertem Durchsatz.

Muster „Warteschlangenbasierter Lastenausgleich“

Sie können eine Warteschlange implementieren, die als Puffer zwischen einem Client und Azure Cosmos DB fungiert, um unregelmäßig auftretende hohe Lasten aufzufangen, die den Ausfall des Diensts oder eine Zeitüberschreitung der Aufgabe verursachen können.

Dieses Muster ist für jede Anwendung hilfreich, die Dienste verwendet, die Überlastung ausgesetzt sind. Dieses Muster ist jedoch nicht hilfreich, wenn die Anwendung eine Antwort vom Dienst mit minimaler Wartezeit erwartet.

Dieses Muster eignet sich oftmals gut für Erfassungsvorgänge.

Weitere Informationen zu diesem Muster finden Sie unter Warteschlangenbasiertes Lastenausgleichsmuster.

Cache-Aside Muster

Sie können erwägen, Daten bei Bedarf in einen Cache zu laden, anstatt jedes Mal Azure Cosmos DB abzufragen. Die Verwendung eines Caches kann die Leistung verbessern und trägt zudem dazu bei, die Konsistenz zwischen den Daten im Cache und den Daten im zugrunde liegenden Datenspeicher aufrechtzuerhalten.

Weitere Informationen finden Sie unter Cachefremdes Muster.

Muster für materialisierte Sichten

Sie könnten Ansichten nach dem Speichern der Daten in Azure Cosmos DB vorab in andere Sammlungen einfüllen, wenn die Daten für erforderliche Abfragevorgänge nicht ideal formatiert sind. Dieses Muster kann für die Unterstützung effizienter Abfragen und Datenextraktionen hilfreich sein und die Leistung verbessern.

Weitere Informationen finden Sie im Abschnitt zur Muster für materialisierte Sichten.