Java sur AWS Lambda est-il lent?

Java s'exécutant sur AWS Lambda est lent la première fois, mais j'ai cherché un moyen de le rendre plus rapide. Je suis arrivé au contenu du site de référence à la fin et je l'ai essayé, donc c'est un record.

Les informations de latence ont été acquises par X-Ray.

Cible de test

Mettez simplement le fichier dans S3

S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();
PutObjectResponse result = s3.putObject(
        PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
        RequestBody.fromString("contents"));

Vérification 1 Exécution normale

Tout d'abord, essayez-le normalement.

<détails> <résumé> source entière </ résumé>

package helloworld;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class TestTarget0429 implements RequestHandler<Object, Object> {

    public Object handleRequest(final Object input, final Context context) {
        String ENV_BUCKET = System.getenv("BUCKET");

        S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();
        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);

        return null;
    }
}
Nombre de fois Latence(ms) Traitement du contenu
1 6200
2 422
3 217
4 210
5 315

Seule la première fois est en retard, le soi-disant démarrage à froid est en retard. Créer simplement un fichier dans S3 prend 6 secondes, n'est-ce pas?

Vérification 2 Activer la simultanéité provisionnée

Alors, que diriez-vous d'utiliser la "Concurrence fournie" qui est apparue à la fin de l'année dernière? https://aws.amazon.com/jp/blogs/news/new-provisioned-concurrency-for-lambda-functions/

Le code source est le même que celui de la vérification 1.

Nombre de fois Latence(ms) Traitement du contenu
1 5500
2 266
3 274
4 402
5 304

** La première fois n'est-elle pas encore en retard? .. ** ** Il en coûte 14,42 $ par mois juste pour provisionner la concurrence 1, mais ce n'est pas tellement. .. ..

Donc, après cela, désactivez la concurrence allouée et continuez la vérification

Vérification 3 Séparation du traitement (sans accès concurrentiel fourni)

Afin de découvrir la cause de la lenteur à la première fois, j'ai essayé de séparer le traitement au premier démarrage de Lambda et au deuxième démarrage.

Créez une variable statique count et essayez de ne renvoyer rapidement que le premier appel.

        if (count == 1) {
            count++;
            return null;
        }

<détails> <résumé> source entière </ résumé>

package helloworld;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class TestTarget0429 implements RequestHandler<Object, Object> {

    private static int count = 1;

    public Object handleRequest(final Object input, final Context context) {
        if (count == 1) {
            count++;
            return null;
        }
        
        String ENV_BUCKET = System.getenv("BUCKET");

        S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();
        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);

        return null;
    }
}

résultat

Nombre de fois Latence Traitement du contenu
1 625ms Processus d'initialisation uniquement
2 5600ms S3 PUT (1ère fois)
3 393ms S3 PUT (2ème fois)
4 401ms S3 PUT (3e fois)
5 311ms S3 PUT (4ème fois)

Il s'avère que le processus d'initialisation n'est pas lent. Il semble que S3 PUT (première fois) prend beaucoup de temps.

Vérification 4 Rendre le processus d'initialisation statique (pas de concurrence allouée)

Rendons la partie qui crée S3Client statique.

private static String ENV_BUCKET = System.getenv("BUCKET");
private static S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();

<détails> <résumé> source entière </ résumé>

package helloworld;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class TestTarget0429 implements RequestHandler<Object, Object> {

    private static int count = 1;

    private static String ENV_BUCKET = System.getenv("BUCKET");
    private static S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();

    public Object handleRequest(final Object input, final Context context) {
        if (count == 1) {
            count++;
            return null;
        }

        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);

        return null;
    }
}

résultat

Nombre de fois Latence Traitement du contenu
1 2400ms Processus d'initialisation et création d'instance S3Client
2 2200ms S3 PUT (1ère fois)
3 43ms S3 PUT (2ème fois)
4 46ms S3 PUT (3e fois)
5 78ms S3 PUT (4ème fois)

Oh! Il a fallu un peu plus de temps pour traiter la première fois, et la deuxième fois était un peu plus rapide. Cela s'accélère après la troisième fois, mais cela a-t-il également un effet?

Vérification 5 Faites-le une fois avec l'initialiseur statique (sans accès concurrentiel provisionné)

J'ai trouvé que le traitement avec statique le rend plus rapide. Créons une fois un fichier factice avec l'initialiseur statique.

static{
    PutObjectResponse result = s3.putObject(
            PutObjectRequest.builder().bucket(ENV_BUCKET).key("dummy.txt").build(),
            RequestBody.fromString("contents"));

    System.out.println(result);
}

<détails> <résumé> source entière </ résumé>

package helloworld;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class TestTarget0429 implements RequestHandler<Object, Object> {

    private static int count = 1;

    private static String ENV_BUCKET = System.getenv("BUCKET");
    private static S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();

    static{
        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("dummy.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);
    }

    public Object handleRequest(final Object input, final Context context) {
        if (count == 1) {
            count++;
            return null;
        }

        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);

        return null;
    }
}

résultat

Nombre de fois Latence Traitement du contenu
1 4000ms Fichier factice S3 PUT (première fois) par traitement d'initialisation et méthode statique
2 42ms S3 PUT (2ème fois)
3 125ms S3 PUT (3e fois)
4 42ms S3 PUT (4ème fois)
5 44ms S3 PUT (5ème fois)

Félicitations, la deuxième fois et les suivantes sont devenues plus rapides!

Vérification 6 Vérification 5 + Concurrence provisionnée

Puisqu'il est devenu plus rapide dans la vérification 5, sera-t-il plus rapide dès la première fois s'il est combiné avec la simultanéité provisionnée? !!

La source est la même que la vérification 5.

Nombre de fois Latence Traitement du contenu
1 80ms Processus d'initialisation
2 370ms S3 PUT (2ème fois) * Parce qu'il a déjà été exécuté une fois avec l'initialiseur statique pendant Provisioned
3 43ms S3 PUT (3e fois)
4 72ms S3 PUT (4ème fois)
5 84ms S3 PUT (5ème fois)

** Je l'ai fait! ** ** C'est ce à quoi je m'attendais.

Résultat final

La forme finale est comme ça.

<détails> <résumé> source entière </ résumé>

package helloworld;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

public class TestTarget0429 implements RequestHandler<Object, Object> {

    private static String ENV_BUCKET = System.getenv("BUCKET");
    private static S3Client s3 = S3Client.builder().region(Region.AP_NORTHEAST_1).build();

    static{
        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("dummy.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);
    }

    public Object handleRequest(final Object input, final Context context) {
        PutObjectResponse result = s3.putObject(
                PutObjectRequest.builder().bucket(ENV_BUCKET).key("filename.txt").build(),
                RequestBody.fromString("contents"));

        System.out.println(result);

        return null;
    }
}
Nombre de fois Latence Traitement du contenu
1 552ms S3 PUT (2ème fois) * Parce qu'il a déjà été exécuté une fois avec l'initialiseur statique pendant Provisioned
2 118ms S3 PUT (3e fois)
3 44ms S3 PUT (4ème fois)
4 86ms S3 PUT (5ème fois)
5 146ms S3 PUT (6ème fois)

Félicitations, félicitations.

Considération

Apparemment, le chargeur de classe Java charge la classe lorsque la classe est appelée pour la première fois, et il semble que le chargement initial de la classe prend du temps. Donc, il semble que si vous le chargez une fois et chargez la classe, ce sera plus rapide à partir de la prochaine fois.

Ce serait bien si toutes les classes étaient chargées en premier, pas quand elles ont été appelées, mais n'est-ce pas possible?

Le site de référence est ici.

Blog de la méthode de classe https://dev.classmethod.jp/articles/report-best-practive-for-java-on-lambda/

Matériel de session à re: Invent 2019 https://d1.awsstatic.com/events/reinvent/2019/REPEAT_1_Best_practices_for_AWS_Lambda_and_Java_SVS403-R1.pdf https://youtu.be/ddg1u5HLwg8

Autres blogs que j'ai trouvés https://pattern-match.com/blog/2020/03/14/springboot2-and-aws-lambda-provisioned-concurrency/

Recommended Posts

Java sur AWS Lambda est-il lent?
Hello World avec AWS Lambda + Java
Publiez régulièrement des images de tweets sur Twitter avec AWS Lambda + Java
Qu'est-ce qu'une expression lambda (Java)
Exécuter des binaires C sur AWS Lambda
AWS Lambda (Lambda) Partie 1 avec Java pour démarrer maintenant
Créer un environnement de développement Java 8 avec AWS Cloud 9
Qu'est-ce que 'java
Qu'est-ce que Java <>?
Qu'est-ce que 'java
Bonjour Java Lambda
[Java] Expression Lambda
Expression lambda Java
Comment utiliser le framework Java avec AWS Lambda! ??
Installez Java sur Mac
Comment déployer Java sur AWS Lambda avec Serverless Framework
Changement de fuseau horaire AWS Lambda
expression 1 de la table lambda neutre java
Quarkus enregistre Java Lambda! ??
Exécutez PostgreSQL sur Java
Comprendre les expressions lambda Java 8
Variations d'expressions lambda Java
Qu'est-ce que l'encapsulation Java?
Vous pouvez le faire tout de suite avec Serverless Framework Serverless with AWS (API + Lambda [java] est facile à configurer)
Fonctionnalité d'expression lambda Java 8
mémo d'expression java lambda
À propos des expressions Java lambda
Qu'est-ce que la technologie Java?
Qu'est-ce que Java API-java
expression lambda java [écriture de notes]
Expliquer les expressions lambda Java 8
Etudier Java 8 (expression lambda)
Évaluer java8 ~ Type Lambda ~
Expression lambda Java à nouveau
[Java] Qu'est-ce que flatMap?
[Java] Qu'est-ce que ArrayList?
Créer un SlackBot avec AWS lambda et API Gateway en Java
Comment déployer une application kotlin (java) sur AWS Fargate
Conseils autour de l'exemple pour publier Lambda de Java sur CodePipeline
[Java] Code difficile à remarquer mais terriblement lent
Gestion des versions Java sur macOS
Utiliser des couches Lambda avec Java
Qu'est-ce que l'assertion Java? Résumé.
Installez OpenJDK7 (JAVA) sur ubuntu 14.04
Rétrograder Java sur openSUSE Linux
En passant Java Gold SE 8
Oracle Java 8 sur Docker Ubuntu
Flux Java8, résumé de l'expression lambda
Avec [AWS] CodeStar, vous pouvez créer un projet Spring (Java) s'exécutant sur Lambda en seulement 3 minutes! !!
[Java] Introduction à l'expression lambda
Installez Java sur WSL Ubuntu 18.04
Qu'est-ce qu'une collection Java?
[Windows] Le code Java est déformé
Qu'est-ce qu'une expression lambda?
Exécutez l'applet java sur ubuntu