Saaspective

Software Briefing

Java-Cold-Starts in AWS Lambda: Wann SnapStart, wann Native Image?

Für bestehende Java-Lambdas ist SnapStart meist der risikoärmere erste Test, solange Snapshot-Zustand und Produktgrenzen passen. Native Image lohnt eine eigene Prüfung, wenn der Stack AOT-tauglich ist und das Team den zusätzlichen Build- und Kompatibilitätsaufwand tragen kann. Entscheidend sind Messungen am echten Workload – nicht ein fremder Einzelbenchmark.

Developer ToolsVon Saaspective Redaktion

Aktualisierung: Aktualisiert am 8. August 2026: Entscheidungskriterien, Produktgrenzen, Zustandsrisiken und Produktions-Messplan wurden grundlegend erweitert und mit aktuellen offiziellen Quellen belegt.

Illustration zum Artikel: AWS Lambda SnapStart vs. GraalVM Native Image: Welche Java-Strategie für Cold Starts?Dieses Bild wurde mit KI erstellt.

Kurz gesagt

Für bestehende Java-Lambdas ist SnapStart meist der risikoärmere erste Test, solange Snapshot-Zustand und Produktgrenzen passen. Native Image lohnt eine eigene Prüfung, wenn der Stack AOT-tauglich ist und das Team den zusätzlichen Build- und Kompatibilitätsaufwand tragen kann. Entscheidend sind Messungen am echten Workload – nicht ein fremder Einzelbenchmark.

Kurzantwort: SnapStart zuerst prüfen, wenn ihr auf der JVM bleiben wollt

Ein Cold Start entsteht, wenn AWS Lambda für einen Aufruf eine neue Ausführungsumgebung initialisieren muss. Für eine bestehende Java-Funktion ist SnapStart häufig der kleinere Architekturwechsel: AWS initialisiert eine veröffentlichte Funktionsversion vorab, speichert den Speicher- und Festplattenzustand als Snapshot und stellt daraus später neue Umgebungen wieder her. GraalVM Native Image kompiliert die Anwendung dagegen schon im Build in ein natives, plattformspezifisches Programm. Damit ändert sich nicht nur der Start, sondern auch der Build- und Kompatibilitätsvertrag.

Als Arbeitshypothese gilt:

  • SnapStart zuerst testen, wenn ihr beim verwalteten Java-Runtime-Modell bleiben, dynamische Java-Funktionen möglichst unverändert nutzen und den Umbau begrenzen wollt.
  • Native Image als eigenen Architekturpfad prüfen, wenn Framework und Abhängigkeiten nachweislich AOT-tauglich sind, ein Linux-Binary Teil eures Deployments werden darf und ihr native Builds dauerhaft testen und pflegen könnt.
  • Bei der normalen JVM bleiben, wenn Cold Starts in euren echten Nutzerpfaden kein relevantes Latenz- oder Fehlerrisiko darstellen.

Es gibt deshalb keinen allgemeinen Sieger. Die bessere Option ist diejenige, die euren Zielwert im Produktionsprofil erreicht, ohne ein unverhältnismäßiges Korrektheits- oder Betriebsrisiko einzuführen.

Was technisch wirklich verglichen wird

SnapStart und Native Image sind keine zwei Schalter für denselben Mechanismus. SnapStart behält die verwaltete JVM und verschiebt einen großen Teil der Initialisierung auf den Zeitpunkt, an dem eine Funktionsversion veröffentlicht wird. Native Image führt eine statische Analyse durch und nimmt nur erreichbaren Code in das ausführbare Programm auf. Dynamische Funktionen wie Reflection, Ressourcen oder zur Laufzeit geladene Klassen können deshalb zusätzliche Reachability-Metadaten oder Konfiguration erfordern.

Für Lambda wird ein Java-Native-Image über einen OS-only Runtime der provided-Familie bereitgestellt. Das Binary muss für Linux und dieselbe Prozessorarchitektur wie die Funktion gebaut sein. Dieser Pfad ist damit mehr als eine Optimierungsoption innerhalb des verwalteten Java-Runtimes.

Entscheidungsmatrix für Java auf AWS Lambda
KriteriumLambda SnapStartGraalVM Native ImageEntscheidungssignal
LaufzeitmodellVerwaltete JVM; Wiederherstellung aus einem von AWS erzeugten SnapshotNatives Binary auf einem OS-only RuntimeJVM-Nähe spricht für SnapStart; bewusster Runtime-Wechsel für Native Image
Erster UmbauMeist Konfiguration plus Prüfung des Snapshot-ZustandsEigener AOT-Build, Linux-Ziel und Runtime-IntegrationKleine Änderung zuerst: SnapStart
Dynamische Java-FunktionenBleiben grundsätzlich im JVM-ModellKönnen Reachability-Metadaten oder Anpassungen verlangenViel Reflection oder dynamisches Laden erhöht Native-Image-Prüfaufwand
Zustand und SecretsEindeutige oder vergängliche Init-Daten nach Restore erneuernBuild-Time-Initialisierung darf keine sensiblen oder umgebungsabhängigen Werte einbackenBeide Pfade brauchen einen Zustandscheck, aber an anderer Stelle
PackagingKeine Container Images; nur veröffentlichte Versionen und Aliasse auf VersionenBinary für Linux und passende Architektur; OS-only RuntimeBestehende Paketform kann eine Option ausschließen
Provisioned ConcurrencyNicht auf derselben Funktionsversion kombinierbarSeparat für den konkreten Runtime-Pfad prüfenIst Provisioned Concurrency Pflicht, scheidet SnapStart für diese Version aus
Seltene AufrufeJava-Snapshot wird nach 14 Tagen ohne Aufruf gelöschtKein SnapStart-Lifecycle; Startverhalten des Binaries bleibt zu messenBei sehr seltener Nutzung nicht automatisch von SnapStart-Nutzen ausgehen
MessgrößeRestore Duration plus End-to-End-LatenzStart plus End-to-End-LatenzMit identischem Event- und Lastprofil vergleichen

Fünf Ausschlussfragen vor jedem Benchmark

1. Ist SnapStart für euer Paket überhaupt zulässig?

SnapStart unterstützt bei Java verwaltete Runtimes ab Java 11, aber keine OS-only Runtimes und keine Container Images. Außerdem lässt es sich auf derselben Funktionsversion nicht mit Provisioned Concurrency kombinieren. EFS, S3 Files und mehr als 512 MB temporärer Speicher sind ebenfalls ausgeschlossen. Trifft eine dieser Grenzen zu, ist SnapStart für diese konkrete Funktion keine Option.

2. Ist der initialisierte Zustand nach einer Wiederherstellung noch korrekt?

Ein SnapStart-Snapshot kann Zustand enthalten, der später in mehrere Ausführungsumgebungen kopiert wird. Eindeutige IDs, Secrets, Zufallszustand, temporäre Zugangsdaten, Zeitstempel und Netzwerkverbindungen dürfen deshalb nicht ungeprüft aus der Initialisierungsphase übernommen werden. AWS empfiehlt, vergängliche oder eindeutige Daten nach der Wiederherstellung neu zu erzeugen beziehungsweise zu aktualisieren. Für Java können CRaC-Runtime-Hooks Code unmittelbar vor dem Snapshot und nach der Wiederherstellung ausführen; ein afterRestore-Hook muss innerhalb des von AWS vorgegebenen Restore-Zeitfensters fertig werden.

3. Ist der Java-Stack wirklich Native-Image-tauglich?

Native Image arbeitet mit einer Closed-World-Annahme: Der relevante Code muss beim Build bekannt sein. Reflection, dynamische Proxies, Ressourcen, Serialisierung, JNI und dynamisches Class Loading können zusätzliche Metadaten verlangen. Eine erfolgreiche Kompilierung allein reicht daher nicht. Die Tests müssen auch die seltenen Laufzeitpfade abdecken, in denen solche Funktionen erst unter bestimmten Events oder Fehlern aktiviert werden.

Auch die Class Initialization verlangt Aufmerksamkeit. Eine Initialisierung zur Build-Zeit kann den Start beschleunigen, aber Zustand in das Binary übernehmen, der erst zur Laufzeit entstehen sollte. GraalVM warnt ausdrücklich davor, dabei etwa sensible Daten, Zufallszustand oder umgebungsabhängige Werte festzuschreiben.

4. Passt der Deployment-Pfad zum Team?

Ein Native Image für Lambda benötigt ein passendes Linux-Binary, die richtige Architektur und einen Runtime Interface Client im OS-only Runtime. Frameworks können viel davon vorbereiten: Die offizielle Quarkus-Dokumentation zeigt beispielsweise sowohl den verwalteten Java-Pfad als auch einen nativen Custom-Runtime-Pfad. Sie nennt zugleich native-spezifische Konfiguration, etwa für HTTPS-Abhängigkeiten. Das ist ein gutes Muster für die Bewertung: Framework-Unterstützung senkt den Aufwand, ersetzt aber keine Abhängigkeits- und Integrationstests.

5. Passt die Option zum Aufrufprofil?

SnapStart wirkt laut AWS am besten bei skalierenden Aufrufmustern. Bei Java-Versionen löscht AWS einen Snapshot nach 14 Tagen ohne Aufruf; die Version wird inaktiv und muss beim nächsten Versuch zunächst wieder initialisiert werden. Für selten aufgerufene Funktionen kann der Nutzen deshalb kleiner sein als für regelmäßig skalierende APIs. Wenn eine Funktion überwiegend warm bleibt oder der Nutzerpfad die Startlatenz nicht wahrnimmt, kann die normale JVM die betrieblich einfachste Lösung bleiben.

Drei Entscheidungsmuster für kleine Teams

Bestehende, framework-lastige JVM-API

Beginnt mit SnapStart, sofern keine harte Produktgrenze greift. Ihr könnt denselben verwalteten Runtime-Pfad behalten und euch zuerst auf Snapshot-Sicherheit, Restore-Verhalten und reale Latenz konzentrieren. Native Image bleibt ein zweiter Kandidat, wenn das Ergebnis den Zielwert nicht erreicht oder der Speicherbedarf weiterhin problematisch ist.

AOT-bereiter Dienst mit empfindlicher Scale-out-Latenz

Native Image ist ein ernsthafter Kandidat, wenn Framework und Bibliotheken den nativen Build offiziell unterstützen und das Team den Build reproduzierbar betreiben kann. Behandelt das Binary als eigenes Release-Artefakt: Architektur, Runtime Interface Client, Metadaten und native Integrationstests gehören dann in die Lieferkette.

Warmer Hintergrundjob ohne harte Antwortzeit

Optimiert nicht automatisch. Messt zunächst, wie oft überhaupt neue Umgebungen entstehen und ob diese Starts einen geschäftlich relevanten Ablauf verzögern. Wenn nicht, kann die normale JVM weniger Risiko und weniger Pflege bedeuten als beide Optimierungspfade.

Ein Messplan, der eine belastbare Entscheidung ermöglicht

Testet drei Varianten derselben Funktion: normale JVM, JVM mit SnapStart und – sofern technisch möglich – Native Image. Verwendet dieselben fachlichen Events, dieselben nachgelagerten Dienste und vergleichbare Lastverläufe. Dokumentiert Abweichungen im Packaging oder in der Initialisierung, damit nicht versehentlich unterschiedliche Anwendungen verglichen werden.

Erfasst mindestens:

  1. End-to-End-Latenz des Nutzer- oder Event-Pfads als p50, p95 und p99.
  2. Anteil neuer Ausführungsumgebungen und deren Start- beziehungsweise Restore-Zeit.
  3. Fehler nach Scale-out, nach längerer Inaktivität und in seltenen Eventpfaden.
  4. Maximalen Speicherverbrauch sowie abgerechnete Dauer und Requests.
  5. Build-Dauer, Artefaktgröße, Deployment-Dauer und Zeit bis zur aktiven Version.
  6. Aufwand für Fehlersuche, Sicherheitsupdates und reproduzierbare Builds.

Bei SnapStart weist der Lambda-REPORT-Datensatz für neue Umgebungen eine Restore Duration aus; die Initialisierung beim Veröffentlichen steht im INIT_REPORT. Bewertet nicht nur den Mittelwert. Gerade die hohen Perzentile zeigen, ob ein Nutzerpfad unter Scale-out stabil bleibt.

Legt vor dem Test einen Zielwert und einen Abbruchgrund fest. Ein Beispiel: „Die p95-End-to-End-Latenz muss im Scale-out-Test unter unserem internen Grenzwert bleiben; Fehlerquote und Deployment-Zeit dürfen sich nicht verschlechtern.“ Der konkrete Grenzwert muss aus eurem Dienst kommen, nicht aus einem fremden Benchmark.

Entscheidung in einem Satz

Wählt SnapStart als risikoärmeren ersten Versuch, wenn ihr eine kompatible verwaltete Java-Funktion beschleunigen wollt; wählt Native Image nur dann als dauerhaften Pfad, wenn AOT-Kompatibilität und Betrieb beherrscht sind und der gemessene Vorteil den zusätzlichen Build-Vertrag rechtfertigt.

Quellen

Weitere Artikel aus Developer Tools