Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
Java-Laufzeit für Lambda Managed Instances
Für Java-Laufzeiten verwenden Lambda Managed Instances Betriebssystem-Threads aus Gründen der Parallelität. Lambda lädt Ihr Handler-Objekt während der Initialisierung einmal pro Ausführungsumgebung und erstellt dann mehrere Threads. Diese Threads werden parallel ausgeführt und erfordern eine threadsichere Handhabung von Zustands- und gemeinsam genutzten Ressourcen. Jeder Thread verwendet dasselbe Handler-Objekt und alle statischen Felder.
Konfiguration der Parallelität
Die maximale Anzahl gleichzeitiger Anforderungen, die Lambda an jede Ausführungsumgebung sendet, wird durch die PerExecutionEnvironmentMaxConcurrency Einstellung in der Funktionskonfiguration gesteuert. Dies ist eine optionale Einstellung, und der Standardwert variiert je nach Laufzeit. Für Java-Laufzeiten ist der Standardwert 32 gleichzeitige Anforderungen pro vCPU, oder Sie können Ihren eigenen Wert konfigurieren. Dieser Wert bestimmt auch die Anzahl der Threads, die von der Java-Laufzeit verwendet werden. Lambda passt die Anzahl der gleichzeitigen Anforderungen automatisch bis zum konfigurierten Maximum an, basierend auf der Kapazität der einzelnen Ausführungsumgebungen, diese Anforderungen zu verarbeiten.
Erstellung von Funktionen für Mehrfachparallelität
Sie sollten bei der Verwendung von Lambda Managed Instances dieselben Thread-Sicherheitspraktiken anwenden wie in jeder anderen Multithread-Umgebung. Da das Handler-Objekt von allen Runtime-Worker-Threads gemeinsam genutzt wird, muss jeder veränderbare Status threadsicher sein. Dazu gehören Sammlungen, Datenbankverbindungen und alle statischen Objekte, die während der Anforderungsverarbeitung geändert werden.
AWS SDK-Clients sind threadsicher und erfordern keine besondere Behandlung.
Beispiel: Datenbank-Verbindungspools
Der folgende Code verwendet ein statisches Datenbankverbindungsobjekt, das von Threads gemeinsam genutzt wird. Abhängig von der verwendeten Verbindungsbibliothek ist dies möglicherweise nicht threadsicher.
public class DBQueryHandler implements RequestHandler<Object, String> { // Single connection shared across all threads - NOT SAFE private static Connection connection; public DBQueryHandler() { this.connection = DriverManager.getConnection(jdbcUrl, username, password); } @Override public String handleRequest(Object input, Context context) { PreparedStatement stmt = connection.prepareStatement(query); ResultSet rs = stmt.executeQuery(); // Multiple threads using same connection causes issues return result.toString(); } }
Ein threadsicherer Ansatz besteht darin, einen Verbindungspool zu verwenden. Im folgenden Beispiel ruft der Funktionshandler eine Verbindung aus dem Pool ab. Die Verbindung wird nur im Kontext einer einzelnen Anfrage verwendet.
public class DBQueryHandler implements RequestHandler<Object, String> { private static HikariDataSource dataSource; public DBQueryHandler() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/your_database"); dataSource = new HikariDataSource(config); // Create pool once per Lambda container } @Override public String handleRequest(Object input, Context context) { String query = "SELECT column_name FROM your_table LIMIT 10"; StringBuilder result = new StringBuilder("Data:\n"); // try-with-resources automatically calls close() on the connection, // which returns it to the HikariCP pool (does NOT close the physical DB connection) try (Connection connection = dataSource.getConnection(); PreparedStatement stmt = connection.prepareStatement(query); ResultSet rs = stmt.executeQuery()) { while (rs.next()) { result.append(rs.getString("column_name")).append("\n"); } } catch (Exception e) { context.getLogger().log("Error: " + e.getMessage()); return "Error"; } return result.toString(); } }
Beispiel: Sammlungen
Standard-Java-Sammlungen sind nicht threadsicher:
public class Handler implements RequestHandler<Object, String> { private static List<String> items = new ArrayList<>(); private static Map<String, Object> cache = new HashMap<>(); @Override public String handleRequest(Object input, Context context) { items.add("list item"); // Not thread-safe cache.put("key", input); // Not thread-safe return "Success"; } }
Verwenden Sie stattdessen threadsichere Sammlungen:
public class Handler implements RequestHandler<Object, String> { private static final List<String> items = Collections.synchronizedList(new ArrayList<>()); private static final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>(); @Override public String handleRequest(Object input, Context context) { items.add("list item"); // Thread-safe cache.put("key", input); // Thread-safe return "Success"; } }
Gemeinsames /tmp-Verzeichnis
Das /tmp Verzeichnis wird von allen gleichzeitigen Anforderungen in der Ausführungsumgebung gemeinsam genutzt. Gleichzeitige Schreibvorgänge in dieselbe Datei können zu Datenbeschädigungen führen, z. B. wenn ein anderer Prozess die Datei überschreibt. Um dieses Problem zu beheben, implementieren Sie entweder Dateisperren für gemeinsam genutzte Dateien oder verwenden Sie eindeutige Dateinamen pro Thread oder pro Anfrage, um Konflikte zu vermeiden. Denken Sie daran, nicht benötigte Dateien zu bereinigen, um zu vermeiden, dass der verfügbare Speicherplatz ausgeschöpft wird.
Protokollierung
Das Verschachteln von Protokollen (Protokolleinträge aus verschiedenen Anfragen werden in Protokollen verschachtelt) ist bei Systemen mit mehreren gleichzeitigen Vorgängen normal.
Funktionen, die Lambda Managed Instances verwenden, verwenden immer das strukturierte JSON-Protokollformat, das mit erweiterten Protokollierungssteuerungen eingeführt wurde. Konfigurieren erweiterter Protokollierungsoptionen für Lambda-Funktionen Dieses Format beinhaltet dasrequestId, sodass Logeinträge einer einzelnen Anfrage zugeordnet werden können. Wenn Sie das LambdaLogger Objekt aus context.getLogger() dem verwenden, requestId ist es automatisch in jedem Protokolleintrag enthalten. Weitere Informationen finden Sie unterVerwenden von Lambda-Optionen für die erweiterte Protokollierung mit Java.
Kontext anfordern
Das context Objekt ist an den Anforderungsthread gebunden. Using context.getAwsRequestId() bietet threadsicheren Zugriff auf die Anforderungs-ID für die aktuelle Anfrage.
Wird für context.getXrayTraceId() den Zugriff auf die X-Ray Trace-ID verwendet. Dies bietet Thread-sicheren Zugriff auf die Trace-ID für die aktuelle Anfrage. Lambda unterstützt die _X_AMZN_TRACE_ID Umgebungsvariable mit Lambda Managed Instances nicht. Die X-Ray Trace-ID wird automatisch weitergegeben, wenn das SDK verwendet wird. AWS
Wird verwendetcom.amazonaws.services.lambda.runtime.Context.getRemainingTimeInMillis(), um Timeouts zu erkennen. Weitere Informationen finden Sie unter Fehlerbehandlung und Wiederherstellung.
Wenn Sie virtuelle Threads in Ihrem Programm verwenden oder während der Initialisierung Threads erstellen, müssen Sie den erforderlichen Anforderungskontext an diese Threads übergeben.
Beispiel: Timeout-Behandlung
Prüfen Sie die verbleibende Zeit vor jeder Arbeitseinheit und beenden Sie die Verarbeitung, bevor der Timeout ausgelöst wird. Konfigurieren Sie die Konfiguration auf der BUFFER_MS Grundlage der erwarteten Dauer Ihres nächsten Arbeitsabschnitts.
private static final int BUFFER_MS = 2000; // Configure based on your next chunk of work public Map<String, Object> handleRequest(Map<String, Object> event, Context context) { for (Object item : (List<Object>) event.get("items")) { if (context.getRemainingTimeInMillis() < BUFFER_MS) return Map.of("statusCode", 206, "body", "Timeout approaching, stopping early"); processItem(item); } return Map.of("statusCode", 200, "body", "Done"); }
Beispiel: Weitergabe von Terminen an Downstream-Aufrufe
Wenn Sie nachgelagerte Dienste aufrufen, geben Sie die verbleibende Zeit als Timeout an, um zu vermeiden, dass Netzwerkaufrufe, die Ihren Aufruf überdauern würden, hängen bleiben. Verwenden Sie eine Überschreibung pro Anfrage auf einem gemeinsam genutzten Client, anstatt pro Aufruf einen neuen Client zu erstellen:
import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import java.time.Duration; private static final S3Client s3 = S3Client.create(); public String handleRequest(Map<String, Object> event, Context context) { Duration timeout = Duration.ofMillis(Math.max(1000, context.getRemainingTimeInMillis() - 500)); GetObjectRequest req = GetObjectRequest.builder() .bucket("my-bucket").key("my-key") .overrideConfiguration(cfg -> cfg.apiCallTimeout(timeout)) .build(); s3.getObject(req); return "Done"; }
Initialisierung und Herunterfahren
Die Funktionsinitialisierung erfolgt einmal pro Ausführungsumgebung. Objekte, die während der Initialisierung erstellt wurden, werden von allen Threads gemeinsam genutzt.
Bei Lambda-Funktionen mit Erweiterungen gibt die Ausführungsumgebung beim Herunterfahren ein SIGTERM-Signal aus. Dieses Signal wird von Erweiterungen verwendet, um Bereinigungsaufgaben wie das Leeren von Puffern auszulösen. Sie können SIGTERM-Ereignisse abonnieren, um Aufgaben zur Funktionsbereinigung auszulösen, z. B. das Schließen von Datenbankverbindungen. Weitere Informationen zum Lebenszyklus der Ausführungsumgebung finden Sie unter Verständnis des Lebenszyklus der Lambda-Ausführungsumgebung.
Versionen, die abhängig sind
Für Lambda Managed Instances sind die folgenden Mindestpaketversionen erforderlich:
-
AWS SDK für Java 2.0: Version 2.34.0 oder höher
-
AWS X-Ray SDK für Java: Version 2.20.0 oder höher
-
AWS Distribution für OpenTelemetry - Instrumentation für Java: Version 2.20.0 oder höher
-
Powertools für AWS Lambda (Java): Version 2.8.0 oder höher
Powertools für AWS Lambda (Java)
Powertools for AWS Lambda (Java) ist mit Lambda Managed Instances kompatibel und bietet Hilfsprogramme für Logging, Tracing, Metriken und mehr. Weitere Informationen finden Sie unter Powertools for AWS Lambda (Java).
Nächste Schritte
-
Überprüfen Sie die Node.js Laufzeit für von Lambda Managed Instances
-
Überprüfen Sie die Python-Laufzeit für von Lambda verwaltete Instances
-
Überprüfen Sie die .NET-Laufzeit für von Lambda verwaltete Instances
-
Erfahren Sie mehr über die Skalierung von Lambda Managed Instances