본문 바로가기

OpenSource

[JDBC] JDBC Internal - 타임아웃의 이해 정리

http://www.cubrid.org/blog/dev-platform/understanding-jdbc-internals-and-timeout-configuration/ 원본


http://d2.naver.com/helloworld/1321 해석본 여기 내용 참조해서 정리



* 상위 레벨의 타임아웃은 하위 레벨의 타임아웃에 의존성을 가지고 있다. 하위 레벨의 타임아웃이 정상으로 동작해야 상위 레벨의 타임아웃도 정상으로 


  동작한다. 예를 들면, JDBC Driver SocketTimeout이 정상으로 동작하지 않으면, 그보다 상위 레벨의 타임아웃인 StatementTimeout과 


  TransactionTimeout도 정상으로 동작하지 않는다.


* StatementTimeout은 Statement 한 개의 수행 시간을 제한하는 기능만 담당한다. 네트워크 장애에 대비하는 타임아웃은 JDBC Driver 


  SocketTimeout이 처리해야한다. (설정방법은 java.sql.Statement.setQueryTimeout(init) 메서드로 설정)


  이 떄, JDBC Driver SocketTimeout은 OS의 SocketTimeout 설정에 영향을 받는다. JDBC Driver SocketTimeout을 설정하지 않아도 네트워크 장애 발생 


  이후 30분이 지나면 JDBC Connection Hang 이 복구되는 것은 OS의 SocketTimeout 설정 때문이다.


* SocketTimeout은 JDBC Connection 내부의 소켓 타임아웃을 수행. 즉, Connection 에서 Socket을 열어서 취하는 Type4 방식이라면 Socket 의


  Timeout을 결정할 수 있다는거지.

  

  (설정 방법은 JDBC 드라이버 옵션 설정)


* 여기서 잠깐 요약하고 넘어가면 WAS - Framework - MyBatis - DBMS 이렇게 있으면 WAS 에서는 단순히 Connection Pool을 관리만 하는 


   것 이다. 즉, 타임아웃 설정은 Connection을 받은 프레임워크가 받아서 처리한다. 예를 들면, IBatis에서 StatementTimeout 값을 설정할 수 있다.


* DBCP는 Connection을 생성하고 관리하는 일을 하며, 타임아웃 처리는 관여하지 않음. 




JDBCInternal3

그림 3 각 레벨 별 타임아웃



* TransactionTimeout은 프레임워크나 애플리케이션 레벨에서 유효한 타임아웃이다.


  StatementTimeout * N (Statement 수행 수) + a (가비지 컬렉션 및 기타)


  전체 Statement 수행 시간을 허용할 수 있는 최대 시간 이내로 제한하려 할 때 TransactionTimeout 사용


  ( 실제로 프레임워크의 서비스 타임아웃 같은 것이 트랜잭션 타임아웃이라 할 수 있다. )




* Spring 에서 제공하는 TransactionTimeout 원리는 Trasaction Synchronization 방식을 사용한다. Connection 을 ThreadLocal에 저장해두고


  사용한다. ThreadLocal에 Connection 저장 시 Trsaction 의 시작 시간과 타임아웃 시간을 같이 기록하고, Proxy Connection을 사용하여


  Statement 를 생성하는 작업을 시도할 경우 경과 시간을 체크하여 예외를 발생시킴. 


  (ThreadLocal은 쓰레드 단위로 로컬 변수를 할당할 수 있다. 즉, 동기화를 보장해준다는 것이지. 그러한 이유 때문에 ThreadLocal에


   Connection을 저장해둠으로써 여러개의 Connection이 동시에 ThreadLocal 에 진입해도 동기화를 보장해준다.)      




* StatementTimeout 이란?


  Statement 하나가 얼마나 오래 수행되어도 괜찮은지에 대한 한계 값이다. JDBC API인 Statement에 타임아웃 값을 설정하며, 이 값을


  바탕으로 JDBC 드라이버가 StatementTimeout 을 처리한다. java.sql.Statement.setQueryTimeout(int timeout) 


  (위에서도 설명했지만 IBatis를 통해 Statement 타임아웃을 설정할 수 있고 statement, insert, select, update 구문마다 @timeout 값으로


  개별적으로 설정할 수도 있다.)



  

* Oracle JDBC Statement의 QueryTimeout은 과정


  ① Connection.createStatement() 메서드를 호출하여 Statement를 생성한다.

  

  ② Statement.executeQuery() 메서드를 호출한다. 

 

  ③ Statement는 자신의 Connection을 사용하여 Oracle DBMS로 쿼리를 전송한다.


  ④ Statement는 타임아웃 처리를 위해 OracleTimeoutPollingThread(classloader별로 1개 존재)에 Statement를 등록한다.


  ⑤ 타임아웃이 발생한다.


  ⑥ OracleTimeoutPollingThread는 OracleStatement.cancel() 메서드를 호출한다.


  ⑦ Connection을 통해 취소(cancel) 메시지를 전송하여 수행중인 쿼리를 취소한다



* JDBC 드라이버의 SocketTimeout 이란?


  JDBC Driver Type4는 소켓을 사용하여 DBMS에 연결하는 방식이고, 애플리케이션과 DBMS 사이의 ConnectionTimeout 처리는


  DBMS 에서 하지 않음.


  SocketTimeout 값은 DBMS가 비정상으로 종료되었거나 네트워크 장애가 발생했을 때 필요한 값이다. TCP / IP 의 구조상 소켓에는


  네트워크의 장애를 감지할 수 있는 방법이 없다. 그렇기 때문에 애플리케이션은 DBMS와의 연결 끊김을 알 수 없다. 이럴 때 SocketTimeout을 


  이용해서 타임아웃을 걸 수 있다. 만약 SocketTimeout이 설정 되어 있지 않다면 애플리케이션은 DBMS로부터의 결과를 무한정 기다릴 수 있다.


  이러한 Connection을 Dead Connection 이라고 부른다.


  보통 상위 타임아웃이 하위 타임아웃보다 커야하지만 SocketTimeout 값은 StatementTimeout 값보다는 크게 설정해야 한다. SocketTimeout 


  값이 StatementTimeout 보다 작으면, SocketTimeout 이 먼저 동작하므로 StatementTimeout 값은 의미가 없게 된다.


  StatementTimeout 는 Statement 자체에 거는 것이 목적이고, SocketTimeout은 애플리케이션과 DBMS 간 통신에 대해 타임아웃을 거는 것이


  주목적이다.  







* OS 레벨 SocketTimeout 설정


  OS 레벨에서 네트워크 연결 끊김을 확인한다. SocketTimeout 설정을 0으로 해도 OS 레벨에서 Timeout을 체크한다. 그래서 네트워크 장애를


  대비한다.