모니터링

Spring Actuator health check 주의사항

Junuuu 2023. 8. 14. 00:01
728x90

개요

Spring Actuator의 health check를 유의 깊게 살펴보지 않으면 발생할 수 있는 장애를 재현해 보며 이를 분석하고 해결하는 과정을 공유하고자 합니다.

 

Spring Actuator란?

Spring Boot 애플리케이션의 운영 정보와 모니터링을 제공하는 라이브러리입니다.

Actuator를 사용하면 애플리케이션의 상태 정보를 쉽게 확인할 수 있으며, 실행 중인 애플리케이션의 로그, 메모리 사용량, HTTP 요청 수 등의 정보를 수집할 수 있습니다.

 

Actuator의 애플리케이션의 상태 정보를 쉽게 확인할 수 있는 기능중 하나로 health check를 제공합니다.

 

Health Check란?

health check란 서버의 상태를 주기적으로 확인하여 서버가 살아있는지(정상 동작) 판단하는 과정을 말합니다.

 

우리는 서비스의 고가용성, 고성능을 위한 부하 분산 등의 이유로 우리는 서버를 이중화하고, 앞에서 어떤 서버로 요청을 보낼지 라우팅 역할을 하는 로드밸런서를 둡니다.

 

하지만 서버 한대가 서비스가 불가능한 상태라면?

해당 서버에 요청이 가면 안됩니다, 오히려 장애를 유발하게 됩니다.

https://toss.tech/article/how-to-work-health-check-in-spring-boot-actuator

 

따라서 로드밸런서에서는 각 서버의 헬스체크를 통해 서버가 현재 서비스 가능한 상태인지 주기적으로 점검합니다.

비슷하게 쿠버네티스(k8s)에서도 파드가 정상적인지 판단하기 위해 헬스체크를 수행하고, 이상 종료된 경우 파드의 설정된 경우 정책에 따라 파드를 재시작할 수 있습니다.

 

 

Spring Boot Actuator로 Health Check 해보기

테스트 환경

  • localhost:8080
  • Spring Boot 3.1.0
  • Java 17

 

gradle 의존성을 추가

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

 

 

헬스체크확인

http://localhost:8080/actuator/health

//결과
{"status":"UP"}

 

Spring Boot Actuator는 어떤 기준으로 헬스 체크를 수행할까?

application.yml 수정

management:
  endpoint:
    health:
      show-details: always

기본적으로 해당 설정(show-details)은 never이기 때문에 노출되지 않습니다.

이 속성을 always로 두어 디테일만 정보를 볼 수 있습니다.

이때 보안에 민감한 요소가 들어있을 수 있기 때문에 퍼블릭하게 접근을 가능하게 하는 것은 위험할 수 있습니다.

 

결과

{
  "status": "UP",
  "components": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 994662584320,
        "free": 746242093056,
        "threshold": 10485760,
        "path": "/Users/junuu/Downloads/study/.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

지금은 h2, postgresql등 db의 어떤 의존성도 존재하지 않기 때문에 정보에 db정보는 없습니다.

이때 components 하위의 항목이 하나라도 DOWN 상태라면 애플리케이션의 상태도 DOWN이 됩니다.

 

예를 들어 Redis를 캐시용도로 사용했는데 Redis 인프라가 잠시 이상이 생겨 DOWN 된다면 장애가 전파되면서 애플리케이션이 DOWN 됩니다.

 

즉, 장애대비를 위해 두었던 redis로 인해 장애가 발생하게 됩니다.

 

 

H2 의존성 추가하여 테스트해 보기

gradle 의존성 추가

runtimeOnly("com.h2database:h2")
implementation ("org.springframework.boot:spring-boot-starter-data-jpa")

h2 db와 jpa를 추가해 줍니다.

 

application.yml

management:
  endpoint:
    health:
      show-details: always


# Database Settings
spring:
  datasource:
    url: jdbc:h2:mem:testdb;MODE=mysql;
    username: sa
    password:
    driverClassName: org.h2.Driver

  h2:
    console:
      enabled: true
      path: /h2-console

 

 

 

http://localhost:8080/h2-console

h2-console login

password를 설정하였다면 password까지 입력해 주세요

 

http://localhost:8080/actuator/health

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "H2",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 994662584320,
        "free": 747068006400,
        "threshold": 10485760,
        "path": "/Users/junuu/Downloads/study/.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

이제 components의 하위로 db가 생긴 모습을 볼 수 있습니다.

 

이때 h2를 사용할 수 없다면?

h2로는 shutdown 테스트가 잘 동작하지 않아..

postgresql으로 넘어갑니다.

 

Docker-Compose로 PostgreSQL 준비

h2 -> postgresql

runtimeOnly("org.postgresql:postgresql:42.3.5")

 

docker-compose

version: '3.9'

services:
  postgres:
    image: postgres:latest
    container_name: my_postgres_db
    restart: always
    environment:
      POSTGRES_USER: your_postgres_username
      POSTGRES_PASSWORD: your_postgres_password
      POSTGRES_DB: your_database_name
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

volumes:
  postgres_data:

 

application.yml

management:
  endpoint:
    health:
      show-details: always

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/your_database_name
    username: your_postgres_username
    password: your_postgres_password
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect

 

application 구동후 health check 시도

{
  "status": "UP",
  "components": {
    "db": {
      "status": "UP",
      "details": {
        "database": "PostgreSQL",
        "validationQuery": "isValid()"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 994662584320,
        "free": 747939028992,
        "threshold": 10485760,
        "path": "/Users/junuu/Downloads/study/.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

h2 대신에 postgreSQL으로 바뀌었습니다.

 

postgreSQL docker-compose down시

{
  "status": "DOWN",
  "components": {
    "db": {
      "status": "DOWN",
      "details": {
        "error": "org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection"
      }
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 994662584320,
        "free": 747938422784,
        "threshold": 10485760,
        "path": "/Users/junuu/Downloads/study/.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

db status가 down 되자 전체 stats가 down 되었습니다.

어떻게 해결해야 할까요?

 

db health check를 하지 않도록 옵션 주기

management:
  health:
    db:
      enabled: false
    redis:
      enabled: false

application.yml에서 db.enabled는 false로 줍니다.

이외에도 redis, es 등 다른 의존성들을 false로 줄수도 있습니다.

 

health check 시도 시

{
  "status": "UP",
  "components": {
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 994662584320,
        "free": 747943141376,
        "threshold": 10485760,
        "path": "/Users/junuu/Downloads/study/.",
        "exists": true
      }
    },
    "ping": {
      "status": "UP"
    }
  }
}

더 이상 db를 체크하지 않습니다.

docker-compose down으로 postgreSQL을 멈추어도 health check는 정상적으로 200OK를 보냅니다.

 

 

마무리

사소한 헬스체크가 장애로 이루어질 수 있으니 주의 깊게 잘 사용해야 합니다!

평소에 이런 고민을 미리 해보았다면 장애 상황을 미연에 방지할 수 있습니다.

 

 

참고자료

https://docs.spring.io/spring-boot/docs/current/actuator-api/htmlsingle/

https://toss.tech/article/how-to-work-health-check-in-spring-boot-actuator

http://forward.nhnent.com/hands-on-labs/java.spring-boot-actuator/06-health.html#id1