Kubernetes 이야기

컨테이너 환경에서 JVM Memory 설정 본문

Kubernetes/일반

컨테이너 환경에서 JVM Memory 설정

kmaster 2022. 5. 10. 18:27
반응형

일반적으로 Java App에서 Heap Space를 조절하기 위해서는 JAVA OPT 를 Xms, Xmx로 설정이 일반적이다.

java -Xms512m -Xmx512m test.jar

 

하지만 Kubernetes의 Container 환경에서는 사이즈를 고정하는 부분은 많은 고민이 필요하다. 왜냐하면 Kubernetes에서 Pod 를 생성시에는 resource 를 설정할 수 있기 때문이다.

  containers:
  - name: tomcat
    image: tomcat:9
    env:
    - name: JAVA_OPTS
      value: "-Xms1024m -Xmx1024m"
    resources:
      requests:
        memory: "500Mi"
      limits:
        memory: "500Mi"

 

위와 같이 Container에 memory 제한을 설정하고, Tomcat memory설정에는 최대 1024m 로 설정하는 OOMKiller에 의해 Container가 재기동 될 수 있다.

Container resource에 제한이 없는 경우 물리적인 메모리가 1G 이상이라면 정상적으로 운영될 수는 있을 것이다.

 

Container에 가급적 resource 제한을 설정하는 것을 권장하기 때문에 일반적으로 설정하는 JAVA_OPTS의 -Xms와 -Xmx는 Kubernetes환경에서는 맞지 않는다.

 

그래서, OpenJDK에서는 UseContainerSupport 옵션이 지원된다. ( 기본값 True )

 

그럼 Container 환경에서 Java application의 메모리 설정방법을 알아보자.

 

-XX:InitialRAMPercentage

 

'-XX:InitialRAMPercentage'는 '-Xms' JVM 인수가 전달되지 않은 경우에만 초기 힙 크기를 설정하는데 사용된다. 

 

'-Xms' JVM 인수가 설정되면 이 옵션은 무시한다.

 

-XX:MaxRAMPercentage, -XX:MinRAMPercentage

 

컨테이너에 1GB의 메모리를 할당했다고 가정하고 -XX:MaxRAMPercentage=50을 구성하면 약 512GB(1GB의 1/2)가 Java 힙 크기에 할당된다.

 

'-XX:MaxRAMPercentage' 및 '-XX:MinRAMPercentage'는 모두 최대 Java 힙 크기를 결정하는 데 사용된다.

 

'-XX:MinRAMPercentage' JVM 인수는 물리적 서버(또는 컨테이너)에서 사용 가능한 전체 메모리 크기가 약 250MB 미만인 경우에만 Java 힙 크기를 계산하는 데 사용된다. -XX:MinRAMPercentage=50을 구성하고 전체 물리적 메모리(또는 컨테이너) 메모리가 100MB라고 가정하면 Java 애플리케이션의 최대 힙 크기는 50MB(즉, 100MB의 50%)로 설정된다.

 

'-XX:MaxRAMPercentage' JVM 인수는 물리적 서버(또는 컨테이너)에서 사용 가능한 전체 메모리 크기가 250MB(대략) 이상인 경우에만 Java 힙 크기를 계산하는 데 사용된다. -XX:MaxRAMPercentage=75를 구성하고 전체 물리적 서버(또는 컨테이너) 메모리가 1GB라고 가정하면 Java 애플리케이션의 최대 힙 크기는 750MB(즉, 1GB의 75%)로 설정된다.

 

-XX:MaxRAMPercentage, -XX:MinRAMPercentage 옵션은 OpenJDK8 u191 이상에서만 지원된다.
'-Xms' JVM 인수가 설정되면 이 옵션들은 무시된다.

 

그럼 한번 설정을 해보자.

 

# cat <<EOF | kubectl create -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: openjdk
spec:
  template:
    spec:
      containers:
      - name: openjdk
        image: docker.io/openjdk:10
        command: ["java", "-XX:InitialRAMPercentage=25", "-XX:MaxRAMPercentage=50", "-XshowSettings:all", "-version"]
      restartPolicy: Never
  backoffLimit: 4
EOF

# kubectl logs openjdk-j674q
[root@master ~]# k logs openjdk-dr4fm
VM settings:
    Max. Heap Size (Estimated): 7.56G
    Using VM: OpenJDK 64-Bit Server VM
...
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-2, mixed mode)


# free -h
              total        used        free      shared  buff/cache   available
Mem:           15Gi       1.8Gi        10Gi        41Mi       3.3Gi        13Gi

 

위의 정보를 보면 MaxRAMPercentage=50으로 설정했다. jvm 정보를 보면 7.56G 가 최대 Heap Size로 설정되었다. 이유는 노드의 메모리가 15Gi이기 때문에 15G의 50%로 설정된 것이다.

 

이제 kubernetes에 resource 설정을 한 후 테스트해보자.

 

# cat <<EOF | kubectl create -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: openjdk
spec:
  template:
    spec:
      containers:
      - name: openjdk
        image: docker.io/openjdk:10
        command: ["java", "-XX:InitialRAMPercentage=25", "-XX:MaxRAMPercentage=50", "-XshowSettings:all", "-version"]
        resources:
          limits:
            memory: "1000Mi"
          requests:
            memory: "1000Mi"
      restartPolicy: Never
  backoffLimit: 4
EOF

# kubectl logs openjdk-55tgd
VM settings:
    Max. Heap Size (Estimated): 483.38M
    Using VM: OpenJDK 64-Bit Server VM

...
openjdk version "10.0.2" 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Debian-2)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Debian-2, mixed mode)

 

위와 같이 최대 메모리를 1G 로 Resource를 제한하면 Java의 Heap Memory는 50%인 500M 정도 설정됨을 확인할 수 있다.

 

결론

 

Java에서는 Heap Memory외에 non-heap ( GC, Metaspce, Code ... )의 영역이 있기 때문에 Resource 의 limit 값보다 적게 설정되어야 한다. ( JNI를 사용하는 경우는 JNI 영역에 필요한 메모리를 별도 계산해야 한다. ) 

 

그래서 보통 limit의 70~80% 정도로 heap memory 설정을 하면 OOM Killer가 작동하지 않고 운영될 수 있다.

 

 

참고

https://www.ibm.com/docs/en/sdk-java-technology/8?topic=options-xx-usecontainersupport 

https://songrgg.github.io/operation/how-to-setup-java-application-memory-limit-in-kubernetes/

https://dzone.com/articles/best-practices-java-memory-arguments-for-container

https://github.com/docker-library/openjdk/issues/245

https://blog.softwaremill.com/docker-support-in-new-java-8-finally-fd595df0ca54

반응형
Comments