Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Runtime Java pour les instances gérées Lambda
Pour les environnements d'exécution Java, les instances gérées Lambda utilisent des threads du système d'exploitation pour la simultanéité. Lambda charge votre objet gestionnaire une fois par environnement d'exécution lors de l'initialisation, puis crée plusieurs threads. Ces threads s'exécutent en parallèle et nécessitent une gestion sûre de l'état et des ressources partagées. Chaque thread partage le même objet gestionnaire et tous les champs statiques.
Configuration de la simultanéité
Le nombre maximum de requêtes simultanées que Lambda envoie à chaque environnement d'exécution est contrôlé par le PerExecutionEnvironmentMaxConcurrency paramètre de la configuration de la fonction. Il s'agit d'un paramètre facultatif et la valeur par défaut varie en fonction de l'exécution. Pour les environnements d'exécution Java, la valeur par défaut est de 32 requêtes simultanées par processeur virtuel, ou vous pouvez configurer votre propre valeur. Cette valeur détermine également le nombre de threads utilisés par le moteur d'exécution Java. Lambda ajuste automatiquement le nombre de demandes simultanées jusqu'au maximum configuré en fonction de la capacité de chaque environnement d'exécution à absorber ces demandes.
Création de fonctions pour la multisimultanéité
Vous devez appliquer les mêmes pratiques de sécurité des threads lorsque vous utilisez des instances gérées Lambda que dans tout autre environnement multithread. Étant donné que l'objet du gestionnaire est partagé entre tous les threads de travail d'exécution, tout état mutable doit être sûr pour les threads. Cela inclut les collections, les connexions aux bases de données et tous les objets statiques modifiés lors du traitement des demandes.
AWS Les clients du SDK sont sûrs pour les threads et ne nécessitent aucune manipulation particulière.
Exemple : pools de connexions à la base de données
Le code suivant utilise un objet de connexion à une base de données statique qui est partagé entre les threads. Selon la bibliothèque de connexion utilisée, cela peut ne pas être compatible avec les threads.
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(); } }
Une approche sûre des threads consiste à utiliser un pool de connexions. Dans l'exemple suivant, le gestionnaire de fonctions récupère une connexion depuis le pool. La connexion n'est utilisée que dans le cadre d'une seule demande.
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(); } }
Exemple : Collections
Les collections Java standard ne sont pas sûres pour les threads :
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"; } }
Utilisez plutôt des collections adaptées aux threads :
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"; } }
Répertoire /tmp partagé
Le /tmp répertoire est partagé entre toutes les demandes simultanées de l'environnement d'exécution. Les écritures simultanées dans le même fichier peuvent entraîner une corruption des données, par exemple si un autre processus remplace le fichier. Pour résoudre ce problème, implémentez le verrouillage des fichiers partagés ou utilisez des noms de fichiers uniques par thread ou par requête pour éviter les conflits. N'oubliez pas de nettoyer les fichiers inutiles pour ne pas épuiser l'espace disponible.
Logging
L'entrelacement des journaux (les entrées de journal provenant de différentes demandes sont entrelacées dans les journaux) est normal dans les systèmes multisimultanés.
Les fonctions utilisant des instances gérées Lambda utilisent toujours le format de journal JSON structuré introduit avec les contrôles de journalisation avancés. Ce format inclut lerequestId, permettant de corréler les entrées du journal à une seule demande. Lorsque vous utilisez l'LambdaLoggerobjet decontext.getLogger(), requestId il est automatiquement inclus dans chaque entrée du journal. Pour plus d'informations, voirUtilisation des contrôles de journalisation avancés de Lambda avec Java.
Contexte de la requête
L'contextobjet est lié au thread de requête. Using context.getAwsRequestId() fournit un accès sécurisé à l'ID de demande pour la demande en cours.
Utilisez-le context.getXrayTraceId() pour accéder à l'ID de X-Ray trace. Cela fournit un accès sécurisé à l'ID de trace de la demande en cours. Lambda ne prend pas en charge la variable d'_X_AMZN_TRACE_IDenvironnement avec les instances gérées Lambda. L'ID de X-Ray trace est automatiquement propagé lors de l'utilisation du AWS SDK.
Utilisez-le com.amazonaws.services.lambda.runtime.Context.getRemainingTimeInMillis() pour détecter les délais d'attente. Pour plus d’informations, consultez Gestion des erreurs et restauration.
Si vous utilisez des fils virtuels dans votre programme ou si vous créez des fils lors de l'initialisation, vous devez transmettre tout contexte de demande requis à ces fils.
Exemple : gestion des délais
Vérifiez le temps restant avant chaque unité de travail et arrêtez le traitement avant le déclenchement du timeout. Configurez en BUFFER_MS fonction de la durée prévue de votre prochaine partie de travail.
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"); }
Exemple : Propagation des délais aux appels en aval
Lorsque vous passez des appels vers des services en aval, répartissez le temps restant sous forme de délai d'attente pour éviter de vous accrocher à des appels réseau qui dureraient plus longtemps que votre appel. Utilisez un remplacement par demande sur un client partagé plutôt que de créer un nouveau client par appel :
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"; }
Initialisation et arrêt
L'initialisation des fonctions se produit une fois par environnement d'exécution. Les objets créés lors de l'initialisation sont partagés entre les threads.
Pour les fonctions Lambda dotées d'extensions, l'environnement d'exécution émet un signal SIGTERM lors de l'arrêt. Ce signal est utilisé par les extensions pour déclencher des tâches de nettoyage, telles que le vidage des buffers. Vous pouvez vous abonner aux événements SIGTERM pour déclencher des tâches de nettoyage des fonctions, telles que la fermeture des connexions à la base de données. Pour en savoir plus sur le cycle de vie de l'environnement d'exécution, veuillez consulter Comprendre le cycle de vie de l’environnement d’exécution Lambda.
Versions de dépendance
Les instances gérées Lambda nécessitent les versions de package minimales suivantes :
-
AWS SDK pour Java 2.0 : version 2.34.0 ou ultérieure
-
AWS X-Ray SDK pour Java : version 2.20.0 ou ultérieure
-
AWS Distribution pour OpenTelemetry - Instrumentation pour Java : version 2.20.0 ou ultérieure
-
Powertools pour AWS Lambda (Java) : version 2.8.0 ou ultérieure
Outils électriques pour AWS Lambda (Java)
Powertools for AWS Lambda (Java) est compatible avec les instances gérées Lambda et fournit des utilitaires pour la journalisation, le suivi, les métriques, etc. Pour plus d'informations, consultez Powertools for AWS Lambda (Java).
Étapes suivantes
-
Vérifier le Node.js temps d'exécution pour les instances gérées Lambda
-
Vérifier l'environnement d'exécution Python pour les instances gérées Lambda
-
Vérifier l'environnement d'exécution .NET pour les instances gérées Lambda
-
En savoir plus sur la mise à l'échelle des instances gérées Lambda