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

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

7 more properties
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 로그에서 해당 누수 메시지 소멸 확인
👉 핵심 질문: 우리 애플리케이션에서 커넥션을 사용하는 모든 코드 경로가 예외 상황에서도 안전하게 자원을 반납하고 있는가?
한정상 프로
에스코어에서 미들웨어 엔지니어로 근무하며, 삼성 그룹사를 비롯한 국내 주요 대기업과 공공기관의 미들웨어 설계 및 기술지원을 담당하고 있어요 😄