최근에 새 프로젝트에 커넥션 풀 모니터링을 위해 hikariCP
의 isRegisterMBeans
를 true
로 설정 후 실행하다가 다음과 같은 에러를 맞닥뜨렸습니다.
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [HikariDataSource (FdsPostgreSQLHikariCP)] with key 'fdsDataSource'
Caused by: javax.management.InstanceAlreadyExistsException: MXBean already registered with name com.zaxxer.hikari:type=PoolConfig (FdsPostgreSQLHikariCP)
애플리케이션 컨텍스트(ApplicationContext)가 초기화되는 시점에 MBean
이 중복 등록되었다는 오류였습니다. 처음 보는 분들에게는 다소 생소할 수 있는 개념인데, 이 문제를 풀면서 정리한 내용을 공유해보려고 합니다.
즉, 운영 중인 애플리케이션의 상태를 외부에서 관측하거나 일부 속성을 조정하기 위해 등록하는 내부 빈입니다.
Spring Boot에서는 spring-boot-actuator를 통해 애플리케이션 상태를 HTTP(/actuator/**
)나 JMX(MBeans
)로 노출할 수 있습니다.
문제는, 외부 모니터링을 위해 HikariCP 설정 중 isRegisterMbeans를 true로 설정하는 경우에 자체적으로 MBean을 등록한다는 점입니다. isRegisterMbeans=true로 설정되어 있으면 Hikari가 com.zaxxer.hikari:type=PoolConfig,Pool 같은 이름으로 MBean을 등록합니다. 그런데 Spring도 같은 대상을 등록하려고 하면서 충돌이 발생하는 것이 위 에러의 이유였습니다.
-Dspring.jmx.enabled=true
로 JMX가 활성화되어 있었음isRegisterMbeans=true
로 되어 있었음MBeanExporter
도 동일한 ObjectName
으로 등록 시도 → InstanceAlreadyExistsException
발생해결책은 여러 가지가 있습니다.
Spring 쪽에서 충돌 무시하기
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
→ 이미 같은 이름의 MBean이 있으면 스프링이 새로 등록하지 않고 넘어감.
→ 제가 적용한 방식.
HikariCP의 MBean 등록 끄기
config.isRegisterMbeans = false
→ Hikari가 직접 등록하지 않고 Spring 쪽만 등록되도록 조정.
→ 이렇게 하면, 모니터링 시스템에서 풀 모니터링이 불가능했음. 아래에서 설명.
Spring JMX 자체 끄기
spring.jmx.enabled: false
→ Actuator의 JMX 노출을 아예 막고, Hikari 기본 MBean만 사용.
그런데 여기서 의문점이 생길 수 있습니다. 저도 그랬구요!
결국 registerMbeans=false
하더라도 MBean은 등록이 되는 것 같은데 왜 메트릭이 안 보일까??
여기서 흥미로운 점이 있었습니다.
registerMbeans=false
로 하면 외부 모니터링 시스템에서 Hikari 풀 지표가 아예 나타나지 않았습니다.registerMbeans=true + @EnableMBeanExport(registration = IGNORE_EXISTING)
조합에서는 지표가 잘 보였습니다.그 이유는 다음과 같습니다.
MBeanExporter
는 스프링 빈을 MBean
으로 등록하는 역할을 할 뿐, Hikari 내부 풀 상태 지표(MXBean)까지 대신 등록하지는 않습니다.registerMbeans=false
로 꺼버리면, 단순히 DataSource
라는 객체만 MBean
으로 보일 뿐 우리가 원하는 풀 상태 지표(ActiveConnections, IdleConnections 등) 는 아예 노출되지 않습니다.registerMbeans=true
면 HikariCP가 직접 풀 관련 MBean
을 JMX에 등록합니다.IGNORE_EXISTING
덕분에 Spring이 중복 등록을 시도하다가 충돌하지 않고, Hikari가 등록한 MBean이 그대로 유지됩니다.그럼 어떤 방법을 선택해야 할까요?
registerMbeans=false
), 대신 Micrometer의 Hikari 모듈을 활성화하는 것이 깔끔합니다.registerMbeans=true
를 유지하고, Spring에는 IGNORE_EXISTING
을 줘서 충돌만 피하는 게 현실적인 방법입니다.저 같은 경우, 사내에서 후자의 JMX 기반 모니터링 툴이 제공되고 사용하고 있기 때문에
registerMbeans=true
를 유지하고, Spring에는IGNORE_EXISTING
을 주는 방식으로 문제를 해결했습니다. (물론, 프로메테우스/그라파나 도 사용 중이지만, 해당 용도와 달라 위와 같이 판단했습니다.)
⸻
이번 이슈를 겪으면서, 단순히 “에러 로그 고치기”를 넘어서 Spring Boot Actuator, JMX, MBean, HikariCP의 관계를 이해할 수 있었습니다.
혹시 비슷한 에러(InstanceAlreadyExistsException
)를 만난다면,
오늘도 화이팅입니다~!