PCG logo
Artikel

AWS Lambda: Vermeiden Sie diese Fallstricke

Inmitten des riesigen Angebots an AWS-Cloud-Services sticht AWS Lambda als benutzerfreundliche, “serverless” Computing-Plattform hervor, mit der Sie Ihre Anwendungen ausführen können, ohne dass Sie Server bereitstellen oder verwalten müssen.

Ein großartiges Angebot, um schnell Ergebnisse zu erzielen, aber wie jedes gute Tool muss es richtig eingesetzt werden. Ich bin durch die weitläufige Lambda-Landschaft gewandert und hin und wieder gestolpert.

AWS Lambda: einfach zu nutzen, schwer zu meistern

Innovativ zu sein geht oft mit Fehlern einher, und in der Tat habe ich im Bereich von AWS Lambda schon einiges erlebt. Sehen wir uns meine persönlichen Top-Fehltritte an.

Lambda-Konfigurationen mit maximaler Leistung

Beim Testen von neu erstellten Lambda-Funktionen stößt man oft auf das gleiche Problem. Der Standard-Timeout-Wert beträgt 3 Sekunden und reicht oft nicht aus. Eine schnelle Lösung besteht darin, den Wert auf das Maximum von 15 Minuten zu erhöhen. Gleiches gilt für den RAM-Speicher: Wenn zu viele Daten geladen werden, bricht die Funktion ab, weil der Speicher ausgelastet ist. Auch hier kann das Problem schnell gelöst werden, indem man den RAM-Speicher auf das Maximum erhöht. 

Die Gefahr: Sie merken nicht, falls Lambda-Funktionen ineffizient programmiert sind. Setzen Sie stattdessen die Limits so, dass ungewöhnliches Verhalten zu einem Absturz führt. Das ist aus Kostensicht (und übrigens auch aus Security-Sicht) deutlich besser und nachhaltiger.

Nutzen Sie eine Testumgebung mit den gleichen Werten wie in der Produktivumgebung und verwenden Sie Lasttests mit Referenzdaten, um anschließend mithilfe von AWS CloudWatch die richtigen Werte für Ihre Lambda-Konfiguration zu ermitteln.

“Reserved Concurrency” gleichgesetzt mit “Provisioned Concurrency”

Zu Beginn meiner Arbeit nahm ich naiverweise an, dass “Reserved Concurrency” gleichbedeutend mit “Provisioned Concurrency” sei. Da hätte ich mich nicht mehr täuschen können. Beide Mechanismen bestimmen die Skalierung Ihrer Lambda-Funktionen, allerdings mit einem unterschiedlichen Ziel:

“Reserved Concurrency”

Jeder AWS Account hat eine Accountweite Limitierung (Soft Limit) der maximal, gleichzeitig aktiven Lambda Funktionen - abhängig von der ausgewählten Region. Ist dieses Limit einmal erreicht, kann keine weitere Lambda-Funktion gestartet werden, bis sich eine andere beendet.

Bei automatischer Skalierung kann dieses Limit schneller erreicht werden, als man denkt, insbesondere wenn man AWS SQS nutzt. Mit einer “Reserved Concurrency” kann ich einzelnen Lambda Funktionen eine beliebige Anzahl an Instanzen reservieren, sodass diese immer gestartet werden können, egal wie hoch die Auslastung sonst ist. Allerdings ist die Funktion gleichzeitig auch auf diese Anzahl im Maximum beschränkt.

Wichtig zu verstehen: diese Reservierung ist auf der anderen Seite nicht mehr für andere Lambda Funktionen verfügbar. Sie wird also vom Gesamtkontingent des Accounts abgezogen. Das folgende Bild veranschaulicht die Funktionsweise:

image-e7bde1ad4029

Quelle: https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html

“Provisioned Concurrency”

Bei diesem Wert geht es darum, wie viele Instanzen der Funktion dauerhaft “warm” gehalten werden - also initialisiert sein - sollen. Somit lässt sich die Initialisierungsphase grundsätzlich überspringen.

image-7a1b48e7e721

Quelle: https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html

Dieser Wert kann ein Quick-Win für die Performance sein, erhöht aber auch die Kosten. Mal ehrlich: “serverless” nutzen, um vom “Pay-as-you-use”-Konzept zu profitieren, nur um dann doch die eigenen Funktionen dauerhaft bereit zu stellen und dafür zu bezahlen? Das sollte man sich gut überlegen.

Übrigens: Mit der Veröffentlichung von “Lambda SnapStartExternal Link” ist das Problem von Kaltstarts ohnehin gelöst.

Lastspitzen mit erhöhter “Provisioned Concurrency” abfangen

Im Zuge meiner Projekte kam es schon vor, dass wir besonders hohe Lastspitzen abfangen mussten, ohne dass wir noch die Zeit hatten, Code-Optimierungen vorzunehmen. Leider bietet es sich extrem an, diesem Problem mit einer enormen Anzahl von “Provisioned Concurrency” zu begegnen, da somit ein enormer Performance-Zuwachs generiert werden kann. Ganz ohne Aufwand.

Dennoch sollte man dieses Vorgehen gut überdenken: Die Mehrkosten, die hierdurch entstehen, können enorm sein. Noch wichtiger: Das Problem ist hiermit nicht nachhaltig behoben. Es ist wichtiger, seine Architektur entsprechend anzupassen, um Lastspitzen auch ohne diesen “Trick” bewältigen zu können.

“Reserved Concurrency” für jede Lambda Funktion

Ein oft gemachter Anfängerfehler ist, jeder Lambda Funktion eine eigene “Reserved Concurrency” zuzuweisen. Es scheint die logische Konsequenz zu sein, nachdem man verstanden hat, was dieser Wert bewirkt.

In Wirklichkeit braucht nicht jede Funktion diesen Wert - im Gegenteil. Die Zuweisung von “Reserved Concurrency” hat zum einen Auswirkungen auf den gesamten AWS Account und ist gleichzeitig nicht zentral einsehbar. Es gibt keine Übersicht welche Funktionen wie viel der Reservierung in Anspruch nehmen - da kann man schnell falsche Konfigurationen vornehmen.

Also: “Reserved Concurrency” bitte nur für absolut kritische Lambda-Funktionen verwenden, die auf jeden Fall funktionieren müssen. Diese Konfiguration sollte dann zentral in Ihrem System dokumentiert sein, um einen Überblick zu gewährleisten. Alle anderen Funktionen können über AWS Step-Functions bzw. Dienste wie SQS verwaltet werden. Diese Dienste warten automatisch ab, falls die Accountweite Grenze erreicht wurde und starten die Funktion automatisch, sobald wieder Kapazität verfügbar ist.

Direkte und synchrone Aufrufe zwischen Lambda Funktionen

Wenn man mit der Verwendung von AWS Lambda Funktionen durchstartet, bietet es sich absolut an, Lambda Funktionen direkt miteinander zu verbinden. Im Klartext: Eine Lambda Funktion ruft eine andere Lambda Funktion auf und wartet auf die Verarbeitung, um dann damit weiter zu arbeiten.

Obwohl einfach zu implementieren, ist dieser Ansatz absolut zu vermeiden. Folgende Probleme entstehen durch Direktaufrufe:

  • Die aufrufende Lambda Funktion muss “aktiv warten”, es entstehen also unnötige Kosten
  • Die aufrufende Lambda Funktion selbst hat weiterhin ihren eigenen Timeout. Es besteht also die Möglichkeit, dass sich diese Lambda Funktion selbst beendet, während die andere noch arbeitet.
  • In diesem Fall würde die aufgerufene Funktion trotzdem bis zum Schluss arbeiten, das Ergebnis kann jedoch nicht mehr zurückgegeben werden und verschwindet schließlich.
  • Eine Skalierung ist nicht gewährleistet: Sollte die aufgerufene Funktion keine verfügbare “concurrency” mehr haben, kann sie nicht starten.

Auch in diesem Fall ist die Lösung: Nutzen Sie AWS Step Functions oder asynchrone Aufrufe mit der Hilfe von AWS SQS.

AWS SQS: “Batch Size” auf 1 limitiert

Wir haben nun einige Fälle gesehen, die durch den Einsatz von AWS SQS deutlich besser funktionieren würden. Genau hier gibt es aber einen weiteren oft gemachten Fehler: die Einstellung der “Batch Size”.

Diese Einstellung reguliert wie viele Nachrichten die SQS Queue gleichzeitig an eine einzelne Lambda Funktion geben darf. Hieraus ergeben sich gleich mehrere Aspekte:

  • Nachrichten, die an eine AWS SQS Queue gesendet werden, sollten grundsätzlich immer eine einzelne Aufgabe darstellen. Vermeiden Sie es unbedingt, beispielsweise ein JSON Array aus mehreren Aufgaben als Nachricht zu schicken. Denn…
  • …genau hierfür gibt es die AWS SQS Einstellung “Batch Size”: diese packt mehrere Nachrichten zusammen und schickt sie an die entsprechende Lambda Funktion
  • Nicht zu unterschätzen: der Code der Lambda Funktion muss dafür ausgelegt sein. Je nach Anwendungsfall ist es mit einigem Aufwand verbunden die eigene Lambda Funktion zu befähigen mehrere Anfragen nacheinander abzuarbeiten (Caching, bereits initialisierte Variablen, etc.)
  • Bitte bedenken Sie den Timeout, den Sie benötigen, um mit einer entsprechenden Batch-Size umzugehen. Ihre Funktion benötigt für eine Aufgabe 1 Minute? Dann wird sie für 5 Aufrufe vermutlich länger brauchen.
    • Aber Vorsicht: Wie bereits besprochen, nicht den Fehler machen, den Timeout einfach auf 15 Minuten zu stellen.
  • Sollte eine Lambda Funktion inmitten eines Batch-Auftrages beendet werden (Timeout, Code-Fehler, etc.), nimmt die SQS Queue alle Nachrichten zurück in die Queue. Sie merken: Es ist sehr wichtig, dass Lambda Funktionen stets nachvollziehen können, ob Aufgaben bereits verarbeitet wurden oder nicht, um Mehrfachbearbeitung zu vermeiden.

AWS Lambda Code für Orchestrierung

Ich sehe immer wieder Lambda-Funktionen, die dafür genutzt werden, auf einen gewissen Status oder Wert zu warten, um darauf zu reagieren. Offensichtlich ist Lambda dafür nicht gedacht. Die Funktion verursacht durchgehend Kosten und ist gleichzeitig auf bis zu 15 Minuten Timeout begrenzt.

Bitte vermeiden Sie es, Lambda Funktionen für diesen Zweck zu nutzen. “Lambda Trigger” bzw. AWS Step Functions können eine sinnvolle Alternative sein.

AWS Lambda “Reverse Calling”

Ist der Timeout von 15 Minuten einfach zu wenig? Wie wäre es dann, wenn wir im Code mit berechnen, wie lange die Funktion schon läuft, um vor dem Timeout die Funktion selbst mit dem gleichen Payload erneut aufzurufen?

Dieser Ansatz findet sich leider immer wieder und ist absolut zu vermeiden. Wenn Sie gedanklich an diesem Punkt angekommen sind, ist die Nutzung von AWS Lambda oft die falsche Idee. Hier ein paar Lösungsansätze:

  • Versuchen Sie die Aufgabe in kleinere Aspekte zu unterteilen und mehrere Lambda Funktionen zu bauen.
  • Nutzen Sie AWS Step Functions.
  • Falls sich die Dauer nicht reduzieren lässt, nutzen Sie stattdessen AWS ECS.

Fazit

In diesem Blog-Artikel haben wir uns einige Fälle aus meiner persönlichen Erfahrung angesehen, die eine optimale Nutzung von AWS Lambda verhindern. Grundsätzlich lässt sich zusammenfassen:

  • Nutzen Sie AWS Lambda stets im Sinne einer Micro-Service Architektur.
  • Nutzen Sie AWS SQS oder andere Methoden um die Funktionen asynchron miteinander zu verbinden
  • Seien Sie äußerst sparsam und sorgsam beim Einsatz von “Reserved Concurrency” und “Provisioned Concurrency”
  • Stellen Sie sicher, dass Ihre Lambda Funktionen stets nachvollziehen können, welche Aufgaben bereits verarbeitet wurden, um Mehrfachaufrufe zu vermeiden.
  • Beschäftigen Sie sich bewusst mit der “Timeout” Einstellung jeder einzelnen Funktion und tricksen Sie diese Mechanik nicht aus.

Benötigen Sie Unterstützung bei der Verwendung von AWS Lambda?

Sprechen Sie uns an und profitieren Sie von unserer Cloud- und Applikations Erfahrung.



Genutzte Services

Weiterlesen

Fallstudie
Finanzdienste
Cloud Migration
Die Cloud Journey der VHV Gruppe - Mit Strategie zum Erfolg

Wie meistert ein Versicherungskonzern mit über 4.000 Mitarbeitern den Spagat zwischen Compliance, Modernisierung und Kosteneffizienz?

Mehr erfahren
Fallstudie
Finanzdienste
DevOps
KYC – Archivsystem für die digitale Bank

Aufbau eines KYC-Cloud-Archivs für eine digitale Bank zur Speicherung von KYC-Kundendaten.

Mehr erfahren
Fallstudie
Software
DevOps
Mehr Tempo für die Buchhaltung

Was als Start-up im elterlichen Keller begann, hat sich innerhalb von wenigen Jahren zum führenden Anbieter cloudbasierter Buchhaltungs- und Finanzsoftware entwickelt: sevDesk.

Mehr erfahren
Fallstudie
Medien & Unterhaltung
Big Data-Plattform unterstützt Verlag bei der Datenverarbeitung

Axel Springer arbeitet mit modernen Big-Data-Technologien, um enorme Mengen operativer Daten zu verwalten.

Mehr erfahren
Alles sehen

Gemeinsam durchstarten

United Kingdom
Arrow Down