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

2026. 8. 4. 12:54·Project/척척학사

이 글은 Velog에서 이전한 글입니다. Velog 원문 보기

1. 문제 상황 (Issue Description)

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

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

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

날짜 (UTC) 작업 유형 인스턴스 ID 비고
2026-02-05 10:21 Launch i-0f75... 생성
2026-02-07 11:55 Terminate i-0f75... 약 2일 후 종료
2026-02-07 11:55 Launch i-0a97... 재생성
2026-02-09 06:20 Terminate i-0a97... 약 2일 후 종료
2026-02-09 06:20 Launch i-0dc7... 재생성
2026-02-11 11:49 Terminate i-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로 인한 성능 저하 없이 안정적으로 운영 가능한 상태입니다.

'Project > 척척학사' 카테고리의 다른 글

[척척학사] 포털 연동 과정 16초를 0.8초로 94.8% 개선한 과정  (0) 2026.08.04
트래픽 피크형 서비스의 운영 구조를 요청 기반 구조로 바꾼 과정  (0) 2026.08.04
DB 커넥션 23초 점유 해결: 비동기 상태 머신으로 가용성 100% 확보하기  (0) 2026.08.04
[척척학사 | DevOps] Terraform으로 AWS 계정 간 인프라를 재현 가능하게 만들기  (0) 2026.08.04
[척척학사 | 부하 테스트 (3)] 7 TPS에서 96 TPS까지 — 병목을 제거하며 t3.micro의 한계를 밀어본 기록  (0) 2026.08.04
'Project/척척학사' 카테고리의 다른 글
  • [척척학사] 포털 연동 과정 16초를 0.8초로 94.8% 개선한 과정
  • 트래픽 피크형 서비스의 운영 구조를 요청 기반 구조로 바꾼 과정
  • DB 커넥션 23초 점유 해결: 비동기 상태 머신으로 가용성 100% 확보하기
  • [척척학사 | DevOps] Terraform으로 AWS 계정 간 인프라를 재현 가능하게 만들기
pp8817
pp8817
공부한 내용, 개발 관련 지식, 트러블 슈팅 등을 기록합니다. 이전 블로그: https://velog.io/@pp8817/posts
  • pp8817
    끄적이는 개발 log
    pp8817
  • 전체
    오늘
    어제
    • 분류 전체보기 (273)
      • Project (71)
        • 척척학사 (29)
        • Book (23)
        • Saynow (3)
        • YAPP 27기 (4)
        • 나의 작은 프로젝트 (10)
        • Landit (2)
      • Backend (88)
        • Spring (13)
        • Spring MVC (13)
        • Spring Security (4)
        • JPA (26)
        • Database (19)
        • HTTP·Web (13)
        • Architecture (0)
      • Language·CS (59)
        • Java·Kotlin (5)
        • CS Interview (17)
        • Backend Interview (5)
        • Concepts (32)
      • Algorithm (25)
        • Algorithm (24)
        • 소마 알고리즘 스터디 (1)
      • Infra (8)
      • Troubleshooting (11)
      • Retrospective (6)
      • Etc (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Python
    BOJ
    게시판
    CS Interview
    개념 정리!
    HTTP WEB 기본 지식
    Spring MVC
    object
    Spring
    jpa
    나의 작은 프로젝트
    OS
    Project
    척척학사
    Algorithm
    Book
    interview
    트러블슈팅
    http
    java
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
pp8817
AWS EC2 주기적 사망 원인 분석 및 JVM 메모리 최적화 (t3.micro → t3.small)
상단으로

티스토리툴바