새소식

Welcome to the tech blog of Junior Backend Developer Seulbin Kang!

Backend

(BE 개발자 3개월 차) 현업에서 겪은 EC2 장애로 시작한 모니터링 구축기 : Prometheus / Grafana 지표 선택의 기준

  • -

👀 들어가기 전에

때는 12월 초 오전 7시28분... 갑자기 업무 카톡이 오기 시작했다.

이유는 아래와 같다. 

멀쩡하게 잘 돌아가던 테스트 서버가 다운되었다는 내용이었다.

비상 비사아앙

 

메시지를 확인하자마자 머리가 빠르게 돌아가기 시작했다.

'내가 껐나? 끈 적이 없는데?', '그렇다는건 서버가 혼자 꺼졌다는건데?', '어?? 왜꺼지지 그게? 그럴 리가 없는데?'

출근 중이었고, 회사에 도착하자마자 후다닥 노트북을 열어 확인했다. 결과적으로는 EC2 인스턴스 자체가 다운된 상태였다.

우선, 급하게 처리해야할 업무였기에, EC2를 재부팅해 서버를 정상 상태로 복구한 뒤, 로그 및 시스템 지표를 확인했다.


👀 본론

EC2 재기동 이후 확인한 로그에서 원인은 비교적 명확했다.

CPU 사용률 99%, Memory 사용률 99% .....

 

MVP 단계의 테스트 서버였기에 EC2 스펙을 최소한으로 설정해두었는데 그 선택이 한계에 도달한 상태였다.

즉, 서버가 갑자기 꺼진 것이 아니라 지속적인 리소스 사용 증가로 인해 인스턴스가 한계에 도달한 상태였다.

(당시 이 시점에 mvp 테스트 이른바 기능 테스트가 몰려 있었고, 여러 기능 검증과 실험이 동시에 진행되던 시기였던 것이 한 몫을 했을 것이라 판단했다.)


단순 스펙 업그레이드의 한계

 

물론, 예상 사용량 대비 EC2 스펙이 너무 낮았기 때문에 인스턴스 타입 업그레이드는 우선적으로 진행했다.

하지만 그럼에도 불구하고 이 방법의 한계는 명확하다.

지금 당장은 문제 해결이 되지만, 다음 장애는 언제 발생할지, 왜 발생했는지 알 수가 없다.

다음에 똑같은 일이 발생하게 되면, 또 다시 ec2가 다운되기 전까지는 전조 증상조차 알 수 없다.

뿐만 아니라, 장애 발생 시마다 직접 서버에 접속해 원인을 추적해야 했다.

 

단순히 스펙 업그레이드를 하고 끝내는 것은 명확한 문제의 해결이 아니라 생각했다.


이 장애를 계기로 아래와 같은 질문을 던졌다.

  • CPU / 메모리 사용률은 언제부터 증가했는가?
  • 특정 시간대에만 급증하는 패턴이 있는가?
  • 어플리케이션 레벨에서 병목은 없는가?
  • 다음 장애를 사전에 감지할 수 있는 방법은 없는가?

이를 위해 모니터링 시스템이 필요하다고 판단하였고 구축하기 시작하였다.


운영 환경에서 (물론 우리는 테스트 환경이지만, 회사에서 사용하는 운영환경인 셈이니까..) 장애는 대부분 다음과 같은 흐름을 따르게 된다.

 

1. 자원 사용률이 서서히 증가

2. 특정 임계점을 넘어 성능 저하 발생

3. 최종적으로 장애 발생

 

중요한 것은 2단계에서 이를 인지해야만 3단계 장애를 피할 수 있는 것이다.

따라서 목표는 다음과 같다.

장애 발생 이후 대응이 아니라, 장애 발생 이전에 상태를 인지할 수 있는 시스템

 

이를 위해 Prometheus + Grafana 기반의 모니터링 환경을 구축했다.


왜 하필 Prometheus + Grafana 였는가?

 

선택의 이유는 다음과 같다.

  • 이전에 사용해본 경험이 있어 학습 비용이 낮았다.
  • 현재 서버 상태를 한눈에 파악할 수 있도록 커스터마이징이 가능했으며
  • 보고 싶고, 반드시 봐야만 하는 메트릭을 하나의 대시보드로 구성할 수 있었기 때문이다.

이번 모니터링 구축의 핵심 목표는 "서버가 다운되기 전에 감지하고 대응하자"였다.


 

이를 위해 다음 지표들을 우선적으로 모니터링 했다.

프로메테우스 상태 팔로우업

1) 인프라 레벨

"CPU 사용률, Memory 사용률, Load Average, Disk 사용률"

 

2) 어플리케이션 레벨

"JVM Heap / Non-Heap , 요청 수 (TPS), 응답 시간, 스레드 사용률"

 

이 지표들을 통해 서버 상태를 로그가 아닌 그래프로 한눈에 확인할 수 있는 환경을 구축했다.


메트릭 선택의 이유

내가 알고 싶었던 것은 인프라 레벨도 있으나 가장 중요한 것은

  • 무슨 요청이 늘었는가? (어떤 API에서 나오는 병목인지에 대한 확인을 위해)
  • 애플리케이션이 어떤 방식으로 자원을 더 쓰게 되었는가?
  • 지금 상황이 일시적인 스파이크인가 누적되는 문제인가?
  • 장애가 다시 일어날 가능성이 큰 곳인가
  • 어떤 부분이 문제가 있길래 장애가 발생했는가 (+ 이를 통한 수정이 가능해야 한다.)

이다.

 

그래서 인프라 지표와 별개로 어플리케이션 내부에서 나오는 신호가 필요했고 그 중에서도 운영적으로 꼭 필요한 지표가 아래 네가지라고 생각했다.

 

1. JVM Heap / Non-Heap

2. 요청 수 (TPS)

3. 응답 시간 (Latency)

4. 스레드 사용률


1) JVM Heap / Non - Heap

 

메모리 99%의 원인이 JVM인지에 대한 구분이 필요하다.

EC2 메모리 사용률이 높아도 원인은 여러 가지이다.

  • JVM 힙이 커져서 메모리를 잡아먹는 경우
  • 네이티브 메모리나 스레드 스택이 늘어난 경우
  • 캐시/버퍼/파일 시스템 캐시 등 OS레벨에서 증가한 경우

일 수도 있는 것이다.

즉 "메모리 사용률이 높다"만으로 대응할 수 있는 방법이 없다.


Heap은 자바 객체가 쌓이는 공간이고, Heap이 압박 받으면 GC가 돌아가는게 잦아진다.

GC가 잦아지면 운영 환경에서 다음과 같은 문제로 이어진다.

  • 응답 시간이 점점 늘어남 (Latency의 상승)
  • GC 중 Stop-The-World로 인한 요청 처리 지연
  • GC 작업으로 인한 CPU 사용률 급등
  • 최악의 경우 OOM 또는 프로세스 kill로 인한 서버 장애

그렇다면 Non-Heap은 왜 봐야하는가?

Non-Heap 영역은 JVM의 메타데이터 영역으로 클래스 정보, 메소드 영역, 코드 캐시 등을 포함한다.

 

즉, 

  • 힙을 늘려도 해결되지 않는 메모리 문제를 구분할 수 있다.
  • 특히 Metaspace 증가(클래스 로딩 증가 / 동적 프록시 / 리플렉션 과다 등) 같은 이슈는 힙만 튜닝한다고 해서 해결이 안된다.

그래서??

모니터링 환경 구축 이후 Heap / Non-Heap 의 경우 다음과 같은 부분을 염두에 두고 모니터링하였다.

  • Heap 사용량이 지속적으로 증가만하고 줄어들지 않는건 아닌지 (메모리 누수를 의심해봐야 하는 상황은 아닌지)
  • 주기적으로 급격하게 치솟았다가 떨어지는 스파이크 형태를 보이지는 않는지
    (대용량 객체 생성이 발생하는 요청인지, 주기적인 배치 작업은 아닌지, 캐시 재구성 로직은 아닌지 등 어떤 상황인지에 대한 판단)
  • Non-Heap 사용량이 지속적으로 증가하지는 않는지 (클래스, 즉 코드 자체에서 문제가 있는 상황은 아닌지)

2) 요청수

 

TPS는 서버가 초당 처리하는 요청의 양을 나타내는 지표이다.

자원이 갑자기 부족해졌을 때, 그 원인이 트래픽 증가 때문인지 아니면 코드나 구조적인 문제 때문인지를 가장 먼저 구분해주는 지표가 TPS다. TPS 관찰은 다음과 같은 부분을 위해 트래킹을 시작했다.

  • 특정 시간대에 요청이 몰리는 패턴 확인
  • 특정 API 호출이 급증하는 시점 파악
  • 부하테스트시 실제 트래픽 대비 여유 구간 산정

3) 응답 시간

 

CPU나 메모리 사용률이 안정적이더라도 응답시간이 느려지면 장애로 인식하게 된다.

GC로 인한 처리 지연, DB 쿼리 지연, 외부 API 응답 지연, 스레드 풀 또는 커넥션 풀 대기로 인해 주로 응답시간이 늦어진다.

평균 응답시간도 중요하지만, P95, P99는 사용자의 경험을 더 직접적으로 반영한다.

 

일부 요청에서만 발생하는 심각한 지연은 평균값에 묻히기 쉽기 때문에, P95, P99 지표를 통해 이런 상황을 감지하고자 하였다.


4) 스레드 사용률

 

CPU 사용률이 높지 않아도 응답 시간이 급격히 증가하는 경우가  있다.

요청은 계속 들어오지만, 처리할 스레드가 부족해 대기 상태가 늘어나고 그 결과 응답 시간이 증가하게 되는 경우이다.

스레드 사용률을 통해 구분하고자 하는 지표는 다음과 같았다.

  • 스레드 풀의 고갈인지
  • 특정 API에서 스레드 점유시간이 길어서 발생하는 문제인지
  • 외부 I/O 대기로 인한 스레드 블로킹인지 (ex. DB 문제)

구축 이후의 상태변화 

장애를 어느 정도 예측 가능해졌으며, 위에서 말한 것과 같이 장애가 발생하더라도 원인에 대한 분석이 한눈에 가능해졌다.

  • 리소스 사용 패턴 파악 가능
  • 특정 시간대의 CPU 피크 확인
  • 메모리 사용량 증가 추세에 대한 사전 인지
  • 스펙 업그레이드에 대한 명확한 근거 확보

👀 결론

이제는 매일 아침 출근해서, 퇴근 전에 서버 상태 모니터링 체크하는게 일종의 루틴 처럼 자리 잡았다.

서버 스펙을 키우는 것은 곧 비용 증가로 이어지기에 비용을 들이기 전에 모니터링을 하는 것이 맞다고 판단했다.

 

현재는 리소스 사용량이나 서버 상태를 사내 메신저로 주기적으로 알림 받을 수 있도록 자동화시키는 방향도 고민 중이다.

No bug,,,,Yes happy,,,,,😭

 

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.