본문으로 이동
99%가 모른다는 DB Connection 누수 문제
문서

99%가 모른다는 DB Connection 누수 문제

김동호 · 컬리 · 컬리 기술 블로그

원본 보기

소개

DB Connection과 Garbage Collector의 관계를 중심으로 mysql-connector-j 사용 시 발생할 수 있는 메모리 누수를 탐지하고 해결한 경험을 공유합니다.

AI 핵심 요약

MariaDB JDBC 드라이버를 MySQL로 바꾼 뒤 EC2에서 OOM이 반복되자, 팀은 Heap Dump를 분석해 AbandonedConnectionCleanupThread가 보유한 PhantomReference와 Connection 객체가 누적된 것을 확인했습니다. 이 스레드는 ReferenceQueue를 감시하며 버려진 Connection의 네트워크 자원을 정리하지만, 단일 스레드가 한 번에 하나씩 처리해 네트워크 병목이 생길 수 있습니다. HikariCP의 max-lifetime을 50초로 짧게 설정한 탓에 Connection 재생성 속도가 정리 속도를 앞질렀고, mysql-connector-j를 8.0.22 이상으로 올린 뒤 정리 스레드를 비활성화하는 JVM 옵션을 적용했습니다. 적용 후 Heap Dump에서 해당 메모리 점유가 사라졌고, 장애 분석에는 트래픽 지표뿐 아니라 Heap Dump와 객체 참조 관계를 살펴보는 것이 중요하다는 교훈을 얻었습니다.

  • OOM이 발생하면 트래픽 증가만 의심하지 말고 Heap Dump에서 메모리를 점유하는 객체와 참조 경로를 확인하세요.
  • mysql-connector-j의 AbandonedConnectionCleanupThread는 PhantomReference와 ReferenceQueue를 이용해 Connection의 네트워크 자원을 정리합니다.
  • 단일 스레드가 네트워크 자원을 하나씩 정리하므로 Connection 재생성 속도가 처리 속도를 앞서면 참조 객체가 누적될 수 있습니다.
  • Connection의 max-lifetime을 짧게 설정할 때는 장애 조치 요구와 정리 작업의 부하를 함께 고려해야 합니다.
  • mysql-connector-j 8.0.22 이상에서는 -Dcom.mysql.cj.disableAbandonedConnectionCleanup=true 옵션으로 정리 스레드를 비활성화할 수 있습니다.