AWS EKS 환경에서 Spring Boot Pod의 G1GC 튜닝 가이드
AWS Elastic Kubernetes Service(EKS)는 컨테이너화된 애플리케이션을 손쉽게 배포하고 관리할 수 있는 강력한 클라우드 플랫폼입니다. Spring Boot 애플리케이션은 EKS Pod에서 자주 사용되며, JVM의 G1GC(Garbage First Garbage Collector)를 활용해 안정성과 성능을 최적화할 수 있습니다. 본 포스트에서는 AWS EKS 환경에서 Spring Boot Pod의 G1GC 설정과 효과적인 튜닝 방법을 다룹니다.
AWS EKS 환경의 특징과 JVM GC 요구사항
EKS 환경에서 JVM을 운영할 때 고려해야 할 주요 사항은 다음과 같습니다:
-
컨테이너 리소스 제한
Pod는 CPU와 메모리의 상한선을 제한(Resource Limit)받으므로, GC 동작이 이를 초과하지 않도록 설정해야 합니다. -
분산 시스템에서의 안정성
예측 가능한 GC 지연 시간(Pause Time)이 중요합니다. -
수평 확장성
애플리케이션 Pod의 개수를 조정하며 GC 동작을 관찰할 필요가 있습니다.
Spring Boot에서 G1GC 활성화 및 기본 설정
Spring Boot는 JVM 설정을 쉽게 적용할 수 있습니다. Dockerfile 또는 Helm 차트에 다음과 같은 JVM 옵션을 추가하여 G1GC를 활성화할 수 있습니다.
G1GC 활성화 예제
-XX:+UseG1GC
Spring Boot 컨테이너 실행 시 설정
resources:
limits:
memory: "1Gi"
cpu: "500m"
requests:
memory: "512Mi"
cpu: "250m"
env:
- name: JAVA_OPTS
value: >
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-Xmx512m
-Xms512m
AWS EKS에서의 튜닝 전략
-
소규모 Pod (메모리 512MB~1GB)
-
추천 JVM 옵션
-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=35 -Xmx512m -Xms512m -
설명
메모리 리소스가 제한된 Pod에서는 GC를 자주 수행하여 메모리 초과를 방지합니다.
-
-
중간 규모 Pod (메모리 1GB~4GB)
-
추천 JVM 옵션
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:InitiatingHeapOccupancyPercent=45 -Xmx2g -Xms2g -
설명
적당한 Pause Time과 처리량의 균형을 위해 기본값을 유지하며 튜닝합니다.
-
-
대규모 Pod (메모리 4GB 이상)
-
추천 JVM 옵션
-XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:InitiatingHeapOccupancyPercent=60 -Xmx6g -Xms6g -
설명
더 큰 힙 크기를 사용하여 GC 빈도를 줄이고 처리량을 극대화합니다.
-
G1GC 튜닝 시 유용한 도구
- GC 로그 활성화
-Xlog:gc*:file=/var/log/gc.log:time,uptime,level,tagsGC 로그를 분석하여 Pause Time, GC 빈도 등을 확인합니다.
- Kubernetes 메트릭 관찰
- Metrics Server를 통해 메모리와 CPU 사용량을 모니터링합니다.
- Prometheus와 Grafana를 사용하여 Pod의 성능 데이터를 시각화합니다.
- Spring Actuator 활용
HeapDump,ThreadDump엔드포인트를 활성화하여 실시간 JVM 상태를 확인합니다.
실전 최적화 팁
- Pod 리소스 한도에 맞춘 JVM 설정
-Xmx값을 Pod 메모리 Limit보다 약간 낮게 설정하여 안정성을 확보합니다.
- 지속적인 GC 로그 분석
- GC Pause Time이 설정 목표를 초과하는 경우
-XX:MaxGCPauseMillis를 조정합니다.
- GC Pause Time이 설정 목표를 초과하는 경우
- 수평 확장 테스트
- Replica 수를 늘리면서 개별 Pod의 GC 성능을 비교하고 최적 설정을 찾습니다.
결론
AWS EKS에서 Spring Boot 애플리케이션을 운영할 때 G1GC는 메모리 관리와 성능 최적화에 매우 유용합니다. Pod의 리소스 제한과 분산 시스템 특성을 고려한 G1GC 튜닝은 애플리케이션의 안정성과 성능을 크게 향상시킬 수 있습니다. 본 포스트의 가이드를 활용하여 EKS 환경에서 JVM 성능을 최적화해 보세요.
CPU Request/Limit과 GC 성능 관계
EKS 환경에서 CPU request/limit 설정은 G1GC의 Concurrent 스레드 수에 직접 영향을 줍니다.
resources:
requests:
cpu: "1" # JVM이 인식하는 CPU 수 기준
memory: "2Gi"
limits:
cpu: "2" # Burst 가능한 최대 CPU
memory: "2Gi"
주의사항:
- JVM은
Runtime.getRuntime().availableProcessors()로 CPU를 감지 - CPU Limit이 낮으면 GC 스레드 수가 자동으로 줄어듦 → GC 완료 시간 증가
- CPU Request와 Limit의 차이가 클수록 GC 성능 변동성 증가
권장 설정:
# CPU Limit을 JVM 스레드 수 계산에 반영
-XX:ParallelGCThreads=2 # CPU Request 기준으로 명시 설정
-XX:ConcGCThreads=1 # Concurrent GC 스레드
CGroup v2 메모리 관리
최신 Kubernetes(1.25+)는 CGroup v2를 기본으로 사용합니다. Java 17부터 CGroup v2를 올바르게 인식합니다.
# CGroup v2 메모리 제한 인식 확인 (Java 17)
java -XX:+PrintFlagsFinal -version 2>&1 | grep UseContainerSupport
# UseContainerSupport = true (기본값)
# Container Memory Limit에 맞게 힙 자동 조정 (기본 25% of container memory)
# -XX:MaxRAMPercentage=75.0 # 컨테이너 메모리의 75% 힙 사용
권장 Dockerfile 설정:
FROM eclipse-temurin:17-jre
ENV JAVA_OPTS="-XX:+UseG1GC \
-XX:MaxRAMPercentage=75.0 \
-XX:InitialRAMPercentage=50.0 \
-XX:+UseContainerSupport \
-Xlog:gc*:file=/var/log/app/gc.log:time:filecount=3,filesize=10m"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]
GC 알고리즘 비교: G1GC vs ZGC vs Shenandoah (EKS 환경)
| 항목 | G1GC | ZGC | Shenandoah |
|---|---|---|---|
| Pause Time | 수십~수백ms | < 1ms | < 10ms |
| 메모리 오버헤드 | 낮음 | 중간 (10~20%) | 중간 |
| CPU 오버헤드 | 낮음 | 중간 | 중간 |
| 컨테이너 지원 | 완전 지원 | 완전 지원 | 완전 지원 |
| 활성화 옵션 | -XX:+UseG1GC |
-XX:+UseZGC |
-XX:+UseShenandoahGC |
| EKS 권장 상황 | 범용 REST API | 금융 트랜잭션, 초저지연 API | 대용량 캐시, 메모리 집약적 |
ZGC 활성화 예시 (초저지연 요구 시):
# Kubernetes Deployment
env:
- name: JAVA_OPTS
value: >-
-XX:+UseZGC
-Xms1g -Xmx2g
-XX:ZCollectionInterval=120
-XX:+ZUncommit
-Xlog:gc*:file=/var/log/gc.log:time:filecount=3
HPA(Horizontal Pod Autoscaler)와 GC 튜닝 통합
# hpa.yaml — CPU 기반 HPA + 커스텀 메트릭 (GC pause time)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: spring-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: spring-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
HPA와 GC 연계 고려사항:
- 힙 사용률이 높아 GC가 빈번할 경우 → CPU 사용률 증가 → HPA Scale-out
- Scale-out 시 새 Pod는 콜드스타트 JIT 컴파일 부하 발생
minReplicas를 적절히 설정하여 과도한 Scale-in/out 방지
모니터링: CloudWatch + Prometheus
CloudWatch Container Insights 활용
# EKS Add-on으로 CloudWatch Agent 설치
aws eks create-addon \
--cluster-name my-cluster \
--addon-name amazon-cloudwatch-observability
Prometheus + Grafana (Spring Boot Actuator 연동)
# application.yml — Actuator + Micrometer Prometheus
management:
endpoints:
web:
exposure:
include: prometheus,health,metrics
metrics:
export:
prometheus:
enabled: true
tags:
application: ${spring.application.name}
environment: production
GC 관련 주요 Prometheus 메트릭:
| 메트릭 | PromQL 예시 | 설명 |
|---|---|---|
| GC 일시정지 시간 | jvm_gc_pause_seconds_max{application="app"} |
최대 GC Pause 시간 |
| GC 실행 횟수 | rate(jvm_gc_pause_seconds_count[5m]) |
분당 GC 실행 빈도 |
| 힙 사용률 | jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} |
힙 사용률 |
| OOM 위험도 | jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.85 |
85% 초과 시 Alert |
댓글남기기