-
Spring Boot 애플리케이션이 Kubernetes에서 Pod 시작 시 CPU를 많이 사용하는 이유DevOps 2025. 3. 18. 14:14728x90
Spring Boot 애플리케이션이 Kubernetes에서 Pod 시작 시 CPU 사용량이 급증하는 주된 이유는 JVM(Java Virtual Machine)의 초기화 과정과 Spring Boot 자체의 초기 부팅 과정 때문입니다.
이를 자세히 분석하면 다음과 같은 주요 원인이 있습니다.
1️⃣ JVM 초기화 및 JIT(Just-In-Time) 컴파일 최적화
✔ JVM은 애플리케이션 실행 전 여러 초기화 작업을 수행
✔ JIT(Just-In-Time) 컴파일러가 코드를 최적화하면서 CPU 사용량 증가✅ 설명:
- JVM은 애플리케이션 실행 시 클래스 로딩, 메서드 컴파일, JIT 최적화를 수행
- 특히 JIT 컴파일러는 처음 실행되는 코드의 성능을 최적화하기 위해 상당한 CPU를 사용
- JIT 컴파일이 완료된 후에는 CPU 사용량이 안정화됨
📌 해결 방법:
- AOT(Ahead-Of-Time) 컴파일 적용 (GraalVM 사용)
- JVM 옵션 튜닝 (-XX:+TieredCompilation, -XX:+AlwaysPreTouch 설정)
- G1GC 등 최적의 가비지 컬렉터 적용 (-XX:+UseG1GC)
✅ 예제 JVM 설정 (CPU 사용량 최적화)
bash복사편집JAVA_OPTS="-XX:+TieredCompilation -XX:+UseG1GC -XX:+AlwaysPreTouch"
2️⃣ Spring Boot 컨텍스트 초기화 및 Bean 로딩
✔ Spring Boot는 애플리케이션 시작 시 모든 Bean을 생성 및 DI(의존성 주입) 수행
✔ Bean 생성 및 초기화 작업이 많을수록 CPU 사용량 증가✅ 설명:
- Spring Boot는 모든 Bean을 한 번에 초기화(Eager Initialization)하기 때문에 CPU 부하가 높아짐
- 특히 Hibernate, JPA, Feign Client, Kafka Consumer 등의 초기화가 무겁게 작동
- 대규모 애플리케이션일수록 Bean 수가 많아지고, CPU 사용량도 증가
📌 해결 방법:
- Lazy Initialization 적용 (필요할 때만 Bean을 로드)
- Bean 초기화를 병렬로 수행 (spring.main.allow-bean-definition-overriding=true)
- 프로파일 기반으로 필요 없는 Bean은 실행하지 않도록 구성
✅ 예제 설정 (Lazy Initialization 활성화)
yaml복사편집spring: main: lazy-initialization: true
3️⃣ Classpath Scanning 및 Reflection 사용
✔ Spring Boot는 Component Scan을 사용하여 패키지 전체를 스캔
✔ 이 과정에서 Reflection을 많이 사용하므로 CPU 사용량 증가✅ 설명:
- @ComponentScan, @EntityScan이 넓은 범위를 포함하면 불필요한 클래스를 로딩
- Hibernate/JPA는 엔터티 클래스를 분석하는 과정에서 Reflection을 사용하여 CPU 부하를 증가
- Spring Boot DevTools가 활성화되어 있으면 애플리케이션 리로딩 비용이 추가 발생
📌 해결 방법:
- @ComponentScan, @EntityScan 범위를 최소화하여 불필요한 클래스 로딩 방지
- Hibernate의 hbm2ddl.auto 설정을 update 또는 validate로 설정하여 스키마 자동 생성 방지
- Spring Boot DevTools 비활성화 (spring.devtools.restart.enabled=false)
✅ 예제 설정 (Component Scan 최적화)
java복사편집@ComponentScan(basePackages = "com.example.service") // 전체 패키지 스캔 방지 @EntityScan(basePackages = "com.example.model") // 엔티티 클래스만 스캔
4️⃣ Kubernetes 환경에서 Liveness & Readiness Probe 초기 부하
✔ Pod가 시작될 때 Liveness 및 Readiness Probe가 빠르게 동작하면서 추가적인 부하 발생
✅ 설명:
- Liveness Probe가 너무 자주 실행되면, 초기 부팅 중 불필요한 리소스 소비
- Readiness Probe가 애플리케이션이 완전히 초기화되기 전에 트래픽을 받으면 성능 저하 발생
📌 해결 방법:
- Liveness Probe의 initialDelaySeconds를 늘려서 초기 부하 감소
- Readiness Probe를 활용하여 애플리케이션이 완전히 로딩된 후 트래픽 수신
✅ 예제 설정 (Liveness & Readiness Probe 최적화)
yaml복사편집livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 60 periodSeconds: 10
5️⃣ Kubernetes CPU Request & Limit 설정의 영향
✔ CPU Limit이 낮게 설정되면 JVM이 Throttling되어 부팅 속도가 느려짐
✔ Request 값이 너무 낮으면, 초기 부하를 감당하지 못하고 OOMKilled 발생 가능✅ 설명:
- JVM은 초기화 시 많은 CPU를 필요로 하지만, Kubernetes는 CPU Limit을 강제 적용
- CPU 요청이 낮으면 JVM이 충분한 리소스를 확보하지 못해 Start-up 시간이 길어짐
📌 해결 방법:
- Pod의 CPU Request 값을 높여서 초기 부팅 속도 최적화
- Limit을 너무 낮게 설정하지 않고 JVM 성능을 보장할 수 있도록 조정
✅ 예제 설정 (Kubernetes Resource 최적화)
yaml복사편집resources: requests: cpu: "500m" memory: "512Mi" limits: cpu: "1000m" memory: "1024Mi"
📌 6️⃣ 결론: Spring Boot 컨테이너가 Kubernetes에서 시작 시 CPU를 많이 사용하는 이유
Spring Boot 애플리케이션이 Pod 시작 시 CPU를 많이 사용하는 이유는 다음과 같습니다.
원인설명해결 방법JVM 초기화 및 JIT 컴파일 클래스 로딩, JIT 최적화 AOT 컴파일 적용, JVM 옵션 튜닝 Spring Boot Bean 초기화 모든 Bean을 한 번에 생성 Lazy Initialization 활성화 Classpath Scanning & Reflection 엔터티 및 빈 자동 스캔 @ComponentScan 범위 최소화 Liveness & Readiness Probe 영향 초기 Probe 실행이 부하 유발 Probe 설정 최적화 (초기 지연 적용) CPU Request & Limit 설정 문제 CPU 제한으로 인해 부팅 지연 Kubernetes Resource 최적화 ✅ 최적의 접근 방식:
"Spring Boot 컨테이너가 Kubernetes에서 실행될 때, JVM 초기화, Bean 로딩, Liveness Probe, CPU Limit 등의 요인이 초기 부하를 증가시키므로, AOT 컴파일 적용, Lazy Initialization 설정, Kubernetes 리소스 최적화를 통해 이를 해결할 수 있습니다." 🚀728x90'DevOps' 카테고리의 다른 글
RAID (Redundant Array of Independent/Inexpensive Disks) (0) 2025.03.22 GitHub의 Hubot이란 (0) 2025.03.21 Real User Monitoring(RUM) 개념 (0) 2025.03.15 RTO, RPO와 TTD, TTE, TTF의 관계 (0) 2025.03.15 RTO, RPO 개념 (0) 2025.03.15