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="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 로그에서 해당 누수 메시지 소멸 확인
한정상 프로
에스코어에서 미들웨어 엔지니어로 근무하며, 삼성 그룹사를 비롯한 국내 주요 대기업과 공공기관의 미들웨어 설계 및 기술지원을 담당하고 있어요 


