Azure Functions – Der App Service Plan

27. März 2019

Normalerweise wird man Azure Functions nach Verbrauch abrechnen wollen, um Kosten zu sparen. Dies ist jedoch nicht immer möglich.

Im letzten Beitrag ging es um einen grundlegenden Überblick über Azure Functions. In diesem Beitrag soll es um eine der zentralen Entscheidungen gehen, die man zu treffen hat: Die Wahl des App Service Plans.

Azure Functions können nach zwei Arten abgerechnet werden:

Für diesen Plan muss man sich beim Anlegen der Function App entscheiden, er lässt sich nachträglich nicht ändern:

image

Consumption Plan

Der Kostenvorteil beim Consumption Plan – Abrechnung nach Verbrauch + Freikontingent – sollte diesen zur ersten Wahl machen:

image

 

Dazu kommt, dass bei hoher Last ein automatisches Scale Out stattfindet, d.h. dass weitere Instanzen der Function App gestartet werden, wenn nötig.

Folgende Darstellung zeigt die Skalierung innerhalb einer Function App Instanz, sowie über mehrere Instanzen:

 

image

Auf wie viele Instanzen eine einzelne Function innerhalb einer Function App Instanz skaliert, ist dabei abhängig von der Art des Triggers; dies kann durch entsprechende Konfigurationseinträge gesteuert werden. Die Anzahl der Function App Instanzen ist auf 200 “beschränkt”.

Dieser Grad der Skalierbarkeit ist beeindruckend – allerdings gibt es dabei ein paar Einschränkungen und Randbedingungen zu beachten.

imageDie vermutlich gravierendste: Die Laufzeit einzelner Functions ist auf 5 Minuten begrenzt (was per Konfiguration auf maximal 10 Minuten hochgesetzt werden kann) – angedeutet im Bild oben durch die Uhren.

Ein Beispiel aus einem konkreten Projekt: Aus SAP sollen regelmäßig Daten in das eigene System übernommen werden. Diese müssen von SAP abgerufen, nachverarbeitet und in das eigene System eingespielt werden.
In einem solchen Szenario hat man durchaus mit der Zeitbegrenzung zu kämpfen. Schlimmer noch: Die Laufzeit entzieht sich in Teilen der eigenen Kontrolle, da sie durch die Antwortzeiten von SAP bestimmt wird.

Je nach Einsatzzweck ergeben sich weitere Konsequenzen daraus, dass man keine Kontrolle über die verwendeten App Service Instanzen oder den Skalierungsalgorithmus hat. Damit sind Speicher- und Rechenkapazität vorgegeben und man muss mit Latenzzeiten rechnen, bevor neue Instanzen hinzugeschaltet werden. Letzteres merkt man insbesondere nach längerer Inaktivität, wenn zunächst die erste Instanz gestartet werden muss.

Die Dokumentation zählt weitere Begrenzungen auf.

App Service Plan

Wenn ein Consumption Plan aufgrund seiner Beschränkungen nicht in Frage kommt, kann man einen herkömmlichen App Service Plan einsetzen. Dieser kann entsprechend dimensioniert werden:

image

Die Skalierung der App Service Instanzen lässt sich vorgeben oder man verwendet Autoscale:

image

Außerdem besteht in der Function App die Möglichkeit, “Always On” zu setzen, so dass Latenzzeiten nach Inaktivität vermieden werden:

image

Das folgende Schema gibt diese Zusammenhänge wieder:

image

Hinzu kommt, dass Functions dabei keinen Laufzeitbeschränkungen unterliegen.

Der offensichtliche Nachteil eines herkömmlichen App Service Plans sind die Kosten, da hier nicht nach Verbrauch abgerechnet wird.

Nebenbei: Falls man bereits einen App Service Plan für andere App Services hat, so kann man natürlich auch diesen verwenden und so Mehrkosten vermeiden. Wichtig ist nur, dass die Function App überschaubare Last produziert, damit die anderen App Services nicht beeinträchtigt werden.

Außerdem ist die Anzahl der Instanzen auf 20 begrenzt (100 bei “Isolated”).

Kombinationen

Die Wahl des Plans – Consumption oder herkömmlich – sollte sich aus der Kombination der fachlichen Anforderungen und Kosteneffizienz als Randbedingung ergeben. Betrachtet man das für einzelne Teilanforderungen, so kann die jeweilige Antwort durchaus unterschiedlich ausfallen. Das ist aber kein grundsätzliches Problem.

Ich habe zwar eingangs erwähnt, dass man sich bei einer Function App für einen Plan entscheiden muss; es hindert einen aber niemand daran, mehrere Function Apps zu erstellen. Es spricht also nichts dagegen, sich das jeweils Beste herauszugreifen.

Ein Beispiel:

  • Eine Function App mit Consumption Plan für die meisten Functions ohne besondere Anforderungen.
  • Eine Function App mit eigenem App Service Plan für einen langlaufenden Import.

Hier könnte man sogar noch einen Schritt weitergehen: Ein Import wird eher selten laufen, der App Service Plan produziert also unnötig Kosten. Azure Ressourcen lassen sich aber über PowerShell konfigurieren; warum also nicht aus einer Function heraus die “teure” Function App starten und stoppen, wenn sie benötigt wird.

Refactoring

Man kann natürlich immer versuchen seine Fachlogik in kleinere Teilaufgaben zu zerlegen, die von eigenen Functions schnell genug abgearbeitet werden können.

Der oben beschriebene SAP-Import könnte etwa in mehrere Teilimporte zerlegt werden, die ihre Daten zunächst unverarbeitet im Storage ablegen, um Zeit zu sparen. Nachgelagerte Functions könnten dann die Nachverarbeitung durchführen und die Daten in das eigene System einspielen.

Ein solcher Aufbau könnte sich zudem positiv auf die Gesamtlaufzeit auswirken, zumindest wenn sich die Teilaufgaben parallelisiert abarbeiten lassen.

Fazit

Die Wahl des App Service Plans hat Konsequenzen bezüglich der entstehenden Kosten, der Skalierung und der Laufzeit der einzelnen Functions. Erste Wahl sollte immer der Consumption Plan sein – sofern einem die Laufzeit oder besondere Anforderungen keinen Strich durch die Rechnung machen.

Und selbst wenn: Wenn man seine Fachlogik sauber von der Function App trennt (siehe “Best Practices” im letzten Beitrag) kann man sich problemlos unterschiedliche Function Apps erstellen und die Fachlogik in der jeweils adäquaten Function App anbinden.