Top

Mybatis-Spring의 Connection 해제

프로젝트를 진행하다가 DB Connection을 맺지 못하는 이슈가 발생했다.

에러 로그는 아래와 같다.

org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Timed out waiting for a free available connection. Caused by: java.sql.SQLException: Timed out waiting for a free available connection.

의심되는 영역은 아래와 같다.

  1. boneCP에서 Pool 관리 설정에 에러가 존재
  2. mybatis Connection을 release하지 않아서, Connection은 많이 열려있지만 유효한 Connection이 없다.

 

1번의 테스트를 위해  minConnectionsPerPartition=0, maxConnectionsPerPartition=1로 설정하여 에러의 재현을 시도했다.

하지만 partition=2 이므로, 최대 2개의 connection이 open되어야 하는데 3정도까지 connection이 생성되고,  위와 같은 에러는 발생하지 않았다.

(음 boneCP는 문제인가?)

 

2번의 테스트를 위해 구글신에게 여러가지를 물어봤다.

copy&paste하여 프로젝트를 구성했더니, 돌아가게는 했는데 기본 원리를 모르고 있었다.

persistence framework로 mybatis를 사용하고 있었는데

이게 신기하게도 Dao단에서 Session을 가져오지도 않고, 쿼리가 끝난 후에 connection을 닫아 주는 부분도 존재하지 않는다.

전부터 이 부분이 이상하다고 생각하여, 오늘 문제가 발생하자 덜컥 의심이 되었다.

하지만 확인해보니 내가 사용한 것은 mybatis-spring 1.2.5로 session에 대한 의존성 주입과 사용이 끝난 session에 대한 release를 스프링에게 위임하여 처리하는 신기한 녀석이었다.

(mybatis-spring에 대해서는 여기를 참고)

일단 boneCP와 mybatis-spring에서 문제가 발생한 것은 아니라는 것을 확인했는데… 그럼 도대체 뭐가 문제일까?

정말로 DB의 Connection의 부족한 것일까?

이를 확인하기 위해 20초 마다 한번씩 db connection 수를 로깅하도록 간단한 쉘 스크립트를 작성하여 돌려 놓았다.

while true; 
do 
date; 
totalCnt=$(netstat -nao | grep 3306 | grep ESTABLISHED | wc -l);

printf "db connection:$totalCnt\r\n"; 
printf "consumer connection:"; lsof -p 122367 | grep mysql | wc -l;
printf "mdgs server connection:";lsof -p 122306 | grep mysql | wc -l
printf "bypass server connection:";lsof -p 79501 | grep mysql | wc -l
printf "OADR VEN connection:"; lsof -p 34070 | grep mysql | wc -l;
printf "gems connection:"; lsof -p 71082 | grep mysql | wc -l;

if [ "$totalCnt" -gt 90 ]; then
printf "Error\r\n";
netstat -naop | grep 3306; printf "\r\n"; 
fi
printf "\r\n"
sleep 30; 
done > checkDbCount.log

 

나중에 다시 에러가 발생하면 확인해보도록 하자.

 

드디어 에러가 재현되었다.

간단히 만들어 놓은 DB Connection Monitoring 스크립트의 로그를 확인해보니

max connection 이상의 connection이 생성된 것은 아니었다.

해당 프로세스는 여전히 설정해 놓은 최대 connection인 20개를 넘기지 않았다.

그런데도 connection을 얻을 수 없다고 에러를 발생 시켰다.

확인 해보니 activemq 쪽에 매우 많은 데이터가 pending되어 있었고, 최소로 설정한 consumer를 넘어서 max consumer까지 consumer가 늘어나 있었다.

activemq

active mq의 consumer는 내부적으로 thread로 구현되는 것 같은데

추측하건데 아래와 같은 과정에 의해 문제가 발생한 것으로 생각된다.

  1.  갑자기 많은 데이터 유입
  2. activemq의 consumer 증가(기본 20개, 최대 60개로 설정되어 있었음)
  3. Thread 증가
  4. db pool의 max connection을 초과하는 thread가 동시에 db connection을 요청함에 따라 connection error 발생

위 가정이 맞는지 확인해보기 위해 activemq의 max consumer 수를 db pool의 max connection과 동일하게 설정한 후 프로세스를 재기동 헀다.

추후 문제가 재발하지 않는다면 위 가정이 맞는 것으로 생각된다.

 

참고

kaze

Test

No Comments

Post a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.