오픈소스 인사이트
home
오픈소스 기술 동향
home
💡

WildFly 데이터소스 커넥션 풀 누수 점검: CCM debug 기능 파헤치기

WildFly에서 데이터베이스 커넥션 풀 관리 시 가장 까다로운 문제 중 하나가 커넥션 누수(Connection Leak)입니다. 애플리케이션에서 커넥션을 얻고 나서 제대로 반납하지 않으면 풀이 고갈되어 새로운 요청을 처리할 수 없게 됩니다.

Q. "IJ000453: Unable to get managed connection"

오류가 자주 발생하고, DB 세션 수는 계속 증가한다면?

지금 바로 “커넥션 누수”를 의심해 보세요!

→ CCM(Cached Connection Manager) debug 기능을 활용해 누수 위치를 정확히 찾아보겠습니다.

커넥션 누수가 발생하는 주요 원인 4가지

1.
명시적 close() 호출 누락: 가장 흔한 원인
2.
예외 발생 시 finally 블록 부재: 예외 상황에서 커넥션 미반납
3.
try-with-resources 미사용: Java 7+ 권장 패턴 무시
4.
라이브러리/프레임워크 버그: 서드파티 컴포넌트의 누수

CCM Debug 기능의 작동 원리

감지 메커니즘

각 요청(HTTP 요청, EJB 호출 등)의 컨텍스트 경계에서 커넥션 상태 추적
컨텍스트 종료 시점에 반납되지 않은 커넥션 자동 감지

제공 정보

스택트레이스: 커넥션을 최초 요청한 코드 위치
자동 정리: 누수된 커넥션을 강제로 close 처리
경고 메시지: 개발자에게 직접적인 피드백

CCM Debug 설정 방법

CLI 명령어 (Standalone 모드)

# CCM debug 활성화 /subsystem=jca/cached-connection-manager=cached-connection-manager:write-attribute(name=debug,value=true) # 데이터소스에 CCM 연결 (기본값이지만 확인) /subsystem=datasources/data-source=your_datasource_name:write-attribute(name=use-ccm,value=true) # 설정 적용을 위한 재로드 /reload
Bash
복사

CLI 명령어 (Domain 모드)

# CCM debug 활성화 (프로파일 지정) /profile=full/subsystem=jca/cached-connection-manager=cached-connection-manager:write-attribute(name=debug,value=true) # 데이터소스에 CCM 연결 /profile=full/subsystem=datasources/data-source=your_datasource_name:write-attribute(name=use-ccm,value=true) # 설정 적용을 위한 재로드 /profile=full:reload
Bash
복사

XML 설정

<!-- JCA 서브시스템 설정 --> <subsystem xmlns="urn:jboss:domain:jca:5.0"> <cached-connection-manager debug="true" error="false"/> </subsystem> <!-- 데이터소스 설정 --> <subsystem xmlns="urn:jboss:domain:datasources:5.0"> <datasources> <datasource jndi-name="java:jboss/datasources/TestDS" pool-name="TestDS" enabled="true" use-ccm="true"> <!-- 데이터소스 상세 설정 --> </datasource> </datasources> </subsystem>
XML
복사

실제 누수 감지 시나리오

테스트 코드 (dctest.jsp)

<%@ page import="javax.sql.DataSource" %> <%@ page import="javax.naming.InitialContext" %> <%@ page import="java.sql.Connection" %> <% InitialContext ctx = new InitialContext(); DataSource ds = (DataSource) ctx.lookup("java:jboss/datasources/TestDS"); // 🚨 누수 발생 코드 Connection conn = ds.getConnection(); // conn.close(); <- 이 라인을 주석처리하면 누수 발생 out.println("Connection acquired: " + conn); %>
Plain Text
복사

누수 감지 로그 예시

2024-05-30 19:47:59,669 INFO [org.jboss.jca.core.api.connectionmanager.ccm.CachedConnectionManager] (default task-1) IJ000100: Closing a connection for you. Please close them yourself: org.jboss.jca.adapters.jdbc.jdk8.WrappedConnectionJDK8@20a767a1: java.lang.Throwable: STACKTRACE at org.jboss.jca.core.connectionmanager.ccm.CachedConnectionManagerImpl.registerConnection(CachedConnectionManagerImpl.java:308) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:819) at org.jboss.jca.adapters.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:151) at org.jboss.as.connector.subsystems.datasources.WildFlyDataSource.getConnection(WildFlyDataSource.java:64) at org.apache.jsp.dctest_jsp._jspService(dctest_jsp.java:122) // 👈 누수 발생 지점!
Plain Text
복사
핵심 포인트: 스택트레이스내용을 통해 어느 코드에서 누수가 발생했는지 알 수 있습니다.

로그 분석과 문제 해결

로그에서 찾아야 할 정보

1.
IJ000100 메시지: 누수된 커넥션 식별자와 스택트레이스
2.
애플리케이션 코드 경로: JSP, Servlet, EJB 등 실제 누수 위치
3.
패턴 분석: 특정 기능이나 시점에 집중된 누수인지 확인

올바른 커넥션 사용 패턴

// ✅ 권장: try-with-resources 사용 try (Connection conn = dataSource.getConnection()) { // 비즈니스 로직 수행 PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users"); ResultSet rs = stmt.executeQuery(); // 자동으로 conn.close() 호출됨 } catch (SQLException e) { // 예외 처리 } // ✅ 기존 방식: finally 블록 활용 Connection conn = null; try { conn = dataSource.getConnection(); // 비즈니스 로직 } catch (SQLException e) { // 예외 처리 } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { // 로깅 } } }
Java
복사

성능과 운영 고려사항

개발/테스트 환경
추천: debug="true" 상시 활성화
이유: 개발 중 누수를 조기에 발견하고 수정
운영 환경
추천: 문제 발생 시에만 일시적 활성화
이유: 로그 볼륨 증가와 약간의 성능 오버헤드
error 옵션 사용
개발환경: error="true"로 설정하여 RuntimeException 발생
운영환경: error="false"로 설정하여 로그만 기록

추가 진단 도구

Byteman 기반 상세 추적

복잡한 애플리케이션에서는 Byteman 규칙을 활용해 더 상세한 커넥션 라이프사이클을 추적할 수 있습니다:
RULE ConnectionTrace CLASS AbstractConnectionManager METHOD allocateConnection AT ENTRY DO traceStack("CONNECTION GET: " + $return, 10); ENDRULE
Plain Text
복사

힙 덤프 분석

메모리 누수와 함께 발생하는 경우 힙 덤프에서 커넥션 풀 상태를 확인:
-- VisualVM/Eclipse MAT OQL 쿼리 예시 select p.poolName, p.checkedOutSize, p.cls.baseCount from org.jboss.jca.core.connectionmanager.pool.mcp.* p
SQL
복사

실무 팁과 베스트 프랙티스

선택 가이드라인

CCM Debug 활성화 시점

새로운 애플리케이션 배포 전 반드시 테스트
커넥션 풀 고갈 오류 발생 시 즉시 활성화
정기적인 성능 테스트 시 포함

로그 모니터링

IJ000100 메시지 패턴을 모니터링 도구에 등록
누수 빈도와 패턴을 시각화하여 트렌드 파악
특정 기능이나 사용자 패턴과의 연관성 분석

코드 리뷰 체크리스트

1.
모든 Connection 객체에 대한 close() 호출 확인
2.
try-with-resources 패턴 사용 권장
3.
서드파티 라이브러리의 커넥션 관리 방식 검토
운영 중 발견 시 대응방안
1.
즉시 대응: CCM debug 활성화로 누수 위치 특정
2.
임시 조치: 커넥션 풀 크기 일시적 증가 (근본 해결 아님)
3.
근본 해결: 스택트레이스 기반 코드 수정 및 배포
4.
검증: 수정 후 CCM 로그에서 해당 누수 메시지 소멸 확인
핵심 질문: 우리 애플리케이션에서 커넥션을 사용하는 모든 코드 경로가 예외 상황에서도 안전하게 자원을 반납하고 있는가?
한정상 프로
에스코어에서 미들웨어 엔지니어로 근무하며, 삼성 그룹사를 비롯한 국내 주요 대기업과 공공기관의 미들웨어 설계 및 기술지원을 담당하고 있어요