Lambda 함수의 Java 런타임 시작 동작 사용자 지정

Lambda 함수의 Java 런타임 시작 동작 사용자 지정 (Customize Java runtime startup behavior for Lambda functions)

이 페이지는 AWS Lambda의 Java 함수에 특정한 설정을 설명합니다. 이러한 설정을 사용해 Java 런타임 시작 동작을 사용자 지정할 수 있습니다. 이렇게 하면 코드를 수정하지 않고도 전체 함수 대기 시간을 줄이고 전체 함수 성능을 향상할 수 있습니다.

출처: AWS Lambda 개발자 안내서

본문

JAVA_TOOL_OPTIONS 환경 변수 이해

Java에서 Lambda는 JAVA_TOOL_OPTIONS 환경 변수를 지원해 Lambda에 추가 명령줄 변수를 설정합니다. 이 환경 변수를 다양한 방식으로 사용할 수 있습니다. 예를 들어 계층형 컴파일(tiered-compilation) 설정을 사용자 지정할 수 있습니다. 다음 예제는 이 사용 사례에 JAVA_TOOL_OPTIONS 환경 변수를 사용하는 방법을 보여줍니다.

예시: 계층형 컴파일 설정 사용자 지정

계층형 컴파일(tiered compilation)은 Java 가상 머신(JVM)의 기능입니다. 특정 계층형 컴파일 설정을 사용해 JVM의 JIT(just-in-time) 컴파일러를 최대한 활용할 수 있습니다. 일반적으로 C1 컴파일러는 빠른 시작 시간에 최적화되어 있습니다. C2 컴파일러는 최상의 전체 성능에 최적화되어 있지만 더 많은 메모리를 사용하고 달성하는 데 더 오랜 시간이 걸립니다.

계층형 컴파일에는 5가지 수준이 있습니다. 수준 0에서 JVM은 Java 바이트 코드를 해석합니다. 수준 4에서 JVM은 C2 컴파일러를 사용해 애플리케이션 시작 중에 수집된 프로파일링 데이터를 분석합니다. 시간이 지남에 따라 코드 사용을 모니터링해 최상의 최적화를 식별합니다.

계층형 컴파일 수준을 사용자 지정하면 Java 함수 성능을 조정하는 데 도움이 될 수 있습니다. 빠르게 실행되는 작은 함수의 경우 계층형 컴파일을 수준 1로 설정하면 JVM이 C1 컴파일러를 사용하게 하여 콜드 스타트 성능을 개선하는 데 도움이 됩니다. 이 설정은 최적화된 네이티브 코드를 빠르게 생성하지만 프로파일링 데이터를 생성하지 않으며 C2 컴파일러를 사용하지 않습니다. 더 크고 계산 집약적인 함수의 경우 계층형 컴파일을 수준 4로 설정하면 각 Lambda 실행 환경이 프로비저닝된 후 첫 호출 동안 추가 메모리 소비와 추가 최적화 작업을 희생해 전체 성능을 최대화합니다.

Java 11 런타임 이하의 경우 Lambda는 기본 JVM 계층형 컴파일 설정을 사용합니다. Java 17과 Java 21의 경우 Lambda는 기본적으로 계층형 컴파일이 수준 1에서 중지되도록 JVM을 구성합니다. Java 25부터 Lambda는 여전히 기본적으로 계층형 컴파일을 수준 1에서 중지합니다. 단, SnapStart나 프로비저닝된 동시성을 사용하는 경우에는 기본 JVM 설정을 사용합니다.

이는 SnapStart와 프로비저닝된 동시성의 성능을 향상시킵니다. 이러한 경우 계층형 컴파일이 호출 경로 밖에서 수행되므로 콜드 스타트 불이익이 없습니다. 이 이점을 최대화하려면 priming을 사용할 수 있습니다. 즉 SnapStart 스냅샷을 찍기 전이나 프로비저닝된 동시성 실행 환경이 사전 프로비저닝될 때 함수 초기화 중에 코드 경로를 실행해 JIT를 트리거하는 것입니다. 자세한 내용은 블로그 게시물 "Optimizing cold start performance of AWS Lambda using advanced priming strategies with SnapStart"를 참조하세요.

계층형 컴파일 설정 사용자 지정 (콘솔):

  1. Lambda 콘솔의 Functions(함수) 페이지를 엽니다.
  2. 계층형 컴파일을 사용자 지정하려는 Java 함수를 선택합니다.
  3. Configuration(구성) 탭을 선택한 다음 왼쪽 메뉴에서 Environment variables(환경 변수) 를 선택합니다.
  4. Edit(편집) 을 선택합니다.
  5. Add environment variable(환경 변수 추가) 을 선택합니다.
  6. 키에 JAVA_TOOL_OPTIONS를 입력합니다. 값에 -XX:+TieredCompilation -XX:TieredStopAtLevel=1을 입력합니다.
  7. Save(저장) 를 선택합니다.

참고

Lambda SnapStart를 사용해 콜드 스타트 문제를 완화할 수도 있습니다. SnapStart는 실행 환경의 캐시된 스냅샷을 사용해 시작 성능을 크게 향상합니다. SnapStart 기능, 제한 사항, 지원 리전에 대한 자세한 내용은 Lambda SnapStart로 시작 성능 개선을 참조하세요.

예시: JAVA_TOOL_OPTIONS로 GC 동작 사용자 지정

Java 11 런타임은 가비지 컬렉션에 Serial 가비지 컬렉터(GC)를 사용합니다. 기본적으로 Java 17 런타임도 Serial GC를 사용합니다. 그러나 Java 17에서는 JAVA_TOOL_OPTIONS 환경 변수를 사용해 기본 GC를 변경할 수도 있습니다. Parallel GC와 Shenandoah GC 중에서 선택할 수 있습니다.

예를 들어 워크로드가 더 많은 메모리와 여러 CPU를 사용한다면 성능 향상을 위해 Parallel GC 사용을 고려하세요. JAVA_TOOL_OPTIONS 환경 변수의 값에 다음을 추가하면 됩니다:

-XX:+UseParallelGC

워크로드에 수명이 짧은 객체가 많다면 Java 25에서 도입된 Shenandoah 가비지 컬렉터의 세대(generational) 모드를 활성화해 더 낮은 메모리 소비의 이점을 얻을 수 있습니다. 이렇게 하려면 JAVA_TOOL_OPTIONS 환경 변수의 값에 다음을 추가하세요:

-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational

Log4Shell용 Log4j 패치

Java 8, 11, 17, 21용 Lambda 런타임에는 인기 있는 Java 로깅 프레임워크인 Log4j의 Log4Shell 취약성(CVE-2021-44228)을 완화하는 패치가 포함되어 있습니다. 이 패치는 콜드 스타트 성능 오버헤드를 발생시킵니다. 패치된 Log4j 버전(2.17.0 이상)을 사용한다면 콜드 스타트 성능을 개선하기 위해 이 패치를 비활성화할 수 있습니다. 패치를 비활성화하려면 AWS_LAMBDA_DISABLE_CVE_2021_44228_PROTECTION 환경 변수를 true로 설정하세요.

Java 25부터 Lambda 런타임은 더 이상 Log4Shell 패치를 포함하지 않습니다. Log4j 버전 2.17.0 이상을 사용하는지 확인해야 합니다.

AOT(Ahead-of-Time) 및 CDS 캐시

Java 25부터 Lambda 런타임에는 Java 런타임 인터페이스 클라이언트(RIC)에 대한 AOT(Ahead-of-Time) 캐시가 포함됩니다. RIC는 Lambda 런타임 API에서 이벤트를 능동적으로 폴링하는 런타임 구성 요소입니다. 이는 콜드 스타트 성능을 개선합니다.

AOT 캐시는 특정 JVM 빌드에 한정됩니다. Lambda가 관리형 런타임을 업데이트하면 RIC용 AOT 캐시도 업데이트합니다. 그러나 자체 AOT 캐시를 배포했다면 런타임 업데이트 후 무효화되거나 예기치 않은 동작이 발생할 수 있습니다. 따라서 관리형 런타임을 사용할 때는 AOT 캐시를 사용하지 않는 것을 강력히 권장합니다. AOT 캐시를 사용하려면 컨테이너 이미지를 사용해 함수를 배포해야 합니다.

AOT 캐시는 CDS(Class Data Sharing) 캐시와 함께 사용할 수 없습니다. Lambda 함수에 CDS 캐시를 배포하면 Lambda는 AOT 캐시를 비활성화합니다.

더 알아보기 (Learn more)

  • Lambda SnapStart
  • Java 런타임 환경 변수
  • Lambda 계층형 컴파일 및 가비지 컬렉터