본 블로그는 baeldung 홈페이지에 게시되어 있는 글을 참조하여 실습한 경험을 작성하였습니다.
-XX:+UseContainerSupport
에 대해 이해합니다.UseContainerSupport
백포팅이 적용됨을 확인합니다.["-Xms", "-Xmx"]
관계를 파악할 수 있습니다.Java 컨테이너의 기본 힙 설정
과거에는 JVM이 컨테이너에 할당된 메모리와 CPU를 인식하지 못했습니다.
Java 10
은 근본 원인을 수정하기 위해+UseContainerSupport
(기본적으로 활성화됨) 라는 새로운 설정을 도입했으며 개발자는 수정 사항을8u191
의Java 8
로 백포트했습니다.
JVM은 이제 컨테이너에 할당된 메모리를 기반으로 메모리를 계산합니다.
컨테이너 환경에서 Java를 실행할 때 사용가능한 리소스를 지정할 수 있습니다.
Java 프로세스를 실행하는 컨테이너에서 JVM 매개 변수를 설정하는 방법을 살펴봅니다.
특정 버전의 Java로 실행되는 프로그램을 컨테이너화하는 일반적인 문제와 일부 컨테이너화된 Java 애플리케이션에서 플래그를 설정하는 방법을 살펴봅니다.
테스트를 위한 코드는 github repo 에 배포되어 있습니다.
Xms, Xmx 및 UseContainerSupport
의 설정에 대해서 각각 로컬에서의 동작에 대한 테스트와 AWS ECS에서의 테스트로 진행하였습니다.
조건
JDK 8u191
JAVA Container none none
✅ Result
Initial Memory Max Memory 250mb 3545mb
-Xmx 또는 -Xms JVM 플래그를 제공하지 않았기 때문에 메모리 설정이 기본값으로 설정됩니다.
oldjava
로 빌드된 기본 이미지로 컨테이너를 실행해 보겠습니다.
컨테이너는 현재 설정된 Initial Memory
및 Max Memory
에 대한 내용을 출력하고 종료되며, 종료 즉시 삭제 됩니다.(--rm
옵션)
조건
JDK 8u191
JAVA Container none 1G Limit
✅ Result
Initial Memory Max Memory 250mb 3545mb
컨테이너 메모리를 1GB로 제한하여 다시 이미지를 실행합니다.
컨테이너의 메모리를 제한해도 결과는 동일한 것을 확인할 수 있습니다. JVM이 컨테이너의 메모리 할당을 고려하고 있지 않는 것을 알 수 있습니다.
동일한 테스트 프로그램으로 Dockerfile
의 첫 번째 줄을 변경하여 최신 JVM 8을 사용하여 테스트를 진행합니다.
FROM openjdk:8-jdk-alpine
조건
JDK 8u130
JAVA Container none none
✅ Result
Initial Memory Max Memory 250mb 3545mb
oldjava
의 경우와 동일하게 여기서도 컨테이너의 리소스를 제한하지 않고 별도의 설정이 없는 경우 전체 도커 호스트 메모리
를 사용하여 JVM 힙 크기를 계산하는것을 확인할 수 있습니다.
조건
JDK 8u130
JAVA Container none 1G Limit
✅ Result
Initial Memory Max Memory 16mb 247.5mb
컨테이너 메모리를 1GB로 제한하여 다시 이미지를 실행합니다.
컨테이너에 1GB의 RAM을 할당하는 경우 JVM이 컨테이너에서 사용할 수 있는 1GB RAM을 기준으로 힙 크기를 계산하는것을 확인 할 수 있습니다.
조건
JDK 8u130
JAVA Container -Xms=500 -Xmx=2G 1G Limit
✅ Result
Initial Memory Max Memory 500mb 1979.75mb
JAVA_OPTS 환경 변수를 지정하여 런타임에 메모리 설정을 선택할 수 있습니다.
Xmx 매개변수와 JVM에서 보고하는 최대 메모리 사이에는 약간의 차이가 발생합니다. 이는 Xmx가 힙, 가비지 수집기의 생존 공간 및 기타 풀을 포함하는 메모리 할당 풀의 최대 크기를 설정하기 때문입니다.
Xms, Xms 매개변수 사용하는 경우
docker run -it --rm -e JAVA_OPTS="-Xms500M -Xmx2G" --memory=1G newjava
컨테이너 메모리 제한과는 무관하게 매개변수의 값으로 자바의 메모리가 할당되는 것을 확인할 수 있습니다.
AWS ECS에서 해당 매개변수를 가지고 어떤 방식으로 관리할 수 있는지 확인합니다.
이미지는 newjava
를 이용하여 테스트를 진행하였습니다.
Taskdefinition에서 할당한 Fargate의 크기는 아래와 같습니다.
- vCPU - 0.5G
- Memory - 1G
ECS 작업정의서에는 메모리의 자원을 관리하기 위한 두가지 매개변수가 존재합니다. 소프트 제한
, 하드 제한
소프트 제한이란?
taskdefinition.json
의memoryReservation
에 해당하며, 컨테이너가 확보(예약)할 메모리를 설정하는 매개변수입니다.
하드 제한이란?
taskdefinition.json
의memory
에 해당하며, 컨테이너가 확장할 수 있는 제한을 설정합니다.
조건
JDK 8u130
JAVA Container none none
✅ Result
Initial Memory Max Memory 124mb 1894.688mb
newjava
이미지를 ECS에서 실행합니다.
별도의 매개변수 없이 컨테이너를 실행 할 경우 파게이트의 리소스 제한인 1G를 넘어선 1894mb가 Max Memory로 설정되는 것을 확인할 수 있었습니다.
실제 환경에서 아무런 설정없이 구동시 힙메모리가 상승한다면 컨테이너가 불시에 종료 될 수 있는 장애 포인트가 될 수 도 있습니다.
조건
JDK 8u130
JAVA Container none (soft)1G Limit
✅ Result
Initial Memory Max Memory 124mb 1894.688mb
Taskdefinition의 소프트 제한
을 1024
로 설정하고 컨테이너를 실행하였습니다.
Default로 실행한 컨테이너와 동일한 구성으로 동작하는것을 확인할 수 있습니다.
조건
JDK 8u130
JAVA Container none (hard)1G Limit
✅ Result
Initial Memory Max Memory 16mb 247.5mb
Taskdefinition의 하드 제한
을 1024
로 설정하고 컨테이너를 실행하였습니다.
위의 두 케이스와는 달리 JVM이 컨테이너의 Initial / Max Memory
설정 값을 조정한 것을 확인할 수 있습니다.
조건
JDK 8u130
JAVA Container -Xms50m -Xmx50m (hard)1G Limit
✅ Result
Initial Memory Max Memory 50mb 48.375mb
Taskdefinition의 하드 제한
을 1024
로 설정하고 환경변수로 JAVA_OPTS="-Xms50m -Xmx50m"
을 적용하여 컨테이너를 실행하였습니다.
위의 두 케이스와는 달리 JVM이 컨테이너의 Initial / Max Memory
설정 값을 조정한 것을 확인할 수 있습니다.
조건
JDK 8u130
JAVA Container -Xms2048m -Xmx2048m (hard)1G Limit
✅ Result
Initial Memory Max Memory 2048mb 1979.75mb
Taskdefinition의 하드 제한
을 1024
로 설정하고 환경변수로 JAVA_OPTS="-Xms2048m -Xmx2048m"
태스크에 할당된 리소스보다 더 큰 값으로 매개변수를 적용하여 실행하였습니다.
태스크에 할당된 리소스보다 더 큰 값으로 적용되어 자바가 동작된 것을 확인할 수 있습니다.
JDK 8u130 이후 버전을 사용하는 경우 -Xms, -Xmx
설정을 통해 서비스의 크기를 조정할 수 있었습니다.
-XX:+UseContainerSupport
설정과 함께 -XX:InitialRAMPercentage, -XX:MinRAMPercentage, -XX:MaxRAMPercentage
파라미터를 이용하여 컨테이너의 크기에 따라 서비스의 메모리를 동적으로 관리할 수 있습니다.
이 블로그를 통해 컨테이너 환경에서 잘 동작하는 기본 메모리 설정 -XX:+UseContainerSupport
이 포함된 JVM의 버전을 확인하여 사용해야 하는 필요성에 대해 알아보았습니다.
또한 사용자 지정 컨테이너 이미지에서 -Xms 및 -Xmx를 설정하는 사례와 기존 Java 애플리케이션 컨테이너를 사용하여 JVM 옵션을 설정하는 방법을 살펴보았습니다.
마지막으로 AWS ECS에 컨테이너를 직접 배포하여 ECS에서 -XX:+UseContainerSupport
매개변수를 동작 시킬 수 있는 환경을 파악하고 JAVA_OPTS 매개변수(-Xms
,-Xmx
)를 환경변수로 적용하여 사용하는 방법을 파악할 수 있었습니다.