GraalVM과 함께 AWS Lambda에서 Java 콜드 스타트 물리치기

12842 단어
동료, 친구, 심지어 가족들의 조언에도 불구하고 자바로 빠른 lambda를 만들고 싶습니다.조금이라도 증명하기 위해서든지, 노름돈을 얻기 위해서든지, 아니면 너와 나처럼 자바 극객이기 때문이다.
이 블로그를 통해 GraalVM[1]을 사용하여 Java lambda를 미리 컴파일하여 느린 콜드 부팅 시간을 없애도록 안내합니다.

콜드 시동, 뭐, 어디, 언제?


lambda를 처음 호출할 때, AWS는 코드를 실제 호출하기 전에 정확하게 실행될 때 용기를 시작합니다.NodeJs나 Python 등을 사용하여 실행할 때 콜드 부팅 시간은 200-250ms[2] 사이이고 Java를 사용할 때는 함수 코드의 구체적인 상황에 따라 650ms가 필요합니다.
Java의 콜드 부팅은 주로 JVM에 의해 발생하며, JVM은 AWS에서 미리 설정한 Java를 실행할 때 기본적으로 시작됩니다.다행히도 AWS는 GraalVM을 사용하여 JVM 없이 자바 코드를 바이너리 코드로 미리 컴파일할 수 있도록 자체 custom runtime 를 만드는 옵션도 제공합니다.

우리 실용적으로 하자.


간단한 Java 프로그램을 살펴보겠습니다. 예를 들어 우리의 Lambda Authorizer는 지난 블로그 글[3]에서 나온 것입니다. Github[4]에서 찾을 수 있고 GraalVM 처리에 사용할 수 있습니다.

AWS Lambda 런타임 API


사용자 정의 실행을 구축하려면 AWS Lambda가 실행될 때 API[5]와 상호작용해야 합니다.
이 API에서 우리는 세 가지 단점을 사용해야 한다.
  • /runtime/invocation/next 다음 호출 가져오기
  • /runtime/invocation/{AwsRequestId}/response 특정 호출(요청)에 대한 응답 발표

  • (요청) 호출 중 오류가 발생했습니다.
  • Github[6]에서 AWS 실행 시 API 폴링을 처리하는 간단한 부트 클래스를 찾을 수 있습니다.

    반사


    GraalVM을 미리 컴파일하는 단점 중 하나는 반사를 잘 처리하지 못한다는 것입니다. 이것은 우리가 /runtime/invocation/{AwsRequestId}/error 프로필을 만들어야 한다는 것을 의미합니다. 거기서 GraalVM을 반사할 클래스로 가리킬 수 있습니다.우리는 잭슨을 서열화 라이브러리로 사용하기 때문에, reflect.json 파일에 필요한 모든 서열화 클래스를 설정해야 한다.reflect.json 프로필의 예제 항목:
    [
      ...
      {
        "name": "nl.theguild.lambda.model.DefaultResponse",
        "allPublicMethods" : true
      },
      ...
    ]
    
    전체reflect.json 검사 Github[7]

    그림을 컴파일합니다!


    맞다재밌는 부분!현재, 우리는 이 컴퓨터의 이미지 컴파일링을 위해 자바 프로젝트를 준비했는데, 어떻게 완성되었는지 봅시다.
    우선, 우리는jar가 우리의mainClass를 설명하는 적당한 목록을 첨부해야 한다. 이것은 아래의 설정을 우리reflect.json에 추가해서 완성할 수 있다.
    <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.0.2</version>
        <configuration>
            <archive>
                <manifest>
                    <mainClass>nl.theguild.lambda.Main</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>
    
    그리고 간단한 bash 스크립트를 만들 수 있습니다. 이 스크립트는 사용자 정의 실행 시 zip가 끝날 수 있도록 필요한 모든 절차를 수행합니다.
    단계 1:jar 파일을 만듭니다.
    mvn clean install;
    
    2단계: Docker 컨테이너에서 GraalVM을 실행하고 항목을 마운트합니다.
    docker run --rm --name graal -v $(pwd):/${PATH_TO_PROJECT} oracle/graalvm-ce:19.2.0
    
    3단계: GraalVM의 pom.xml 명령을 설치하고 실행하며 우리의 native-image 설정을 포함하고 http를 사용합니다.
    gu install native-image;
    native-image \
        -H:EnableURLProtocols=http \
        -H:ReflectionConfigurationFiles=${PATH_TO_PROJECT}/reflect.json \
        -jar ${PATH_TO_JAR};
    
    4단계: AWS Lambda에서 사용할 수 있는 이 컴퓨터의 이미지를 폴더로 이동합니다.
    mkdir /${PATH_TO_PROJECT}/target/custom-runtime;
    cp ${BINARY_RESULT} ${PATH_TO_PROJECT}/target/custom-runtime;
    
    단계 5: AWS가 네이티브 이미지를 실행하는 방법을 나타내는 파일reflect.json을 만듭니다.
    AWS는 문서[8]에 정의되어 있으며, 사용자 정의가 실행될 때마다 zip이어야 하며, 시작 함수를 뛰어넘을 수 있는 zip 셸 파일을 포함해야 한다.
    예를 들어, 부트 파일은 다음과 같은 간단한 파일이 될 수 있습니다.
    #!/bin/sh
    set -euo pipefail
    ./${PROJECT_NAME}
    
    이 모든 단계를 bash 스크립트에 추가하면 다음 파일이 생성됩니다.
    PROJECT_NAME=aws-enriching-lambda-authorizer
    PROJECT_VERSION=1.0.0
    
    # Generate Jar file
    mvn clean install;
    
    # Generate Native Image
    docker run --rm --name graal -v $(pwd):/${PROJECT_NAME} oracle/graalvm-ce:19.2.0 \
        /bin/bash -c "gu install native-image; \
                      native-image \
                            -H:ReflectionConfigurationFiles=/${PROJECT_NAME}/reflect.json \
                        -jar /${PROJECT_NAME}/target/${PROJECT_NAME}-${PROJECT_VERSION}.jar \
                        ; \
                        mkdir /${PROJECT_NAME}/target/custom-runtime \
                        ; \
                        cp ${PROJECT_NAME}-${PROJECT_VERSION} /${PROJECT_NAME}/target/custom-runtime/${PROJECT_NAME}";
    
    echo -e "#!/bin/sh \n \
    set -euo pipefail \n \
    ./${PROJECT_NAME}" > target/custom-runtime/bootstrap;
    
    # Make bootstrap executable
    chmod +x target/custom-runtime/bootstrap;
    
    # Zip
    rm $PROJECT_NAME-custom-runtime.zip
    cd target/custom-runtime || exit
    zip -X -r ../../$PROJECT_NAME-custom-runtime.zip .
    

    만세!


    우리는 지금 bootstrap AWS Lambda에서 사용할 수 있고 빠른 냉각 시동 시간을 누릴 수 있다...자바 사용 시!bootstrap->aws-enriching-lambda-authorizer-custom-runtime.zip->AWS Console로 이동하여 Lambda를 선택하고 Create function를 클릭합니다.
    현재 우리는lambda가 하나 있습니다. custom-runtime -> use default bootstrap로 이동하여 우리의zip 파일을 업로드하고 테스트 이벤트를 설정할 수 있습니다.
    권한 수여기lambda는api망에서 터치하기 때문에 기본 create 이벤트를 사용할 수 있습니다. 요청에 Actions 헤더를 추가하기만 하면 됩니다.
    우리가 지금 Amazon API Gateway AWS Proxy 을 눌렀을 때, 우리는 우리의 lambda가 "Authorization": "Bearer 12345" 에서만 응답하는 것을 보았고, 다른 운행 시의 차가운 시작 시간과 일치하여, 당신의 동료, 친구와 가족에게 보여 주었습니다!

    출처


    Github:https://github.com/VR4J/aws-enriching-lambda-authorizer/tree/feature/graal-vm

    공구서류


    [1] https://www.graalvm.org/docs/introduction/
    [2] https://levelup.gitconnected.com
    [3] https://www.kabisa.nl/tech/enriching-requests-with-an-aws-lambda-authorizer
    [4] https://github.com/VR4J/aws-enriching-lambda-authorizer
    [5] https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html
    [6] https://github.com/VR4J/aws-enriching-lambda-authorizer/blob/feature/graal-vm/src/main/java/nl/theguild/lambda/Main.java
    [7] https://github.com/VR4J/aws-enriching-lambda-authorizer/blob/feature/graal-vm/reflect.json
    [8] https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html

    좋은 웹페이지 즐겨찾기