본문 바로가기
프로그래밍/Spring

[Spring Boot] Spring Boot Actuator, Application을 모니터링 하자

by 사바라다 2019. 9. 14.

안녕하세요! 연휴 잘보내고 계신가요? 저도 오랜만에 고향에 내려와서 연휴를 즐기고 있습니다.

시스템을 운영하다보면 시스템이 사용하고 있는 Thread, memory, Session 등의 요소에 대해서 모니터링은 필수적인 요소 입니다. 운영되는 시스템은 아무리 잘 만들어 졌다고 할지라도 버그가 있을 수 있습니다. 우리는 이런 상황을 대비하기 위해서 모니터링은 필요한 요소입니다. Spring Boot에서는 Spring Boot Actuator라는 자체모니터링 툴을 제공합니다. 오늘은 해당 모듈에 대해서 알아보도록 하겠습니다.

Spring Actuator

Spring Boot 공식 Reference에 나와있는 Actuator에대한 간략한 설명입니다.

Spring Boot includes a number of additional features to help you monitor and manage your application when you push it to production. You can choose to manage and monitor your application by using HTTP endpoints or with JMX. Auditing, health, and metrics gathering can also be automatically applied to your application.

어플리케이션을 모니터링하고 관리하는 기능을 Spring Boot에서 자체적으로 제공해주는데 그게 Actuator라고 합니다. 그리고 Actuator는 http와 JMX를 통해 확인할 수 있다고 합니다.

이제 한번 Actuator를 사용해보면서 알아보도록 하겠습니다.


의존성(Dependency)

Spring에서 사용하려면 가장먼저 디펜던시를 잡아주어야합니다. 아래와 같이 maven, gradle에 따라서 잡아주도록 합시다. 버전은 사용하고 계시는 Spring Boot의 버전을 따릅니다.

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
dependencies {
    compile("org.springframework.boot:spring-boot-starter-actuator")
}

엔드 포인트 종류 (EndPoints List)

actuator에서 제공하는 모니터링은 상당히 많습니다. 그중에서도 제가 보면서 유용하게 쓰일것 모니터링 요소만 간단하게 알아보도록 하겠습니다. 전체 리스트를 알고 싶으신 분들은 참조의 Link를 확인해보시면 될것 같습니다.

ID Description
beans  application의 전체 Spring beans를 출력
caches  사용가능한 cache를 노출
conditions  configuration 또는 auto-configuration 되는 class들의 성공 여부와 이유를 설명
env  Spring Boot의 현재 환경설정 정보(application.yml의 정보 등)를 출력
health  application의 현재 상태를 보여줍니다.
httptrace  http를 trace한 정보를 노출(기본적으로 최신 100건의 reqest-response를 보여줍니다.)
mappings  Request와 mapping되어있는 handler 정보를 가져옵니다.
sessions  Spring Session이 가지고 있는 정보를 가져옵니다.
threaddump  threaddump를 가져옴
logfile  log를 가져옵니다.
metrics  metrics 정보를 노출합니다.

우리는 http endpoint를 통해서 위의 정보들을 가져올 수 있습니다.

configuration

actuator에서 제공하는 List는 민감한 정보들이 포함되어있습니다. 이는 보안상 위험요소가 될 수 있습니다. 그렇기 때문에 전 기능을 사용하기 위해서는 설정정보들을 잡아주어야 합니다.

기본세팅만 진행 한 후 endpoint로 /actuator로 확인해보면 아래와 같은 정보가 출력됩니다.

{
    "_links":
    {
        "self":{"href":"http://localhost:8080/actuator","templated":false},
        "health":{"href":"http://localhost:8080/actuator/health","templated":false},
        "health-component":{"href":"http://localhost:8080/actuator/health/{component}","templated":true},
        "health-component-instance":{"href":"http://localhost:8080/actuator/health/{component}/{instance}","templated":true},
        "info":{"href":"http://localhost:8080/actuator/info","templated":false}
    }
}

위에 출력된 리스트는 사용할 수 있는 모니터링리스트입니다. HATEOS를 만족하고 있는것을 알 수 있습니다. 우리는 사용하고 싶은 endpoint를 사용해볼수 있습니다.

health를 사용해 보겠습니다. 사용하기 위해서 health의 link(http://localhost:8080/actuator/health)를 사용해보도록 하겠습니다.

{"status":"UP"}

위와 같이 출력되는 것을 확인할 수 있었습니다. health는 application의 상태를 나타낸다고 했었으며 UP이라고 출력된것을 보아 Application이 실행중이라는 것을 알 수 있습니다.

좀 더 많은 부분을 모니터링 하기 위해서 설정을 변경해보도록 하겠습니다.

management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans

또는

management:
  endpoints:
    web:
      exposure:
        include: "*"

spring boot에서는 properties, yml설정으로 이를 제어할 수 있습니다. 위쪽은 properties이며 아래는 yml 설정입니다. include는 endpoint를 포함한다는 의미이며 exclude는 배제하겠다는 설정입니다. 값을 *로 표시하면 모든 endpoints를 사용하겠다라는 의미입니다. 그게 아니라 특정한 endpoint만 사용하고 싶다면 env, beans처럼 쓰고 싶은 endpoint를 직접 명시할 수 있습니다. 우리는 예제로 모든 endpoint를 사용할 수 있도록 하여 따라가 보도록 하겠습니다. 아래처럼 서정 후 다시 사용할 수 있는 actuator를 확인해보겠습니다.

{
   "_links":{
      "self":{
         "href":"http://localhost:8080/actuator",
         "templated":false
      },
      "auditevents":{
         "href":"http://localhost:8080/actuator/auditevents",
         "templated":false
      },
      "beans":{
         "href":"http://localhost:8080/actuator/beans",
         "templated":false
      },
      "caches":{
         "href":"http://localhost:8080/actuator/caches",
         "templated":false
      },
      "caches-cache":{
         "href":"http://localhost:8080/actuator/caches/{cache}",
         "templated":true
      },
      "health":{
         "href":"http://localhost:8080/actuator/health",
         "templated":false
      },
      "health-component":{
         "href":"http://localhost:8080/actuator/health/{component}",
         "templated":true
      },
      "health-component-instance":{
         "href":"http://localhost:8080/actuator/health/{component}/{instance}",
         "templated":true
      },
      "conditions":{
         "href":"http://localhost:8080/actuator/conditions",
         "templated":false
      },
      "configprops":{
         "href":"http://localhost:8080/actuator/configprops",
         "templated":false
      },
      "env":{
         "href":"http://localhost:8080/actuator/env",
         "templated":false
      },
      "env-toMatch":{
         "href":"http://localhost:8080/actuator/env/{toMatch}",
         "templated":true
      },
      "info":{
         "href":"http://localhost:8080/actuator/info",
         "templated":false
      },
      "logfile":{
         "href":"http://localhost:8080/actuator/logfile",
         "templated":false
      },
      "loggers":{
         "href":"http://localhost:8080/actuator/loggers",
         "templated":false
      },
      "loggers-name":{
         "href":"http://localhost:8080/actuator/loggers/{name}",
         "templated":true
      },
      "heapdump":{
         "href":"http://localhost:8080/actuator/heapdump",
         "templated":false
      },
      "threaddump":{
         "href":"http://localhost:8080/actuator/threaddump",
         "templated":false
      },
      "metrics":{
         "href":"http://localhost:8080/actuator/metrics",
         "templated":false
      },
      "metrics-requiredMetricName":{
         "href":"http://localhost:8080/actuator/metrics/{requiredMetricName}",
         "templated":true
      },
      "scheduledtasks":{
         "href":"http://localhost:8080/actuator/scheduledtasks",
         "templated":false
      },
      "httptrace":{
         "href":"http://localhost:8080/actuator/httptrace",
         "templated":false
      },
      "mappings":{
         "href":"http://localhost:8080/actuator/mappings",
         "templated":false
      }
   }
}

사용할 수 있는 모니터링 수가 많이 늘었습니다. httptrace를 한번 보도록하겠습니다.

위에서 알려준 link중 하나인 http://localhost:8080/actuator/httptrace를 호출해 봅니다.

{
   "traces":[
      {
         "timestamp":"2019-09-14T07:32:03.133Z",
         "principal":null,
         "session":null,
         "request":{
            "method":"GET",
            "uri":"http://localhost:8080/js/materialize.js",
            "headers":{
               "sec-fetch-mode":[
                  "no-cors"
               ],
               "referer":[
                  "http://localhost:8080/orders"
               ],
               "sec-fetch-site":[
                  "same-origin"
               ],
               "cookie":[
                  "Idea-ad55a9a9=85d2188c-9594-425d-9239-8018c4f9caca; JSESSIONID=CA649990E4EE39A70E1DF50B1D070D20"
               ],
               "accept-language":[
                  "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7"
               ],
               "host":[
                  "localhost:8080"
               ],
               "connection":[
                  "keep-alive"
               ],
               "accept-encoding":[
                  "gzip, deflate, br"
               ],
               "accept":[
                  "*/*"
               ],
               "user-agent":[
                  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
               ]
            },
            "remoteAddress":null
         },
         "response":{
            "status":200,
            "headers":{
               "Accept-Ranges":[
                  "bytes"
               ],
               "Cache-Control":[
                  "no-store"
               ],
               "Last-Modified":[
                  "Sat, 14 Sep 2019 07:23:25 GMT"
               ],
               "Content-Length":[
                  "370999"
               ],
               "Date":[
                  "Sat, 14 Sep 2019 07:32:02 GMT"
               ],
               "Content-Type":[
                  "application/javascript"
               ]
            }
         }
         ...
     

위의 trace는 view를 호출했을 때 나온 trace정보입니다. 보면 request와 response에 관한 정보가 담겨있는것을 확인할 수 있었습니다.

한계점

그렇다면 actuator의 한계점은 무엇일까요?

actuator는 상당히 민감한 정보를 많이 볼수 있습니다. 그렇기 때문에 개발이 아닌 운영시에는 보안에 철저하게 신경써야합니다. Role을 설정하여 특정 사용자만 접근하도록 하는 식으로 말입니다.

그리고 정보가 메모리에 저장됩니다. 실제 운영에서 잘 사용하기 위해서는 영구저장소에 저장될 필요가 있습니다. 때문에 우리는 영구히 정보를 저장하기 위해서 DB나 file 등에 저장할 필요가 있습니다.

마무리

이번에는 Spring Boot Actuator의 기본에 대해서 알아보았습니다. Actuator는 기본적으로 어플리케이션의 상태를 보여주고 변경할 수 있도록 추상화하여 정의하고 있습니다. 개발자로 하여금 프로젝트내에서 어플리케이션을 관리 통합할 수 있도록 도와줍니다. 클라우드 환경에서 어플리케이션들의 관리를 더욱 쉽게 만들어 줄것이라 생각되어집니다.

오늘 글을 작성하며 metrics endpoints에 대해서 유심히 보았습니다. metrics는 좀 더 코어적인 부분을 기술해줍니다. JVM정보, CPU정보, file정보 등 말이지요. 이부분은 다음에 다른 별도의 post로 찾아뵙도록 하겠습니다.

그럼 오늘은 여기까지 작성하도록 하겠습니다.

감사합니다.

참고

https://docs.spring.io/spring-boot/docs/2.1.8.RELEASE/reference/html/production-ready-endpoints.html

https://supawer0728.github.io/2018/05/12/spring-actuator/

댓글