Lambda 관리형 인스턴스용 Java 런타임
Java 런타임의 경우 Lambda 관리형 인스턴스는 동시성을 위해 OS 스레드를 사용합니다. Lambda는 초기화 중에 실행 환경별로 한 번씩 핸들러 객체를 로드한 다음 여러 개의 스레드를 생성합니다. 이러한 스레드는 병렬로 실행되고 상태 및 공유 리소스의 스레드 안전 처리가 필요합니다. 각 스레드는 동일한 핸들러 객체와 모든 정적 필드를 공유합니다.
동시성 구성
Lambda가 각 실행 환경에 보내는 최대 동시 요청 수는 함수 구성의 PerExecutionEnvironmentMaxConcurrency 설정으로 제어됩니다. 이 설정은 선택 사항이며, 기본값은 런타임에 따라 달라집니다. Java 런타임의 경우 기본값은 vCPU당 32개 동시 요청이며, 직접 값을 구성할 수도 있습니다. 또한 이 값은 Java 런타임에서 사용하는 스레드 수를 결정합니다. Lambda는 각 실행 환경의 용량에 따라 구성된 최대 수까지 동시 요청 수를 자동으로 조정하여 이러한 요청을 수용합니다.
다중 동시성 함수 빌드
Lambda 관리형 인스턴스를 사용할 때는 다른 다중 스레드 환경에서와 동일한 스레드 안전 관행을 적용해야 합니다. 핸들러 객체는 모든 런타임 작업자 스레드에서 공유되기에 변경 가능한 상태는 스레드 안전 상태여야 합니다. 여기에는 컬렉션, 데이터베이스 연결 및 요청 처리 도중 수정된 모든 정적 객체가 포함됩니다.
AWS SDK 클라이언트는 스레드 안전 상태이기에 별도의 처리가 필요하지 않습니다.
예제: 데이터베이스 연결 풀
다음 코드는 스레드 간에 공유되는 정적 데이터베이스 연결 객체를 사용합니다. 사용되는 연결 라이브러리에 따라 스레드가 안전하지 않을 수 있습니다.
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(); } }
스레드에 있어 안전한 방식은 연결 풀을 사용하는 것입니다. 다음 예제에서 함수 핸들러는 풀에서 연결을 검색합니다. 연결은 단일 요청의 컨텍스트에서만 사용됩니다.
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(); } }
예제: 컬렉션
표준 Java 컬렉션은 스레드에 있어 안전하지 않습니다.
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"; } }
대신 다음 스레드 안전 컬렉션을 사용합니다.
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"; } }
공유 /tmp 디렉터리
/tmp 디렉터리는 실행 환경의 모든 동시 요청에서 공유됩니다. 동일한 파일에 대한 동시 쓰기로 인해 다른 프로세스가 파일을 덮어쓰는 등 데이터가 손상될 수 있습니다. 이를 해결하려면 공유 파일에 대한 파일 잠금을 구현하거나 스레드 또는 요청별로 고유한 파일 이름을 사용하여 충돌을 방지합니다. 사용 가능한 공간이 소진되지 않도록 불필요한 파일을 정리해야 합니다.
로깅
다중 동시 시스템에서는 로그 인터리브(로그에서 서로 다른 요청의 로그 항목이 인터리브됨)가 정상적인 동작입니다.
Lambda 관리형 인스턴스를 사용하는 함수는 항상 고급 로깅 제어가 도입된 구조화된 JSON 로그 형식을 사용합니다. 이 형식에는 requestId가 포함되어 로그 항목을 단일 요청과 연관시킬 수 있습니다. context.getLogger()의 LambdaLogger 객체를 사용하면 requestId가 각 로그 항목에 자동으로 포함됩니다. 자세한 내용은 Java에서 Lambda 고급 로깅 제어 사용을 참조하세요.
요청 컨텍스트
context 객체는 요청 스레드에 바인딩됩니다. context.getAwsRequestId()를 사용하면 현재 요청의 요청 ID에 대해 스레드 안전 액세스가 가능합니다.
context.getXrayTraceId()를 사용하여 X-Ray 트레이스 ID에 액세스합니다. 이렇게 하면 현재 요청의 트레이스 ID에 대한 스레드 안전 액세스 권한이 제공됩니다. Lambda는 Lambda 관리형 인스턴스에서 _X_AMZN_TRACE_ID 환경 변수를 지원하지 않습니다. AWS SDK를 사용할 때 X-Ray 트레이스 ID가 자동으로 전파됩니다.
프로그램에서 가상 스레드를 사용하거나 초기화 도중 스레드를 생성하는 경우 필요한 요청 컨텍스트를 스레드에 전달해야 합니다.
초기화 및 종료
함수 초기화는 실행 환경당 한 번 발생합니다. 초기화 도중 생성된 객체는 스레드 간에 공유됩니다.
확장이 포함된 Lambda 함수의 경우 실행 환경은 종료 중에 SIGTERM 신호를 내보냅니다. 이 신호는 확장에서 버퍼 비우기와 같은 정리 태스크를 트리거하는 데 사용됩니다. SIGTERM 이벤트를 구독하여 데이터베이스 연결 종료와 같은 함수 정리 태스크를 트리거할 수 있습니다. 실행 환경 수명 주기에 대한 자세한 내용은 Lambda 실행 환경 수명 주기 이해를 참조하세요.
종속성 버전
Lambda 관리형 인스턴스에는 다음과 같은 최소 패키지 버전이 필요합니다.
-
AWS SDK for Java 2.0: 버전 2.34.0 이상
-
AWS X-Ray SDK for Java: 버전 2.20.0 이상
-
AWS Distro for OpenTelemetry - Instrumentation for Java: 버전 2.20.0 이상
-
Powertools for AWS Lambda(Java): 버전 2.8.0 이상
Powertools for AWS Lambda(Java)
Powertools for AWS Lambda(Java)는 Lambda 관리형 인스턴스와 호환되고 로깅, 추적, 지표 등을 위한 유틸리티를 제공합니다. 자세한 내용은 Powertools for AWS Lambda(Java)