Java로 간단한 console application을 만들다가 이상한 문제들을 마주하게 되었다. 그 중 하나는 DB 연결이 계속 끊어지는 현상. 현재 시점에서도 DB에 가해지는 부하는 정말 작은 수준이었기 때문에 특별히 tuning할 이유는 없었고 퍼포먼스와 관련해서는 기본 설정값으로 사용하고 있었는데 끊어지는 이유를 알 수가 없었다. (MySQL 5.5의 default wait_timeout은 8시간)
1. 환경
Application 동작의 흐름은 DB select, 특정 행위, DB update 순서였는데 특정한 기능을 수 행하는게 길게는 20분 정도 혹은 그 이상 소요되는 경우가 있었고 편의를 위해 MyBatis를 사용했으며 pool을 사용하도록 설정해 두었다. 연결이 끊어지는 현상을 보고 poolPingQuery, poolPingEnabled를 설정해 봤는데 마찬가지.
2. Azure에 idle timeout이 있다
우선은 MyBatis 설정과 별개로 왜 DB연결이 끊어지는지 궁금해졌다. DB와의 연결은 어차피 socket을 사용하기 때문에 DB와 application 사이의 통신에 영향을 줄 수 있는 것들은 많다. MyBatis 아래의 JDBC, Kernel의 socket timeout, 공유기 설정 등을 살펴봤는데 특이한 내용은 발견할 수 없었다.
다음으로 Azure에 어떤 특성이 있지 않을까 싶어서 알아보니 따로 idle timeout이 있다고 한다. 기본값이 4분이라고 하는데 테스트한 내용과 정확히 맞는다. (강제로 sleep 시간을 늘려가며 테스트해보니 3분까지는 문제가 없었고 4분부터 연결이 끊김을 확인) 이런 내용은 Azure 문서에 잘 보이지 않고 설정 또한 UI로는 불가능하다. PowerShell로만 가능한데 현재 열려있는 endpoint를 확인해보면 공백으로 표시되고 있고 powershell로 IdleTimeoutInMinutes 값을 30분까지 늘릴 수 있다고 한다.
3. Pool ping에 대한 잘못된 소문
Azure의 idle timeout과 별개로 MyBatis의 poolPing에 대해서 살펴보기로 했다. Pool ping 설정 중에 poolPingConnectionsNotUsedFor 가 있는데 문서 상으로는 마치 설정된 시간에 한번씩 DB에 ping으로 설정된 쿼리를 날려서 연결을 유지해줄 것처럼 보인다. 국내의 대부분 블로그 등에서도 비슷하게 설명하고 있다. 하지만 이 내용은 공식 문서가 잘못된 것인지 예상한대로 동작하지 않는다. 거의 동일한 의문을 가진 해외 사용자의 글을 보기도 했는데 소스를 보면 connection pool에서 실제 connection을 꺼내오거나 넣을 때만 connection이 유효한지 확인을 하는데 이 때 pool ping과 관련된 작업을 수행한다. poolPingConnectionsNotUsedFor에 설정된 값은 connection 유효성을 확인할 때만 영향을 주기 때문에 pool에서 connection을 꺼내오고 집어넣는 시점 이외에는 전혀 영향을 주지 않는다.
4. 결론
Azure나 기타 환경에 대한 timeout 값을 늘리는 것은 좋은 방법은 아니라고 본다. DB connection을 오래도록 유지해야만 하는 상황이라면 별도의 장치를 두어서 connection을 유지하도록 조치하거나 아니면 아예 비용이 소모되더라도 필요한 상황에서만 connection을 맺고 끊는 게 나을 것 같다..
5. 참고
(1) MyBatis 공식문서
http://www.mybatis.org/mybatis-3/configuration.html
(2) MyBatis 참고 소스