AWS EC2 주기적 사망 원인 분석 및 JVM 메모리 최적화 (t3.micro → t3.small)

박상민·2026년 2월 11일

척척학사

목록 보기
24/28

1. 문제 상황 (Issue Description)

개발 서버 환경에서 실행 중인 EC2 인스턴스가 약 48시간(2일) 간격으로 주기적으로 비정상 종료되고, Auto Scaling Group(ASG)에 의해 재생성되는 현상이 발생했습니다.

1-1. 발생 패턴 및 로그 (Logs & Patterns)

ASG 활동 이력(Activity History)을 분석한 결과, 인스턴스 실행 후 약 2일이 경과하면 종료되는 패턴이 일정하게 반복됨을 확인했습니다.

날짜 (UTC)작업 유형인스턴스 ID비고
2026-02-05 10:21Launchi-0f75...생성
2026-02-07 11:55Terminatei-0f75...약 2일 후 종료
2026-02-07 11:55Launchi-0a97...재생성
2026-02-09 06:20Terminatei-0a97...약 2일 후 종료
2026-02-09 06:20Launchi-0dc7...재생성
2026-02-11 11:49Terminatei-0dc7...약 2일 후 종료

1-2. 원인 추론 과정 (Root Cause Analysis)

단순한 설정 오류가 아닌, 리소스 누적에 의한 장애로 판단하여 다음과 같은 흐름으로 원인을 좁혔습니다.

  1. Health Check 설정 검증: 로드 밸런서(ELB)의 Health Check 경로는 정상이며, 배포 직후에는 응답이 올바르게 반환됨을 확인했습니다.
  2. 장애 위치 특정: 설정 문제가 아니므로, 시간이 지남에 따라 EC2 인스턴스 내부에서 문제가 발생한 것으로 판단했습니다.
  3. 지연된 장애(Delayed Failure): 배포 직후가 아니라 2일 뒤에 Health Check가 실패한다는 것은, 시간이 지날수록 시스템 상태가 악화되어 응답 불능(Unresponsive) 상태에 빠짐을 시사합니다.
  4. 가설 수립: 애플리케이션 실행 중 리소스가 서서히 고갈되는 패턴이므로, 메모리 누수(Memory Leak) 또는 메모리 부족(OOM)을 가장 유력한 원인으로 특정했습니다.

2. 원인 분석 1: 기존 환경(t3.micro) 진단

가설을 검증하기 위해 기존 t3.micro 환경의 메모리 상태를 정밀 분석했습니다.

2-1. EC2 전체 메모리 상태 (free -m)

              total        used        free      shared  buff/cache   available
Mem:           988          842          41          12         104          73
Swap:         1024          512         512
  • Available (73MB): 즉시 사용할 수 있는 메모리가 거의 고갈됨.
  • Swap Used (512MB): 물리 메모리 부족으로 스왑 영역을 과도하게 사용 중.
  • 해석: 이 상태에서는 작은 트래픽 스파이크에도 OOM Killer가 동작하거나, 심각한 성능 저하가 발생할 수 있습니다.

2-2. JVM 힙 사용률 확인 (jstat)

 S0     S1     E      O      M     YGC   FGC
 0.00   0.00  85.12  92.45  88.31  120    8
  • Old Gen (92%): 장기 객체가 포화 상태.
  • Full GC 발생: 메모리 회수를 위해 Full GC가 반복적으로 발생하며 Stop-The-World 시간이 길어짐.

2-3. 결론: EC2 종료 매커니즘 규명

  1. 메모리 부족 발생 및 스왑 사용
  2. GC 빈도 증가 및 CPU 사용률 급증
  3. 애플리케이션 응답 지연 (Stop-The-World)
  4. ELB Health Check 타임아웃 발생
  5. Auto Scaling Group이 인스턴스를 'Unhealthy'로 판정하고 종료

3. 해결 과정 1: 인프라 스케일업 (t3.micro → t3.small)

물리적 메모리 한계를 극복하기 위해 인스턴스 유형을 t3.small(2GB RAM)로 변경했습니다.

3-1. 변경 후 메모리 상태 (Default 설정)

              total        used        free      shared  buff/cache   available
Mem:           1910         790         469           2         815        1120
Swap:          1023           0        1023
  • Available (1120MB): 메모리 여유가 충분해짐.
  • Swap (0): 스왑 의존성이 사라짐.

3-2. 새로운 문제점 발견 (리소스 낭비)

물리 메모리는 늘어났으나, JVM 옵션을 따로 설정하지 않아(Default) Java는 여전히 보수적인 메모리 정책을 유지하고 있었습니다.

  • Max Heap: 약 512MB (물리 램의 1/4 자동 설정)
  • 문제: 나머지 1GB 이상의 메모리가 유휴 상태로 방치되며, 힙 공간 부족으로 인한 잦은 GC 위험은 여전히 존재함.

4. 해결 과정 2: JVM 메모리 최적화 (Tuning)

인스턴스 스펙업의 효과를 극대화하기 위해, 물리 메모리의 50%를 힙 메모리로 고정 할당하는 최적화 설정을 적용했습니다.

4-1. 실행 명령어 변경

[변경 전 (Default)]

nohup java -jar app.jar ...

[변경 후 (Optimized)]

nohup java -Xms1024m -Xmx1024m -XX:+UseG1GC -XX:MaxMetaspaceSize=256m -jar ...

4-2. 최적화 의도

  1. 메모리 활용 극대화: -Xms1024m -Xmx1024m으로 1GB를 확보하여 비용을 지불한 자원을 100% 활용.
  2. GC 빈도 감소: 힙 공간(Eden)이 넓어져 Minor GC 주기가 길어지고 CPU 효율 증가.
  3. 운영 안정성: 초기 힙 확보(-Xms)로 트래픽 급증 시에도 할당 지연 방지.

5. 최종 검증 (Verification)

최적화 설정 배포 후 시스템 상태를 최종 점검했습니다.

5-1. JVM 힙 메모리 할당 확인 (jstat)

jstat -gc <PID> 1000 5

결과:

 S0C      S1C      S0U      S1U       EC       EU       OC       OU
 0.0  29696.0      0.0  29696.0  280576.0 246784.0 738304.0  14839.0
  • Total Heap Capacity:1,048,576 KB (1GB) (정상 확장됨)
  • Old Generation Usage: 14MB / 738MB (사용률 약 2%)
  • 분석: 기존 대비 힙 용량이 8배 이상 증가했으며, 메모리가 매우 여유로워 Full GC 발생 가능성이 희박함.

5-2. 물리 메모리 점유율 확인 (top & free)

top 결과:

PID   USER     RES    SHR S  %CPU  %MEM
3427  ubuntu  667680 25980 S   0.0  34.1
  • RES (667MB): JVM이 1GB를 예약했으나, OS의 Lazy Allocation 특성으로 인해 실제 사용량은 효율적으로 관리되고 있음.

free -m 결과:

              total        used        free      shared  buff/cache   available
Mem:           1910        1069         158           2         846        840
  • Available (840MB): JVM에 1GB를 할당하고도 OS 운영을 위한 충분한 여유 공간 확보.

6. 최종 결론

  1. 인프라 확장 (Scale-up) 성공: t3.micro의 메모리 고갈 및 스왑 문제를 t3.small 도입으로 해결했습니다.
  2. JVM 튜닝을 통한 효율 극대화: 하드웨어 확장에만 그치지 않고, Xms/Xmx 튜닝을 통해 늘어난 자원을 애플리케이션이 온전히 사용하도록 설정했습니다.
  3. 안정성 확보: 현재 시스템은 메모리 부족으로 인한 셧다운이나, 잦은 GC로 인한 성능 저하 없이 안정적으로 운영 가능한 상태입니다.

0개의 댓글