Parallelität in Azure Functions

In diesem Artikel wird das Parallelverhalten von ereignisgesteuerten Triggern in Azure Functions beschrieben. Außerdem werden die statischen und dynamischen Gleichzeitigkeitsmodelle miteinander verglichen.

Wichtig

Der Flex-Verbrauchstarif befindet sich derzeit in der Vorschau.

In Azure Functions können Sie mehrere Prozesse einer bestimmten Funktion gleichzeitig auf einer einzigen Recheninstanz ausführen lassen. Nehmen Sie zum Beispiel an, dass Sie drei verschiedene Funktionen in Ihrer Funktionsanwendung haben, die auf mehrere Instanzen skaliert wird, um eine erhöhte Last zu bewältigen. In diesem Szenario wird jede Funktion als Reaktion auf einzelne Aufrufe in allen drei Instanzen ausgeführt, und eine bestimmte Instanz kann mehrere Aufrufe desselben Typs verarbeiten. Beachten Sie, dass die Funktionsausführungen auf einer einzelnen Instanz die gleichen Speicher-, CPU- und Verbindungsressourcen nutzen. Da auf jeder Instanz mehrere Funktionsausführungen gleichzeitig laufen können, muss jede Funktion über eine Möglichkeit verfügen, die Anzahl der gleichzeitigen Ausführungen zu verwalten.

Wenn Ihre Anwendung in einem dynamischen Skalierungsplan (Verbrauch, Flex-Verbrauch oder Premium) gehostet wird, skaliert der Hoster die Anzahl der Funktionsanwendungsinstanzen entsprechend der Anzahl der eingehenden Ereignisse nach oben oder unten. Weitere Informationen finden Sie unter Ereignisgesteuerte Skalierung. Wenn Sie Ihre Funktionen in einem dedizierten Plan (App Service) hosten, müssen Sie Ihre Instanzen manuell konfigurieren oder ein Schema für die automatische Skalierung einrichten.

Diese Skalierungsentscheidungen werden auch direkt von der Gleichzeitigkeit der Ausführungen auf einer bestimmten Instanz beeinflusst. Wenn eine Anwendung in einem dynamischen Skalierungsplan eine Gleichzeitigkeitsgrenze erreicht, muss sie möglicherweise skaliert werden, um mit der eingehenden Nachfrage Schritt zu halten.

Azure Functions bietet zwei Hauptmethoden zur Verwaltung der Gleichzeitigkeit:

  • Statische Parallelität: Sie können Grenzwerte auf Hostebene für die Parallelität konfigurieren, die spezifisch für einzelne Auslöser sind. Dies ist das standardmäßige Parallelitätsverhalten für Azure Functions.

  • Dynamische Parallelität: Bei bestimmten Auslösertypen kann der Host von Azure Functions automatisch die beste Parallelitätsstufe für diesen Trigger in Ihrer App ermitteln. Sie müssen sich für dieses Parallelitätsmodell abonnieren.

Statische Parallelität

Standardmäßig unterstützen die meisten Auslöser ein statisches Konfigurationsmodell auf Hostebene. In diesem Modell hat jeder Auslösertyp einen Parallelitätsgrenzwert für jede Instanz. Für die meisten Auslöser können Sie jedoch auch eine bestimmte Parallelität pro Instanz für diesen Auslösertyp anfordern. Beispielsweise stellt der Service Bus-Trigger sowohl eine MaxConcurrentCalls als auch eine MaxConcurrentSessions Einstellung in der Datei host.json zur Verfügung. Diese Einstellungen steuern zusammen die maximale Anzahl von Nachrichten, die jede Funktion gleichzeitig auf jeder Instanz verarbeitet. Andere Triggertypen verfügen über integrierte Mechanismen für den Instanzübergreifenden Lastenausgleich von Aufrufen. Beispielsweise verwenden Event Hubs und Azure Cosmos DB ein partitionsbasiertes Schema.

Bei Auslösertypen, die eine Parallelitätskonfiguration unterstützen, werden die von Ihnen gewählten Einstellungen auf alle laufenden Instanzen angewendet. So können Sie die maximale Parallelität für Ihre Funktionen auf jeder Instanz steuern. Wenn Ihre Funktion beispielsweise CPU- oder ressourcenintensiv ist, können Sie die Parallelität einschränken, um Ihre Instanzen fehlerfrei zu halten, und sich auf die Skalierung verlassen, um erhöhte Lasten zu bewältigen. Sie sollten gegebenenfalls auch beim Senden von Anforderungen an einen Downstreamdienst, der gedrosselt wird, die Parallelität einschränken, um eine Überlastung des Downstreamdiensts zu vermeiden.

HTTP-Auslöserparallelität

Gilt nur für den Flex-Verbrauchsplan (Vorschau)

Der Flex-Verbrauchsplan skaliert alle HTTP-Auslöserfunktionen als Gruppe. Weitere Informationen finden Sie unter Skalierung pro Funktion. Die folgende Tabelle zeigt die standardmäßige Parallelitätseinstellung für HTTP- Auslöser auf einer bestimmten Instanz, basierend auf der konfigurierten Instanzspeichergröße.

Instanzgröße (MB) Standardparalelität*
2048 16
4096 32

*Bei Python-Apps ist die standardmäßige Parallelität für HTTP-Auslöser für alle Instanzengrößen 1.

Diese Standardwerte sollten für die meisten Fälle ausreichen, und sie sind am Anfang standardmäßig festgelegt. Bedenken Sie, dass bei einer bestimmten Anzahl von HTTP-Anforderungen eine Erhöhung des HTTP- Parallelitätswertes die Anzahl der für die Bearbeitung von HTTP-Anforderungen erforderlichen Instanzen reduziert. Ebenso erfordert eine Verringerung des HTTP- Parallelitätswertes mehr Instanzen, um die gleiche Last zu bewältigen.

Wenn Sie eine Feinabstimmung der HTTP- Parallelität vornehmen müssen, können Sie dies mit der Azure-Befehlszeilenschnittstelle tun. Weitere Informationen finden Sie unter Festlegen von HTTP-Parallelitätsgrenzwerten.

Die standardmäßigen Werte für Parallelität in der vorherigen Tabelle gelten nur, wenn Sie ihre eigene HTTP-Parallelitätseinstellung nicht festgelegt haben. Wenn Sie eine HTTP-Parallelitätseinstellung nicht explizit festgelegt haben, wird die Standardparallelität wie in der Tabelle gezeigt erhöht, wenn Sie die Instanzgröße ändern. Nachdem Sie einen HTTP-Parallelitätswert spezifisch festgelegt haben, wird dieser Wert trotz Änderungen der Instanzgröße beibehalten.

Bestimmen der optimalen statischen Parallelität

Mit statischen Parallelitätskonfigurationen können Sie zwar bestimmte Triggerverhalten steuern, z. B. die Drosselung Ihrer Funktionen, aber es kann schwierig sein, die optimalen Werte für diese Einstellungen zu bestimmen. In der Regel müssen Sie über einen iterativen Prozess zu akzeptablen Werten der Auslastungstests gelangen. Selbst nachdem Sie eine Reihe von Werten festlegen, die für ein bestimmtes Lastprofil geeignet sind, kann sich die Anzahl der Ereignisse, die von den verbundenen Diensten eingehen, von Tag zu Tag ändern. Diese Variabilität bedeutet, dass Ihre App häufig mit suboptimalen Werten ausgeführt wird. Beispielsweise kann Ihre Funktions-App besonders anspruchsvolle Nachrichtennutzlasten am letzten Tag der Woche verarbeiten. Daher müssen Sie die Parallelität drosseln. Während der restlichen Woche sind die Nachrichtennutzlasten jedoch einfacher, was bedeutet, dass Sie für den Rest der Woche eine höhere Parallelitätsstufe verwenden können.

Im Idealfall soll das System es den Instanzen ermöglichen, so viel Arbeit wie möglich zu verarbeiten, während jede Instanz fehlerfrei bleibt und die Latenzen gering bleiben.Das ist wofür die dynamischen Parallelität entwickelt wurde.

Dynamische Parallelität

Functions bietet jetzt ein dynamisches Parallelitätsmodell, das die Konfiguration der Parallelität für alle Funktions-Apps vereinfacht, die im gleichen Plan ausgeführt werden.

Hinweis

Dynamische Parallelität wird derzeit nur für Azure-Blob-, Azure Queue- und Service Bus-Trigger unterstützt und erfordert, dass Sie die Versionen verwenden, die im Abschnitt zur Erweiterungsunterstützung unten aufgeführt werden.

Vorteile

Die Verwendung der dynamischen Parallelität bietet die folgenden Vorteile:

  • Eine vereinfachte Konfiguration: Sie müssen die Parallelitätseinstellungen pro Trigger nicht mehr manuell bestimmen. Das System lernt im Laufe der Zeit die optimalen Werte für Ihre Workload.
  • Dynamische Anpassungen: Parallelität wird dynamisch in Echtzeit nach oben oder unten angepasst. Dadurch kann das System im Laufe der Zeit die sich ändernden Auslastungsmuster übernehmen.
  • Der Instanz-Integritätsschutz: Die Runtime schränkt die Parallelität auf Ebenen ein, die eine Funktions-App-Instanz bequem verarbeiten kann. Dies schützt die App davor, sich selbst zu überlasten, indem sie mehr Arbeit auf sich nimmt, als sie sollte.
  • Ein Verbesserter Durchsatz: Der Gesamtdurchsatz wird verbessert, da die einzelnen Instanzen nicht mehr Arbeit bewältigen müssen, als sie schnell verarbeiten können. Das ermöglicht einen effektiveren Lastenausgleich über Instanzen hinweg. Bei Funktionen, die höhere Lasten bewältigen können, kann ein höherer Durchsatz erzielt werden, indem die Parallelität auf Werte oberhalb der Standardkonfiguration erhöht wird.

Konfigurationen für die Dynamische Parallelität

Die Dynamische Parallelität kann auf der Hostebene in der Datei host.json aktiviert werden. Wenn diese Funktion aktiviert ist, werden die Parallelitätsstufen aller Bindungserweiterungen, die diese Funktion unterstützen, bei Bedarf automatisch angepasst. In diesen Fällen haben die dynamischen Einstellungen für die Parallelität Vorrang vor allen manuell konfigurierten Einstellungen für die Parallelität.

Standardmäßig ist die dynamische Parallelität deaktiviert. Bei aktivierter dynamischer Parallelität beginnt die Parallelität für jede Funktion bei 1 und wird auf einen optimalen Wert angepasst, der vom Host bestimmt wird.

Sie können die dynamische Parallelität in Ihrer Funktions-App aktivieren, indem Sie die folgenden Einstellungen der Datei „host.json“ hinzufügen:

    { 
        "version": "2.0", 
        "concurrency": { 
            "dynamicConcurrencyEnabled": true, 
            "snapshotPersistenceEnabled": true 
        } 
    } 

Wenn der Standardwert SnapshotPersistenceEnabledtrue entspricht, werden die gelernten Parallelitätswerte in regelmäßigen Abständen gespeichert. Somit können die neuen Instanzen mit diesen Werten beginnen, anstatt bei 1 und das Lernen wiederholen zu müssen.

Parallelitäts-Manager

Wenn die dynamische Parallelität aktiviert ist, läuft hinter den Kulissen ein Parallelitäts-Verwaltungsprozess im Hintergrund. Dieser Verwalter überwacht ständig die Integritätsmetriken für Instanzen, wie z. B. die CPU- und Threadauslastung und ändert die Drosselungen bei Bedarf. Wenn eine oder mehrere Drosselungen aktiviert sind, wird die Funktionsparallelität nach unten angepasst, bis der Host wieder fehlerfrei ist. Wenn Drosselungen deaktiviert sind, kann die Parallelität erhöht werden. Verschiedene Heuristiken werden verwendet, um die Parallelität basierend auf diesen Drosselungen intelligent nach oben oder unten anzupassen. Im Laufe der Zeit wird die Parallelität für jede Funktion auf eine bestimmte Ebene stabilisiert.

Die Parallelitätsebenen werden für jede einzelne Funktion verwaltet. Daher wird das System zwischen ressourcenintensiven Funktionen, die eine geringe Parallelität erfordern und einfacheren Funktionen, die eine höhere Parallelität verarbeiten können, ausgeglichen. Das Gleichgewicht der Parallelität für jede Funktion hilft, die allgemeine Integrität der Funktions-App-Instanz zu erhalten.

Wenn die dynamische Parallelität aktiviert ist, werden die dynamischen Parallelitätsentscheidungen in Ihren Protokollen angezeigt. Beispielsweise werden Protokolle angezeigt, wenn verschiedene Drosselungen aktiviert sind und wann immer die Parallelität für jede Funktion nach oben oder unten angepasst wird. Diese Protokolle werden in der Ablaufverfolgungstabelle unter der Protokollkategorie Host.Concurrency geschrieben.

Unterstützung für Erweiterung

Die dynamische Parallelität ist für eine Funktions-App auf der Hostebene aktiviert und alle Erweiterungen, die die dynamische Parallelität unterstützen, werden in diesem Modus ausgeführt. Die dynamische Parallelität erfordert die Zusammenarbeit zwischen dem Host und den einzelnen Triggererweiterungen. Nur die aufgeführten Versionen der folgenden Erweiterungen unterstützen die dynamische Parallelität.

Erweiterung Version Beschreibung
Queue Storage Version 5.x (Speichererweiterung) Der Azure Queue Storage-Trigger verfügt über eine eigene Schleife zum Abfragen von Nachrichten. Bei Verwendung der statischen Konfiguration wird Parallelität durch die BatchSize/NewBatchThreshold-Konfigurationsoption bestimmt. Bei Verwendung dynamischer Parallelität werden diese Konfigurationswerte ignoriert. Dynamische Parallelität ist in die Nachrichtenschleife integriert, sodass die Anzahl der pro Iteration abgerufenen Nachrichten dynamisch angepasst wird. Wenn Drosselung aktiviert ist (Host ist überlastet), wird die Nachrichtenverarbeitung angehalten, bis Drosselung deaktiviert wird. Wenn Drosselungen deaktiviert sind, kann die Parallelität erhöht werden.
Blob Storage Version 5.x (Speichererweiterung) Intern verwendet der Azure Blob Storage-Trigger die gleiche Infrastruktur wie der Azure-Warteschlangentrigger. Wenn neue/aktualisierte Blobs verarbeitet werden müssen, werden Nachrichten in eine durch die Plattform verwaltete Steuerungswarteschlange geschrieben, und diese Warteschlange wird mit der gleichen Logik verarbeitet, die auch für QueueTrigger verwendet wird. Wenn dynamische Parallelität aktiviert ist, wird Parallelität für die Verarbeitung dieser Steuerungswarteschlange dynamisch verwaltet.
Service Bus Version 5.x Der Service Bus Trigger unterstützt derzeit drei Ausführungsmodelle. Die dynamische Parallelität wirkt sich wie folgt auf diese Ausführungsmodelle aus:

Verarbeitung einzelner Dispatch-Themen/Warteschlangen: Jeder Aufruf Ihrer Funktion verarbeitet eine einzelne Nachricht. Bei Verwendung der statischen Konfiguration wird Parallelität durch die MaxConcurrentCalls-Konfigurationsoption bestimmt. Bei Verwendung der dynamischen Parallelität wird dieser Konfigurationswert ignoriert und die Parallelität wird dynamisch angepasst.
Sitzungsbasierte Verarbeitung einzelner Dispatch-Themen/Warteschlangen: Jeder Aufruf Ihrer Funktion verarbeitet eine einzelne Nachricht. Abhängig von der Anzahl der aktiven Sitzungen für Ihr Thema / Ihre Warteschlange least jede Instanz eine oder mehrere Sitzungen. Nachrichten in jeder Sitzung werden seriell verarbeitet, um die Reihenfolge in einer Sitzung zu gewährleisten. Wenn keine dynamische Parallelität verwendet wird, wird die Parallelität durch die MaxConcurrentSessions-Einstellung bestimmt. Wenn dynamische Parallelität aktiviert ist, wird MaxConcurrentSessions ignoriert, und die Anzahl der Sitzungen, die von jeder Instanz verarbeitet werden, wird dynamisch angepasst.
Batchverarbeitung: Bei jedem Aufruf Ihrer Funktion wird ein Nachrichtenbatch verarbeitet, der durch die Einstellung MaxMessageCount bestimmt wird. Da Batchaufrufe seriell sind, ist die Parallelität für Ihre durch den Batch ausgelöste Funktion immer eins und die dynamische Parallelität gilt nicht.

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Ressourcen: