일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- OneToMany
- chroot exit code
- SpringBoot 2.0
- docker
- mybatis
- OneToOne
- 디자인 패턴
- 활성프로브
- JDK
- 변경 감지
- OracleJDK
- exit code
- Design Pattern
- 다중 트랜잭션
- openjdk
- Entity
- JPA
- Multi Transaction
- ManyToMany
- Multi Datasource
- ManyToOne
- MaxRAMPercentage
- 영속화
- 다중 데이타소스
- Java
- 트랜잭션 쓰기 지연
- K8s
- SpringBoot
- dirty check
- 종료코드
- Today
- Total
조금 평범한 개발 이야기
k8s, docker 에서 jvm 설정 최적화 하기 본문
개요
k8s 는 워커의 자원 (cpu, memory) 을 공유하기 때문에 리소스 제한을 통해 파드가 사용할 자원을 미리 정의 합니다.
이는 워커에 있는 파드들이 요구하는 자원이 워커의 자원을 넘어서는 오버커밋 상태가 되었을때 특정 파드가 종료되거나 이상 동작되는 것을 막기 위함 입니다.
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
SPRING BOOT 으로 구성되었고 xms, xmx 메모리 설정이 아래와 같이 run.sh 에 1g 로 설정된 이미지가 있다고 가정해 보겠습니다.
# Dockerfile
ENTRYPOINT ["./run.sh"]
#!/usr/bin/env bash
exec java \
-jar /usr/local/service/app.jar
-Xms1g \
-Xmx1g \
해당 이미지를 올린 파드는 보기에는 아무런 문제가 없어 보이지만 파드 리소스 제한과 jvm 최대 메모리 설정을 동일하게 1g 로 맞추면 oom killed 처리가 되면서 파드가 계속 재시작되는 현상이 발생 됩니다.
이것은 k8s 컨테이너가 실행될때 단지 spring boot jar 만 실행되는 것이 아니라 컨테이너가 실행되기 위한 최소 메모리가 필요하기 때문 입니다.
- requests.memory ≠ Xms
- limits.memory ≠ Xmx
JDK 8,9
jdk 8u131 과 jdk 9 에서는 이러한 문제를 해결하기 위해 UnlockExperimentalVMOptions, UseCGroupMemoryLimitForHeap 설정을 제공하는데 실행되는 컨테이너의 메모리 크기를 인식해 컨테이너 메모리의 25% 비율로 힙 메모리를 할당해 줍니다.
$ docker run -m 1GB openjdk:8u191-alpine java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XshowSettings:vm \
-version
VM settings:
Max. Heap Size (Estimated): 247.50M
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
하지만 컨테이너에 할당된 메모리를 25% 만 쓰는건 비효율적이기 때문에 해당 비율을 조금 높이고 싶다면 MaxRAMFraction 설정을 통해 크기를 늘릴 수 있습니다.
MaxRAMFraction 값이 1이면 메모리 전체(100%)를 사용하겠다는 의미이고 2이면 (50%), 3이면 (33%)의 메모리를 할당 합니다.
$ docker run -m 1GB openjdk:8u191-alpine java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:MaxRAMFraction=2 \
-XshowSettings:vm \
-version
VM settings:
Max. Heap Size (Estimated): 494.94M
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VM
JDK 10+
jdk 10 이후 부터는 컨테이너에 대한 지원이 강화되어 컨테이너에서 설정한 메모리를 자동으로 인식하고 적용됩니다. 즉 아무런 설정을 하지 않는다고 해도 자동으로 25% 비율로 메모리가 설정이 됩니다.
$ docker run -m 1GB openjdk:10 java \
-XshowSettings:vm \
-version
VM settings:
Max. Heap Size (Estimated): 247.50M
Using VM: OpenJDK 64-Bit Server VM
그리고 동일하게 MaxRAMFraction 값으로 해당 메모리 비율을 조정 할 수 있습니다.
$ docker run -m 1GB openjdk:10 java \
-XX:MaxRAMFraction=2 \
-XshowSettings:vm \
-version
VM settings:
Max. Heap Size (Estimated): 494.94M
Using VM: OpenJDK 64-Bit Server VM
비율 최적화
앞서 컨테이너 힙 메모리를 비율을 통해 설정할 수 있다고 이야기 드렸지만 100%, 50%, 33% 비율로 메모리를 설정 하기에는 아직도 낭비되는 메모리가 많다고 느껴집니다.
이를 위해 MinRAMPercentage, MaxRAMPercentage 설정을 제공하는데 각각 힙 메모리의 최소, 최대 메모리를 설정 할 수 있습니다.
$ docker run -m 1GB openjdk:11 java \
-XX:MinRAMPercentage=50.0 \
-XX:MaxRAMPercentage=80.0 \
-XshowSettings:vm \
-version
VM settings:
Max. Heap Size (Estimated): 792.69M
Using VM: OpenJDK 64-Bit Server VM
XX:MaxRAMPercentage 설정값은 컨테이너에 할당된 메모리 크기에 따라 다르겠지만 75-80 정도가 컨테이너가 동작되는 메모리를 고려한 적정 수준으로 보여집니다.
결론
k8s 컨테이너에 JVM 을 올리려면 Xms, Xmx 설정 말고 MinRAMPercentage, MaxRAMPercentage 설정을 쓰자.
참고
'개발 > docker & k8s' 카테고리의 다른 글
k8s 컨테이너가 종료될때 원인 파악하기 (0) | 2021.08.06 |
---|---|
k8s 리소스 제한 하기 (0) | 2021.07.24 |
KUBERNETES DASHBOARD 사용하기 (3) | 2019.10.15 |