🍃 Language/Java

Spring Boot Actuator로 메모리 이슈 모니터링하기

카프리썬_ 2024. 4. 14. 21:40
728x90
728x90

 

운영 중인 서비스에서 종종 OOM이슈가 발생했다. 원인을 명확하게 알수 없어서 고민하던중 spring 어플리케이션을 모니터링해주는 spring actuator를 알게 되어서 이렇게 글을 작성한다. 그래서 우리 서비스를 가지고 메모리 관련 매트릭 정보를 확인해보았다.

 

목차

     

    Spring Actuator란?

    spring boot로 실행중인 애플리케이션의 내부 상태를 모니터링 해주는 모듈(?).

    메모리, 캐시 등 여러 metrics을 http Endpoint로 제공해준다.

    endpoints

    액추에이터가 프로젝트 빌드의 일부가 되면 여러가지 엔드포인트를 사용할수 있다.

     

    예를 들어 간단하게 직접 확인 해본 엔드포인트들은 아래와 같다. 

    - /health : 애플리케이션의 현재 상태 정보 표시

    - /beans : 컨텐츠의 모든 빈 표시 

    - /httptrace : 가장 최근의 100개 요청에 대한 추적기록 

    - /info : 애플리케이션 자체 정보

    - /loggers : 로거 설정 및 정보 

    - /metrics : 매트릭 정보 

     

    공식문서 https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints

    사용법

    아래 Dependency만 추가해주면 바로 사용할 수 있다.

    implementation("org.springframework.boot:spring-boot-starter-actuator")
    

     

    그래서 yaml 설정파일 노출시킬 특정 endpoint를 명시해주면 된다.

    endpoints:
      web:
        exposure:
          include: info,health, metrics

     

    물론 * 를 통해 모든 엔드포인트를 노출하도록 할수도 있지만, 보안상 권장되지는 않는다.

    endpoints:
      web:
        exposure:
          include: "*"

     

    Actuator 제공 서비스  

    위의 의존성을 추가하고, 아래의 엔드포인트로 가면 actuator가 제공하는 서비스를 확인할수 있다.

    http://localhost:5000/actuator

    include: info,health, metrics endpoint만 명시했을 경우

     

    각각 endpoint에 대한 repsonse는 아래 블로그에서 정리를 잘해주셨다! 

    https://incheol-jung.gitbook.io/docs/study/srping-in-action-5th/chap-16.

     

    CHAP 16. 스프링 부트 액추에이터 사용하기 | Incheol's TECH BLOG

    스프링 인 액션(5판) 챕터 16장을 요약한 내용 입니다.

    incheol-jung.gitbook.io

     

    이 글에서는 기본적으로 health 정보와 메모리 관련 metrics에 대한 정보만 직접 확인한 결과로 공유해보려고 한다.

     

    health 정보 확인

    http://localhost:5000/actuator/health

    애플리케이션에 문제가 발생했을때 문제를 인지할 수 있다. 

    요청에 대한 응답 뿐만 아니라 데이터베이스가 응답하는지, 디스크 사용량에는 문제가 없는지 등 health check를 해준다고 보면 된다. 

     

    기본적으로 정상일 경우 위와 같은 응답을 받으며,

    DOWN, UNKNOWN, OUT_OF_SERVICE 같은 건강상태가 있을수 있다.

     

     

    상세내역을 보려면 yml 파일 속성 정보에서 아래와 같이 endpoint.health.show-details 부분을 추가하면 된다. 

    endpoint:
      health:
        show-details: always

     

    그러면 이렇게 외부 데이터베이스와 시스템을 비롯한 디테일한 상태체크를 할수 있다.

    대신 아래의 components 중에 하나라도 DOWN 이 된다면 전체 상태는 DOWN이 된다. 

     

    metrics 정보 확인

    http://localhost:5000/actuator/metrics

    실행중인 애플리케이션에서 생성되는 매트릭을 제공해준다.

    메모리, 프로세스, 가비지 컬렉션, HTTP 요청 관련 매트릭이 있다.

     

    http://localhost:5000/actuator/metrics/{metrics.name}

     

    이중에서 아래와 같이 몇가지 metrics를 확인해봤다.

     

    디스크 관련

    - /disk.free : 디스크 여유 공간 

    - /disk.total: 디스크 총 용량

     

    종종 OOM 이슈가 발생했기에 메모리 관련 이슈라고 짐작하면서 관련된 지표를 확인해봤다. 

     

    버퍼 메모리 관련

    - /jvm.buffer.memory.used : 사용중인 JVM 버퍼 메모리 용량

    - /jvm.buffer.total.capacity : JVM 버퍼의 총 용량

     

    사용중인 버퍼 메모리의 총 용량은 84,010,879 바이트 (84.010879MB)

    그중에서 사용하고 있는 메모리의 용량은  84,002,688 바이트 (84.002688 MB)

    결국 버퍼 메모리 사용률이 99.9902500723 % 라는 이야기인가..?!

     

    JVM 메모리 관련

    - /jvm.memory.commited : JVM이 할당한 메모리 중에 현재 확보된 메모리양 

    - /jvm.memory.used: JVM이 현재 사용중인 메모리 양

     

    현재 확보된 메모리 사용량은 587,005,952 바이트 (587MB)

    총 메모리 사용량은 힙메모리와 넌힙 메모리를 합쳐서 408,563,208 바이트 (408MB)

    그렇다면 JVM 메모리 사용률은 0.6950596252 % 라는 이야기인가..?!

     

    endpoint뒤에 tag를 통해 heap 메모리와 nonheap 메모리 사용량을 별도로 확인할수도 있다.

    http://localhost:5000/actuator/metrics/jvm.memory.used?tag=area:heap

    그래서 힙 메모리는 약 273,299,024 바이트 (273MB) 넌힙메모리는 약 192,960,016 바이트 (192MB) 이정도 확인했다. 

     

    - /jvm.memory.max : JVM이 최대로 사용할수 있는 메모리 양 

    - /jvm.memory.usage.after.gc : 가비지 컬렉션 후 JVM 메모리 사용률

     

    심지어 최대 메모리 사용량 또한 힙메모리와 넌힙 메모리를 합쳤을땐

    무려 9,714,008,061 바이트 (9.7GB) 까지 되는걸 확인했다.

     

    마찬가지로 tag로 힙메모리와 넌힙메모리를 따로 볼수 있었다.

    http://localhost:5000/actuator/metrics/jvm.memory.max?tag=area:heap

    이때 최대 힙메모리는 8589934590 바이트 (8.5 GB), 최대 넌힙메모리는 1124073471 (1.12GB) 정도였다. 

    그리고 가비지 컬렉션 후 JVM 메모리 사용률은 약 0.019% 로 적었다.

     

    가비지 컬렉션 관련

    - /jvm.gc.live.data.size : gc(Garbage Collection) 중에 살아있는 객체의 크기

    - /jvm.gc.memory.allocated : gc(Garbage Collection)로 할당된 메모리 양

    - /jvm.gc.overhead : gc 오버헤드

     

    GC로 살아있는 객체는 155,069,952 바이트 (155MB), 할당된 메모리 양은 12,582,912 바이트(12MB)

    생각보다 가비지 컬렉터로 인한 오버헤드는 적었다. 

     

    예상하는게 메모리 이슈라서 위와 같은 매트릭들을 살펴보았는데,

    이 외에도 시스템의 CPU사용률이라던지, 프로세스나 스레드 관련 매트릭들도 존재한다.

     

    참고 https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.metrics.endpoint

     

    Production-ready Features

    You can enable recording of HTTP exchanges by providing a bean of type HttpExchangeRepository in your application’s configuration. For convenience, Spring Boot offers InMemoryHttpExchangeRepository, which, by default, stores the last 100 request-response

    docs.spring.io

     

    결론

    spring actuator로 우리 spring 어플리케이션 지표를 모니터링하고 확인해본결과

    버퍼 메모리 사용량은 99%이고, JVM 메모리 사용량 또한 약 70%인 상태였다.

    확실하진 않지만 의심이 되는 부분은 로컬캐시하는 부분으로 예상이 된다.

     

    cache 정보 확인 

    다행히도 sprig actuator에서 cache 정보를 확인하는 endpoint 또한 존재했다.

    http://localhost:5000/actuator/caches

     

    http://localhost:5000/actuator/caches/{cache.name}

     

    다만 cacheManager를 통해 생성된 Ehcache라는 것 이외에 캐시의 메모리 사용량이나 사이즈는 알지 못했다ㅜㅜ

    그래서 요부분은 시간될때 조금더 찾아봐야겠다!

     

    728x90
    반응형