2013년 6월 20일 목요일

Software caused connection abort: recv failed 오류에 대한 고찰


디비 이전 관련해서 발생한 이슈에 대한 해결 방안


원인을 파악하기 위해 조사를 하다가 발견한 사항입니다.

특정 DB 오라클 뿐만이 아니라 대부분의 DBMS의 경우 DB측에서 클라이언트로부터 정기적인 요청이 없는 경우(장시간 요청이 없는 경우)
클라이언트로부터 요청 받았던 DB connection closed한다고 합니다.
java.net.SocketException: Software caused connection abort: recv failed
java.net.SocketException: Connection reset by peer: socket write error
위의 오류의 경우 클라이언트가 DBMS에서 접근하면서 오류가 발생한 것인데 클라이언트가 DBMS와 맺었던 connection을 찾지 못해 발생한 것으로 판단됩니다.

원인 조사와 동시에 해결책에 대하여 찾아보았고
본 시스템의 경우에는 아파치 common 라이브러리 중 org.apache.commons.dbcp.BasicDataSource 라이브러리를 사용 중입니다.
위의 원인으로 발생하는 것이 정확하다면 클라이언트에서 DBMS로 커넥션을 연결 맺고 시간이 지난 후 데이터를 요청하려 할 때 맺었던 connection에 대한
Check를 하는 방법이 있을까? 하는 의문이 들어 해당 라이브러리에 대하여 조사를 진행하였습니다.

관련 라이브러리 옵션 중에 validationQuery 속성이 제가 원하는 기능을 할 수 있을 것이라 판단되어
WAS config에 설정을 하고 테스트를 하였습니다.

테스트는 운영서버 1대를 빼서 validationQuery 속성을 추가하지 않은 상태로 두고 저희 로컬PC에는 validationQuery 속성을 추가하고
동일한 페이지를 일정 시간을 두고 접속을 해보는 것으로 진행하였습니다.

그 결과 운영서버 쪽은 오류가 발생하였지만 로컬PC 쪽에서는 정상적으로 접속되는 것을 확인하였습니다.

validationQuery 속성이 하는 일은 기존 맺었던 connection에 대하여 유효성을 판단하는 기능인데 단순히 “select 1 from dual” 쿼리를 이용하여 확인을 합니다 ^^
클라이언트에서 서비스 쿼리를 DBMS에 날리기 전에 먼저 실행하는 것이고 오류가 발생할 경우 다시 connection을 맺는 것으로 판단됩니다.

추가적으로 재미있는 것은 만일 위와 같은 사항이 상용에서는 일어날까?
제 판단으로는 상용에서는 일어나지 않을 것 같습니다. 이유는 본 서비스는 장시간 DBMS에 데이터를 요청하지 않는 경우가 없기 때문입니다.
하지만 돌다리도 두르려 본다는 심정으로 DB connection 관련 속성 중에 validationQuery와 같은 옵션을 통해 보다 안정적인 DB Connection을 보장해 줄 수 있지 않을까 생각합니다.

Oracle에서의 Software caused connection abort: recv failed 오류가 발생했을 때

오라클 서버 이전을 하게 되었다.
물리적 장비를 사용하다가 이번에 가상화 장비로 이전을 하게 되었고 데이터를 이전 한 후
기존 웹 서비스에 물려 테스트를 하게 되었다.

헌데 그전에는 발견하지 못했던 오류가 발생했다.

Software caused connection abort: recv failed

위의 오류는 웹 서버를 구동한 후 서비스가 활성화 되고 서비스에서 디비 서버 측에 데이터 요청을 하지 않으면 디비 서버에서 커넥션을 close해서 발생하는 문제 였다.

내가 관리하는 웹 서비스는 spring3 framework를 사용하고 있다.
디비에 접속하는 DataSource는 org.apache.commons.dbcp.BasicDataSource를 사용 중이다.

org.apache.commons.dbcp.BasicDataSource 라이브러리에서 위의 오류를 발생하지 않도록 하는 방법이 있을 것 같아 찾아 보았다.

오라클의 경우에는 BasicDataSource 내에 validationQuery 속성이 있고
이 속성은 DB를 연결하기 전에 해당 Connection이 정상적인지 유효성 판단을 한다.

사용 방법은 아래와 같다

<bean id="transactionCPSDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName"><value>${txcps.jdbc.driver}</value></property>
        <property name="url"><value>${txcps.jdbc.url}</value></property>
        <property name="username"><value>${txcps.jdbc.username}</value></property>
        <property name="password"><value>${txcps.jdbc.password}</value></property>
        <property name="defaultAutoCommit"><value>${txcps.jdbc.commit}</value></property>
        <property name="maxActive"><value>${txcps.jdbc.active}</value></property>
        <property name="maxIdle"><value>${txcps.jdbc.idle}</value></property>
        <property name="validationQuery" value="select 1 from dual"></property>
    </bean>

위의 붉은 색 글씨 부분 처럼 넣어주면 된다.

끝!! 머리 아팠는데 우하하