Deep Dive AWS Lambda – Teil III

Der dritte und letzte Teil dieser Miniserie behandelt „Concurrency“, ein wichtiges Konzept bei Anwendungen, die von AWS Lambda unterstützt werden. Sie erfahren, was Concurrency ist und welche Änderungen Sie an Ihrer Lambda-Funktion diesbezüglich vornehmen können. Außerdem werfen wir einen Blick auf das Monitoring von Lambda-Funktionen. Wie üblich empfehlen wir, die vorangehenden Artikel (Einführung, Deep Dive I & II) gelesen zu haben.

Concurrency

Concurrency ist ein wichtiges Thema in AWS Lambda. Dieser Abschnitt erklärt die Idee hinter Concurrency, warum AWS automatisch „Concurrencylimits“ setzt und wann Concurrency reserviert oder konfiguriert werden sollte.

Unter Concurrency versteht man die gleichzeitige Beantwortung einer bestimmten Anzahl von Anfragen mit einer Lambda-Funktion. Triggert ein Event eine Funktion, wird eine Instanz (nicht zu verwechseln mit einer EC2-Instanz) dieser Funktion erstellt, um die Anfrage zu bedienen. Diese Idee ähnelt sehr dem Konzept von Klassen und Instanzen einer Klasse aus dem Bereich der objektorientierten Programmierung.
Steht zum Zeitpunkt der Anfrage keine freie Instanz der Lambda-Funktion zur Verfügung, wird automatisch eine neue Instanz erzeugt und der Anfrage zugewiesen. Dies erhöht das sog. Concurrency-Level, welches pro Region und Account begrenzt ist (Zur Zeit 1000 Ausführungen pro Konto pro Region). Dieses Limit kann über das AWS Supportcenter erhöht werden. Das Limit schützt Benutzer vor unerwarteten Kosten, die durch rekursiven Code oder andere unbeabsichtigte Aufrufe entstehen. Funktionen, die das Limit überschreiten, werden gedrosselt und Anfragen werden mit dem http-Statuscode 429 (Throtteling) beantwortet.

Um sicherzustellen, dass Funktionen nicht unbeabsichtigt gedrosselt werden, kann Concurrency bis zu einem festgelegten Level für eine Funktion reserviert werden. Hier sollte jedoch im Vorhinein sorgfältig analysiert werden. Reserviert man ein zu niedriges Level wird die Funktion weiterhin gedrosselt. Reserviert man ein zu hohes Level, werden andere Funktion des Accounts in der Region möglichweise gedrosselt.

Die folgende Abbildung veranschaulicht das Prinzip des reservierten Concurrency-Levels. Die beiden Funktionen, my-function-DEV/PROD, verbrauchen einen Teil des Levels, wodurch die verbleibende Kapazität der Region von anderen Lambda-Funktionen genutzt werden kann. Wichtig zu beachten: Die DEV-Funktion stößt an die konfigurierte Grenze und wird gedrosselt.

Src: [1]
  •  Function concurrency
  •  Reserved concurrency
  •  Unreserved concurrency
  •  Throttling

Ein bestimmtes Level für Concurrency zu reservieren ist nützlich, wenn Workloads mit vorhersehbaren Lastspitzen vorliegen oder wenn sichergestellt sein soll, dass eine bestimmte Funktion niemals gedrosselt wird. Falls der anfragende Service ebenfalls selbstverwaltet ist, kann sog. „exponential backoff“, also exponentielles Warten bei Anfragen, in der Anwendung implementiert werden. Hierbei werden exponentiell größer werdende Abstände zwischen einzelnen Anfragen genutzt, so dass die Lambda-Funktionen Zeit genug haben, um bereits gestellte Anfragen abzuarbeiten.

Ein reserviertes Concurrency-Level kann ebenfalls genutzt werden, um Latenzschwankungen bei der Skalierung von Lambda-Funktionen zu vermeiden. Latenzschwankungen treten auf, wenn eine Funktion aus dem „Kaltstart“ aufgerufen wird. Jede neue Instanz der Funktion entspricht einem Kaltstart, bei dem alle Abhängigkeiten des Codes neu geladen werden. Abhängig von der Größe kann dies Zeit in Anspruch nehmen. Daher benötigt jede neue Instanz eine gewisse Zeit, um Anfragen bedienen zu können. Folglich bedient eine „warme“ Instanz Anfragen schneller als neue Instanzen. Durch einen voreingestellten Concurrency-Level wird sichergestellt, dass Anforderungen nach Möglichkeit warme Instanzen verwenden.

Auch die Burst-Verwaltung profitiert von einem voreingestellten Concurrency-Level. Das Concurrency-Level einer Funktion skaliert schrittweise, falls die Funktion an ihre Grenzen stößt. Das verfügbare Level für die entsprechende Funktion wird um 500 pro Minute erhöht. Diese Ausweitung findet solange statt bis die Funktion alle Anfragen erfüllt hat.

Monitoring

Monitoring ist eine integrierte Funktion von AWS Lambda und wird durch AWS CloudWatch realisiert.  Für jede erstellte Funktion sollte jedoch geprüft werden, ob die zugewiesene IAM-Rolle die nötigen Berechtigungen aufweist. AWS Lambda benötigt die folgenden Rechte, um Protokolle in AWS CloudWatch abzulegen:

  • logs:createLogStream
  • logs:PutLogEreignisse
  • logs:CreateLogGroup

Alternativ kann AWS Lambda bei der Erstellung der Funktion eine neue Rolle erstellen. In diesem Fall fügt Lambda der IAM-Rolle automatisch die erforderlichen Berechtigungen hinzu. Die Funktion benötigt diese Berechtigungen, da automatische eine Protokollgruppe erstellt und Protokolldaten zur zusätzlichen Analyse oder Fehlerbehebung in die Protokollgruppe gesendet werden.

Zusätzlich verfügt jede Funktion über eine dedizierte Monitoringskonsole, die über das Kontextmenü der Funktion erreicht werden kann. Die Konsole stellt die folgenden Diagramme zur Verfügung.  (src: https://docs.aws.amazon.com/lambda/latest/dg/monitoring-functions-access-metrics.html):

  • Invocations – Die Anzahl der Aufrufe der Funktion aggregiert in einem 5-Minuten-Zeitraum.
  • Duration – Die durchschnittliche, minimale und maximale Ausführungszeit.
  • Error count and success rate (%) – Die Anzahl der Fehler und der Prozentsatz der fehlerfrei beendeten Ausführungen.
  • Throttles – Die Anzahl der Male, bei denen die Ausführung aufgrund von Concurrencylimits fehlgeschlagen ist.
  • IteratorAge – Werden Datenstreams als Trigger genutzt wird das Alter des letzten Elements im „Stapel“ angezeigt, welches Lambda die Funktion aufgerufen hat.
  • Async delivery failures – Die Anzahl der aufgetretenen Fehler, wenn AWS Lambda versucht hat in eine Ziel- oder Dead-Letter-Queue zu schreiben.
  • Concurrent executions – Die Anzahl der Funktionsinstanzen, die Ereignisse verarbeiten.
  • Concurrency kann in AWS CloudWatch überwacht werden. CloudWatch zeigt die Anzahl der gleichzeitigen Ausführungen in Ihrem Konto pro Region an.

Weitere Informationen müssen in CloudWatch analysiert werden. Jedes Mal, wenn eine Lambda-Funktion durchlaufen wurde, werden die entstanden Logeinträge und Metadaten an CloudWatch gesendet. So können alle Logging-Statements untersucht werden, die während der Verarbeitung der Daten entstehen.

Alternativ können benutzerdefinierte Dashboards erstellt werden. Jedes Element im Dashboard visualisiert Daten in einer der folgenden Kategorien:

  • Je Funktion: Metriken für eine bestimmte Funktion
  • Je Ressourcen: Metriken für eine bestimmte Version oder einen Alias
  • Über alle Funktionen hinweg

Weitere Informationen über Metriken und die Überwachung von Lambda-Funktionen finden sich in der Entwicklerdokumentation [2].

Dies war der letzte Artikel der AWS Lambda-Serie. Wenn Sie Feedback zu der Serie oder Fragen zu AWS Lambda haben, zögern Sie nicht und wenden Sie sich an uns!

[1] https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html
[2] https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html

Weitere Informationen zum Thema (Eng.):