
최근 Tomcat 서버에서 Connection 관련된 에러를 만났다.
Connection has been abandoned PooledConnection
위 에러에서 Connection이 버려졌다는 것은 무엇인지, 그리고 왜 버려졌는지와 어떻게 해결할 수 있을지에 대해서 알아보자.
먼저 위 에러에 대해서 알기 위해서는 DBCP에 대해서 간략하게나마 알아야 할 필요가 있다.
데이터베이스 커넥션 풀(DBCP)은 애플리케이션이 데이터베이스와 연결할 때마다 새로운 커넥션을 생성하지 않고, 커넥션 풀에 미리 생성된 커넥션을 재사용하여 성능을 향상시키는 기법이다.
그러나 커넥션 풀에 있는 커넥션은 일정 시간 동안 사용되지 않으면 "Idle(유휴 상태)"가 된다.
데이터베이스 관리 시스템(DBMS)에는 이러한 Idle 커넥션을 일정 시간이 지나면 자동으로 끊어버리는 wait_timeout 설정이 있다.
그리고 이 때 끊어진 커넥션을 버려진 커넥션(=abandon connection)이라 칭한다.
위에서 이야기 한 것들을 조금 더 자세히 이야기 해보자.
어떤 커넥션이 사용된 후 일정 시간 동안 다시 사용되지 않으면 그 커넥션은 Idle 상태가 된다.
만약 커넥션이 Idle 상태로 wait_timeout 시간을 초과하면 DBMS는 해당 커넥션을 끊어버린다.
애플리케이션이 다시 그 Idle 커넥션을 사용하려고 할 때, 이미 DBMS가 해당 커넥션을 끊어버렸기 때문에 커넥션이 유효하지 않는다.
만약 해당 상태의 커넥션을 재사용(=재연결)하려고 하면 연결 실패나 오류가 발생한다.
이 때 ValidationInterval 기능은 ****커넥션이 유효한지 검증하는 주기를 설정하는 옵션이다. 예를 들어, 1시간으로 설정하면 1시간마다 커넥션이 유효한지 검증한다.
아래는 Tomcat의 Context.xml에 작성된 DBCP 설정 중 일부를 발췌했다.
<context:property-placeholder location="classpath:config/jdbc.properties.xml"/>
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close">
<property name="validationQuery" value="select 1 from dual"/> <!--Connection 유효성 검증을 위한 쿼리-->
<property name="validationInterval" value="6000"/> <!-- validation Query 실행 간격 ms-->
</bean>
Validation Query: 유효성 검사를 위해 사용하는 쿼리이며, SELECT 1 같은 간단한 쿼리를 사용한다.
그렇다면 해결 방법은 무엇일까?
ValidationInterval 기능을 통해 정기적으로 Validation Query를 실행하면 Idle 커넥션이 일정 주기마다 활성화된다.
이로 인해 커넥션이 DBMS의 wait_timeout을 초과하여 끊어지는 것을 방지할 수 있다.
커넥션 풀에 DBMS에 설정된 wait_time 시간 이상으로 Idle 상태인 커넥션에 대해서 DBMS는 연결을 종료한다.
이를 비유로 설명하여서 배달부들을 고용한 업장으로 예를 들어보자.
배달부(커넥션)들이일(=쿼리 후)을 하고 가게(=커넥션 풀)로 돌아와쉬고 있는 상태(=Idle 상태)이다.배달부들은 쉬고 있지만
업주(=데이터베이스)입장에서는 배달부들이 쉬고 있는 순간에도 배달부들에게돈(=리소스)이 소모된다.그러므로 일정 시간(=wait_time)동안 계속 놀고있는 배달부들에 대해서 업주는 계약을 해지한다.
"재사용되지 못하는 상황"이란 유휴 연결이 DBMS의 wait_timeout을 초과하여 끊어졌기 때문에, 그 연결을 다시 사용하려 할 때 연결이 유효하지 않아 재사용할 수 없는 상태를 의미한다.
ValidationInterval을 설정하고 Validation Query를 주기적으로 실행하면 이러한 상황을 방지할 수 있다.