Tipp: Schnellere Kaltstarts für AWS Lambda

Bei der Nutzung von AWS Lambda können, auch in Zusammenspiel mit Amazon API Gateway Kaltstart-Zeiten, sogenannte „Cold Starts“ eine wichtige Rolle spielen. Dabei handelt es sich um Wartezeiten für den ersten Aufruf einer Lambda-Funktion, wenn AWS Lambda die Infrastruktur hochfahren, die Runtime-Umgebung provisionieren und den Code starten muss.

Grafik: AWS

Mehrere Faktoren können dabei die Geschwindigkeit für den ersten Funktionsstart beeinflussen:

  • Speicher- und CPU-Zuweisung: AWS Lambda weist dem Speicher, den Sie Ihren Funktionen zuweisen, eine proportionale Anzahl von CPU-Anteilen zu. Wenn Ihr Code CPU-gebunden ist, erhöhen Sie diesen Wert, um die Leistung zu verbessern.
  • Paketgröße des Codes: Jedes Mal, wenn eine Lambda-Funktion zum ersten Mal startet, muss das entsprechende Codepaket heruntergeladen und entpackt werden. Die Größe der entsprechenden ZIP-Datei ist relevant. Beim Import von Abhängigkeiten sollten Sie deshalb vorsichtig sein und zum Beispiel das Maven Shade Plugin nutzen, um unnötige transitive Abhängigkeiten zu entfernen.
  • Code Lebenszyklus: Wenn Sie Ihre Funktion zum ersten Mal starten, erstellt AWS Lambda eine Instanz Ihrer Laufzeitumgebung sowie Ihres laufenden Codes. Diese wird für zukünftige Aufrufe wiederverwendet. Bei jedem neuen Aufruf Ihrer Lambda-Funktion wird die Handler-Funktion beziehungsweise die Handler-Methode direkt angesprochen, ohne den Programmcode neu zu laden. Das bedeutet, dass Objekte, die beim ersten Aufruf initialisiert wurden bei jedem weiteren Aufruf wiederverwendet werden können. Sie können also globale Variablen, Class Objects, etc. verwenden, um Metadaten, Objekte und Verbindungen über mehrere Lambda-Funktionsaufrufe hinweg zu speichern, und diese über einen längeren Zeitraum hinweg wiederverwenden. Diese Methode eignet sich auch, um den RAM-Speicher Ihrer Lambda-Umgebung als Cache zu verwenden.
  • Apropos Caching: Vermeiden Sie das Zwischenspeichern vertraulicher Daten, das könnte zu Sicherheitsproblemen führen, wenn etwa vergessen wird, zwischengespeicherte, vertrauliche Daten zwischen einzelnen Aufrufen zu bereinigen.

Verschiedene Programmiersprachen und ihre Frameworks haben unterschiedliche Eigenschaften und Leistungsmerkmale. Bei Java sind zum Beispiel Spring und Spring Boot extrem leistungsstark, wenn es um die Injektion von Abhängigkeiten und die automatische Verbindung von Anwendungen geht. Der Nachteil der großen Flexibilität sind schlechtere Zeiten beim Cold Start. Jersey führt nur eine begrenzte Reflexion durch, um die jeweiligen Provider und Ressourcen anzubinden. Spark, bei dem alles „statisch verknüpft“ ist, ist in der Java-Welt bei weitem das schnellste Framework.

Generell zeigen Skript-Sprachen wie Python oder JavaScript (Node.js) kürzere Cold-Start-Zeiten. Man erkauft sich diesen Vorteil aber durch eine insgesamt niedrigere Effizienz bei starker Nutzung, etwa bei API-Implementationen mit hohem Durchsatz über einen längeren Zeitraum hinweg – hier ist Java wiederum durch die Vorteile des Hotspot-Compilers besser. Programmiersprachen wie Go und Rust haben hier potenziell große Vorteile, da sie als kompilierte Sprachen mit statischen Binaries sehr kurze Cold-Start-Zeiten unterstützen und gleichzeitig sehr performant sein können. Welche Sprache beziehungsweise welches Framework ist also am ehesten geeignet? Sofern Sie keine strengen Anforderungen an die Latenz haben, wählen Sie einfach das Framework, mit dem Sie am besten vertraut sind. Eine Cold-Start-Optimierung ist in der Regel nur dann notwendig, wenn die Latenzzeit Ihrer Anwendung sehr wichtig ist und die Lambda-Funktion nur selten aufgerufen wird oder gelegentliche Peaks in der Laufzeit sich sehr störend auf die Nutzererfahrung auswirken – Hier kann man jedoch mit ein paar Optimierungs-Maßnahmen in der Regel schnell Abhilfe schaffen, ohne gleich das Framework oder die Programmiersprache wechseln zu müssen.