Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Steuern Sie die Häufigkeit, mit der Ihre Anwendung Anforderungen an einen Dienst sendet, damit Sie innerhalb der Einschränkungsgrenzen und der Gesamtkapazität des Diensts bleiben. Dieser Ansatz hilft Ihnen, Drosselungsfehler zu vermeiden oder zu minimieren und den Durchsatz genauer vorherzusagen.
Die Ratelimitierung eignet sich in vielen Szenarien, ist aber besonders hilfreich für sich wiederholende automatisierte Aufgaben wie die Batchverarbeitung.
Kontext und Problem
Die Ausführung einer großen Anzahl von Vorgängen über einen gedrosselten Dienst kann zu mehr Datenverkehr und einem höheren Durchsatzbedarf führen, da Sie sowohl zurückgewiesene Anfragen nachverfolgen als auch diese Vorgänge anschließend erneut versuchen müssen. Da sich die Anzahl der Vorgänge erhöht, kann ein Drosselungslimit mehrere Versuche erfordern, Daten erneut zu senden, was zu einer größeren Leistungseinbuße führt.
Betrachten Sie als Beispiel den folgenden naiven Wiederholungsprozess bei Fehlern für die Aufnahme von Daten in Azure Cosmos DB:
- Von Ihrer Anwendung müssen 10.000 Datensätze in Azure Cosmos DB erfasst werden. Die Erfassung eines einzelnen Datensatzes kostet zehn Anforderungseinheiten (Request Units, RUs), sodass für die Aufgabe insgesamt 100.000 RUs erforderlich sind.
- Für Ihre Azure Cosmos DB-Instanz wurde eine Kapazität von 20.000 RUs bereitgestellt.
- Sie senden alle 10.000 Datensätze an Azure Cosmos DB. 2.000 Datensätze werden erfolgreich geschrieben, und 8.000 Datensätze werden abgelehnt.
- Sie senden die übrigen 8.000 Datensätze an Azure Cosmos DB. 2.000 Datensätze werden erfolgreich geschrieben, und 6.000 Datensätze werden abgelehnt.
- Sie senden die übrigen 6.000 Datensätze an Azure Cosmos DB. 2.000 Datensätze werden erfolgreich geschrieben, und 4.000 Datensätze werden abgelehnt.
- Sie senden die übrigen 4.000 Datensätze an Azure Cosmos DB. 2.000 Datensätze werden erfolgreich geschrieben, und 2.000 Datensätze werden abgelehnt.
- Sie senden die restlichen 2.000 Datensätze an Azure Cosmos DB. Alle Datensätze werden erfolgreich geschrieben.
Der Erfassungsauftrag wurde zwar erfolgreich abgeschlossen, hierzu mussten jedoch 30.000 Datensätze an Azure Cosmos DB gesendet werden, obwohl das gesamte Dataset nur 10.000 Datensätze umfasste.
Im obigen Beispiel müssen noch weitere Faktoren berücksichtigt werden:
- Die Protokollierung einer hohen Anzahl von Fehlern und die Verarbeitung der resultierenden Protokolldaten können ebenfalls zu einem Mehraufwand führen. Bei diesem einfachen Ansatz werden 20.000 Fehler behandelt, und das Protokollieren dieser Fehler könnte Kosten für Verarbeitungs-, Speicher- oder Speicherressourcen verursachen.
- Ohne die Drosselungsgrenzen des Ingestionsdienstes zu kennen, lässt sich bei diesem naiven Ansatz nicht abschätzen, wie lange die Datenverarbeitung dauern wird. Die Ratenbegrenzung ermöglicht Ihnen die Berechnung der für die Erfassung benötigten Zeit.
Solution
Die Ratenbegrenzung kann Ihren Datenverkehr verringern und potenziell den Durchsatz verbessern. Hierzu wird die Anzahl von Datensätzen reduziert, die über einen bestimmten Zeitraum an einen Dienst gesendet werden.
Ein Dienst kann basierend auf verschiedenen Metriken über die Zeit drosseln, z. B.:
- Die Anzahl von Vorgängen (beispielsweise 20 Anforderungen pro Sekunde)
- Die Datenmenge (beispielsweise 2 GiB pro Minute)
- Die relativen Kosten von Vorgängen (beispielsweise 20.000 RUs pro Sekunde)
Unabhängig von der Metrik, die für die Drosselung verwendet wird, umfasst Ihre Implementierung der Ratenbegrenzung die Steuerung der Anzahl und/oder Größe der Vorgänge, die über einen bestimmten Zeitraum an den Dienst gesendet werden, um die Nutzung des Diensts zu optimieren, ohne dessen Drosselungskapazität zu überschreiten.
In Szenarien, in denen Ihre APIs Anforderungen schneller verarbeiten können als gedrosselte Aufnahmedienste zulassen, müssen Sie verwalten, wie schnell Sie den Dienst verwenden. Das Behandeln der Drosselung nur als Datenratenkonflikt und das Puffern von Eingabeanforderungen, bis sich der Dienst erholt, stellt ein Risiko dar. Wenn Ihre Anwendung in diesem Szenario abstürzt, gehen möglicherweise alle gepufferten Daten verloren.
Zur Vermeidung dieses Risikos empfiehlt es sich gegebenenfalls, die Datensätze an ein langlebiges Messagingsystem zu senden, das in der Lage ist, Ihre Erfassungsrate vollständig auszunutzen. (Dienste wie Azure Event Hubs können Millionen von Vorgängen pro Sekunde bewältigen.) Anschließend können Sie einzelne oder mehrere Auftragsprozessoren verwenden, um die Datensätze mit einer kontrollierten Rate, die innerhalb der Grenzwerte des gedrosselten Diensts liegt, aus dem Messagingsystem zu lesen. Die Übermittlung von Datensätzen an das Messagingsystem trägt zur Entlastung des internen Arbeitsspeichers bei, da Sie so die Möglichkeit haben, nur Datensätze aus der Warteschlange zu entnehmen, die während eines bestimmten Zeitintervalls verarbeitet werden können.
Azure bietet mehrere langlebige Messagingdienste, die mit diesem Muster verwendet werden können. Hierzu zählen beispielsweise:
Wenn Sie Datensätze senden, kann der Zeitraum, den Sie zum Freigeben von Datensätzen verwenden, präziser sein als der Zeitraum, auf den die Dienst-Drosselung basiert. Systeme legen Drosselungen häufig anhand von Zeitspannen fest, die man leicht verstehen kann und mit denen man gut arbeiten kann. Für den Computer, auf dem ein Dienst ausgeführt wird, können diese Zeitrahmen jedoch im Vergleich zur schnellen Verarbeitung von Informationen sehr lang sein. So kann ein System beispielsweise pro Sekunde oder pro Minute drosseln, während der Code üblicherweise in der Größenordnung von Nano- oder Millisekunden arbeitet.
Daher wird oftmals empfohlen, häufiger kleinere Datensatzmengen zu senden, um den Durchsatz zu verbessern. Dies ist jedoch nicht zwingend erforderlich. Anstatt also die Batchverarbeitung für eine Veröffentlichung einmal pro Sekunde oder einmal pro Minute auszuführen, können Sie präziser sein als dies, um den Ressourcenverbrauch (Arbeitsspeicher, CPU und Netzwerk) gleichmäßiger zu halten und potenzielle Engpässe aufgrund plötzlicher Anforderungen zu verhindern. Wenn ein Dienst beispielsweise 100 Vorgänge pro Sekunde zulässt, kann ein Ratelimiter die Anforderungen gleichmäßig verteilen, indem er alle 200 Millisekunden 20 Vorgänge freigibt, wie im nachstehenden Diagramm gezeigt.
Darüber hinaus ist es manchmal erforderlich, dass sich mehrere nicht koordinierte Prozesse einen gedrosselten Dienst teilen. In diesem Szenario können Sie zur Implementierung der Ratenbegrenzung die Kapazität des Dienstes logisch aufteilen und anschließend ein verteiltes Mutual-Exclusion-System verwenden, um Exklusivsperren für diese Partitionen zu verwalten. Die nicht koordinierten Prozesse können dann um Sperren für diese Partitionen konkurrieren, wenn sie Kapazität benötigen. Für jede Partition, für die ein Prozess über eine Sperre verfügt, wird ihm eine bestimmte Kapazität erteilt.
Wenn das gedrosselte System beispielsweise 500 Anforderungen pro Sekunde bewältigen kann, können Sie 20 Partitionen mit jeweils 25 Anforderungen pro Sekunde erstellen. Wenn ein Prozess 100 Anfragen stellen müsste, könnte er beim verteilten System für gegenseitigen Ausschluss vier Partitionen anfordern. Das System könnte für zehn Sekunden zwei Partitionen zuweisen. Der Prozess begrenzt daraufhin die Rate auf 50 Anforderungen pro Sekunde, schließt die Aufgabe in zwei Sekunden ab und gibt anschließend die Sperre frei.
Eine Implementierungsmöglichkeit für dieses Muster wäre beispielsweise die Verwendung von Azure Storage. In diesem Szenario wird pro logischer Partition in einem Container ein einzelnes 0-Byte-Blob erstellt. Ihre Anwendungen können dann für einen kurzen Zeitraum (beispielsweise 15 Sekunden) direkt exklusive Leases für diese Blobs beziehen. Für jede einer Anwendung gewährte Lease kann sie die der jeweiligen Partition entsprechende Kapazität nutzen. Die Anwendung muss dann die Leasezeit nachverfolgen, damit die gewährte Kapazität nach Ablauf der Leasezeit nicht weiter beansprucht wird. Bei der Implementierung dieses Musters sollte jeder Prozess häufig versuchen, eine zufällig ausgewählte Partition zu leasen, wenn er Kapazität benötigt.
Zur weiteren Verkürzung der Wartezeit kann für jeden Prozess eine kleine exklusive Kapazitätsmenge zugeordnet werden. Ein Prozess würde dann nur versuchen, ein Nutzungsrecht für gemeinsam genutzte Kapazität zu erhalten, wenn er seine reservierte Kapazität überschreiten müsste.
Als Alternative zu Azure Storage lässt sich diese Art von Leaseverwaltungssystem unter anderem auch mithilfe von Technologien wie Zookeeper, Consul, etcd und Redis/Redsync implementieren.
Probleme und Überlegungen
Beachten Sie bei der Entscheidung, wie dieses Muster implementiert werden soll, Folgendes:
- Das Einschränkungsmuster für die Rate kann zwar die Anzahl der Drosselungsfehler verringern, ihre Anwendung muss jedoch alle möglicherweise auftretenden Drosselungsfehler ordnungsgemäß behandeln.
- Wenn Ihre Anwendung über mehrere Arbeitsstreams verfügt, die auf den gleichen gedrosselten Dienst zugreifen, müssen alle in Ihre Ratenbegrenzungsstrategie einbezogen werden. Vielleicht unterstützen Sie beispielsweise das Massenladen von Datensätzen in eine Datenbank sowie das Abfragen von Datensätzen in der gleichen Datenbank. Sie können die Kapazität verwalten, indem Sie sicherstellen, dass alle Workstreams über denselben Mechanismus zur Ratenbegrenzung gesteuert werden. Alternativ können Sie separate Kapazitätspools für jeden Arbeitsstream reservieren.
- Der gedrosselte Dienst kann in mehreren Anwendungen verwendet werden. Diese Verwendung kann in manchen Fällen koordiniert werden (wie oben gezeigt). Wenn Sie eine größere als erwartete Anzahl von Drosselungsfehlern sehen, kann dies ein Anzeichen für einen Wettbewerb zwischen Anwendungen sein, die auf einen Dienst zugreifen. In diesem Szenario müssen Sie möglicherweise in Betracht ziehen, den Durchsatz Ihres Rate-Limiting-Mechanismus vorübergehend zu reduzieren, bis die Nutzung durch andere Anwendungen sinkt.
Wann dieses Muster verwendet werden sollte
Verwenden Sie dieses Muster für Folgendes:
- Verringern von Drosselungsfehlern, die durch einen gedrosselten Dienst verursacht werden
- Verringern des Datenverkehrs (verglichen mit einem naiven Ansatz vom Typ „Wiederholung bei Fehler“)
- Reduzieren Sie den Speicherverbrauch, indem Datensätze nur dann aus der Warteschlange entnommen werden, wenn Kapazität für ihre Verarbeitung vorhanden ist.
Workloadentwurf
Ein Architekt sollte evaluieren, wie das Rate Limiting-Pattern im Design seiner Workloads verwendet werden kann, um die Ziele und Prinzipien zu erreichen, die in den Azure Well-Architected Framework-Säulen behandelt werden. Beispiel:
| Pillar | So unterstützt dieses Muster die Säulenziele |
|---|---|
| Zuverlässigkeitsdesignentscheidungen tragen dazu bei, dass Ihre Workload ausfallsicher wird und dass sie nach einem Ausfall wieder in einen voll funktionsfähigen Zustand zurückkehrt. | Diese Taktik schützt den Kunden, indem sie die Einschränkungen und Kosten der Kommunikation mit einem Dienst anerkennt und berücksichtigt, wenn der Dienst eine übermäßige Nutzung vermeiden möchte. - RE:07 Selbsterhaltung |
Berücksichtigen Sie wie bei jeder Designentscheidung alle Kompromisse im Hinblick auf die Ziele der anderen Säulen, die mit diesem Muster eingeführt werden könnten.
Example
Mit der folgenden Beispielanwendung können Benutzer verschiedenartige Datensätze an eine API übermitteln. Für die einzelnen Datensatztypen steht jeweils ein individueller Auftragsprozessor zur Verfügung, der folgende Schritte ausführt:
- Validation
- Enrichment
- Hinzufügung des Datensatzes zur Datenbank
Alle Komponenten der Anwendung (API, Auftragsprozessor A und Auftragsprozessor B) sind separate Prozesse, die unabhängig voneinander skaliert werden können. Die Prozesse kommunizieren nicht direkt miteinander.
Dieses Diagramm zeigt den folgenden Workflow:
- Ein Benutzer übermittelt 10.000 Datensätze vom Typ A an die API.
- Die API reiht diese 10.000 Datensätze in die Warteschlange A ein.
- Ein Benutzer übermittelt 5.000 Datensätze vom Typ B an die API.
- Die API reiht diese 5.000 Datensätze in die Warteschlange B ein.
- Der Auftragsprozessor A erkennt, dass die Warteschlange A Einträge enthält, und versucht, eine exklusive Sperre für Blob 2 zu erhalten.
- Der Auftragsprozessor B erkennt, dass Warteschlange B Einträge enthält, und versucht, eine exklusive Lease für Blob 2 zu erwerben.
- Auftragsprozessor A kann die Lease nicht erhalten.
- Auftragsprozessor B erhält die Lease für Blob 2 für 15 Sekunden. Anfragen an die Datenbank können nun auf 100 pro Sekunde begrenzt werden.
- Der Auftragsprozessor B entnimmt 100 Datensätze aus der Warteschlange B und schreibt sie.
- Eine Sekunde vergeht.
- Der Auftragsprozessor A stellt fest, dass Warteschlange A mehr Datensätze enthält, und versucht, eine exklusive Lease auf Blob 6 zu erwerben.
- Der Auftragsprozessor B stellt fest, dass Warteschlange B mehr Datensätze enthält, und versucht, eine exklusive Sperre für Blob 3 zu erhalten.
- Der Auftragsprozessor A erhält die Lease für Blob 6 für 15 Sekunden. Es kann Anfragen an die Datenbank nun auf 100 pro Sekunde begrenzen.
- Der Auftragsprozessor B erhält die Lease für Blob 3 für 15 Sekunden. Es kann nun Datenbankanfragen auf 200 pro Sekunde begrenzen. (Der Prozessor verfügt auch noch über die Lease für das Blob 2.)
- Der Auftragsprozessor A entnimmt 100 Datensätze aus der Warteschlange A und schreibt sie.
- Der Auftragsprozessor B entnimmt 200 Datensätze aus der Warteschlange B und schreibt sie.
- Eine Sekunde vergeht.
- Auftragsprozessor A sieht, dass Warteschlange A mehr Datensätze enthält, und versucht, eine exklusive Lease für Blob 0 zu erlangen.
- Der Auftragsprozessor B stellt fest, dass Warteschlange B mehr Datensätze enthält, und versucht, eine exklusive Sperre für Blob 1 zu erlangen.
- Jobprozessor A erhält die Lease für Blob 0 für 15 Sekunden. Anfragen an die Datenbank können nun auf 200 Anfragen pro Sekunde begrenzt werden. (Der Prozessor verfügt auch noch über die Lease für das Blob 6.)
- Der Auftragsprozessor B erhält die Lease für Blob 1 für 15 Sekunden. Es kann jetzt die Anfragen an die Datenbank auf 300 pro Sekunde begrenzen. (Es verfügt auch über das Leasingrecht für die Blobs 2 und 3.)
- Der Auftragsprozessor A entnimmt 200 Datensätze aus der Warteschlange A und schreibt sie.
- Der Auftragsprozessor B entnimmt 300 Datensätze aus der Warteschlange B und schreibt sie.
- Und so weiter.
Nach 15 Sekunden ist mindestens einer der beiden Aufträge immer noch nicht abgeschlossen. Wenn die Leases ablaufen, muss ein Prozessor auch die Anzahl von Anforderungen verringern, die er aus der Warteschlange entnimmt und schreibt.
Implementierungen dieses Musters sind in verschiedenen Programmiersprachen verfügbar:
Verwandte Ressourcen
Die folgenden Muster und Anweisungen können für die Implementierung dieses Musters ebenfalls relevant sein:
- Throttling. Das hier erläuterte Ratenbegrenzungsmuster wird in der Regel implementiert, um auf einen gedrosselten Dienst zu reagieren.
- Retry. Wenn Anfragen an einen gedrosselten Dienst zu Fehlern aufgrund von Drosselung führen, sollten diese Anfragen im Allgemeinen nach einem geeigneten Intervall wiederholt werden.
Warteschlangenbasierte Lastnivellierung ist ähnlich, unterscheidet sich jedoch in einigen entscheidenden Punkten vom Muster zur Ratenbegrenzung:
- Bei der Ratenbegrenzung muss die Lastverwaltung nicht unbedingt über Warteschlangen erfolgen, es muss aber ein langlebiger Messagingdienst verwendet werden. Für ein Ratenbegrenzungsmuster können beispielsweise Dienste wie Apache Kafka und Azure Event Hubs genutzt werden.
- Das Muster zur Ratenbegrenzung führt das Konzept eines verteilten Systems zum gegenseitigen Ausschluss über Partitionen hinweg ein, mit dem Sie die Kapazität für mehrere unkoordinierte Prozesse verwalten können, die mit demselben gedrosselten Dienst kommunizieren.
- Ein warteschlangenbasiertes Lastenausgleichsmuster kann immer dann verwendet werden, wenn ein Leistungskonflikt zwischen Diensten besteht oder die Resilienz verbessert werden soll. Dies macht es zu einem universelleren Muster als die Ratenbegrenzung, bei der es mehr um den effizienten Zugriff auf einen gedrosselten Dienst geht.