programming/.net2010.02.19 04:28
OLAP 관련프로젝트를 진행하며 처음으로 다중 or 다수 접속자 환경이 아닌 다소 lazy한 사용자 접속이 요구되는 프로그램을 만들게 되었습니다. 하지만 사용자 접속수가 적은 대신 OLAP 쿼리 하나 실행하는데 최대 20분이 걸리는 것이 있을 정도로 대용량 cube를 처리해야 하는 것이 고민이었습니다. 따라서 이에 따른 Database Connection Timeout Exception 문제를 해결하면서 알아낸 경험 및 정보들을 정리하고 공유하고자 합니다.
(어제부터 존댓말로 포스팅하고자 마음먹었는데 갑자기 문체를 바꾸려니 많이 어렵군요 ㅎㅎ)


Connection Timeout 과 Command Timeout

일반적으로 DB와 연결시간이 초과되었을 때를 의미하는 것은 Connection Time이라고 할 수 있습니다. 하지만 상황에 따라 Connection Timeout이 아닌 Command Timeout이 문제를 야기시키는 경우도 있어서, 일반적인 상황에서의 Connection Time만 늘리는 방식으로 해결이 안되어 당혹스러운 경우가 있습니다. 저도 이 둘의 차이를 몰라서 단순한 차이임에도 불구하고 해결법을 알아내기가 매우 어려웠던 기억이 납니다.  저처럼 기초가 부족한 경력자들이 자신만의 경험만 가지고 섣불리 판단하다가 생기는 문제가 이런게 아닌가 싶습니다.ㅎㅎ 

일단 둘의 정의를 MSDN에서 보면 Connection Timeout은 시도를 종료하고 오류를 생성하기 전에 연결하는 동안 대기할 시간이라고 설명하고 있습니다. Command Timeout은 명령 실행을 종료하고 오류를 생성하기 전 대기 시간이라고 합니다. 위 설명을 보다 구체적으로 확인하기 위해 코드를 짜보았습니다.

<처리시간이 오래걸리는 상황을 시뮬레이션 하기 위한 프로시저>

CREATE PROCEDURE [dbo].[USP_WAIT]  
AS  
BEGIN  
    waitfor delay '00:00:05' -- 5 sec  
END  
<Connection Timeout 에러 발생을 시도한 코드>

using System;  
using System.Data.SqlClient;  
using System.Threading;  
using System.Data;  
  
namespace ConnectionTimeoutTest  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            try  
            {  
                string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;Timeout=1";  
  
                SqlConnection conn = new SqlConnection(constr);  
                conn.Open();  
  
                SqlCommand comm = conn.CreateCommand();  
                comm.CommandText = "USP_WAIT";  
                comm.CommandType = CommandType.StoredProcedure;  
                comm.ExecuteNonQuery();  
  
                conn.Close();  
            }  
            catch (Exception ex)  
            {  
                throw ex;  
            }  
        }  
    }  
}  
위 코드에서 보듯이 Connection Timeout을 1초로 셋팅하고 5초가 걸리는 프로시저를 실행했지만 에러가 발생하지 않았습니다. 이번엔 Command Timeout을 셋팅해 보겠습니다.

<Command Timeout 에러 발생을 시도한 코드>

using System;  
using System.Data.SqlClient;  
using System.Threading;  
using System.Data;  
  
namespace ConnectionTimeoutTest  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            try  
            {  
                string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;Timeout=1";  
  
                SqlConnection conn = new SqlConnection(constr);  
                conn.Open();  
  
                SqlCommand comm = conn.CreateCommand();  
                comm.CommandTimeout = 1;  
                comm.CommandText = "USP_WAIT";  
                comm.CommandType = CommandType.StoredProcedure;  
                comm.ExecuteNonQuery();  
  
                conn.Close();  
            }  
            catch (Exception ex)  
            {  
                throw ex;  
            }  
        }  
    }  
}  
위 처럼 CommandTimeout을 1초로 셋팅 한 후 실행해보니 이번엔 에러가 발생했습니다.

<Command Timeout 에러 발생 장면>



위 결과에서 보듯이 Connection Timeout과 Command Timeout과 서로 다름을 알 수 있고, MSDN에서도 Command Timeout은 Connection 객체의 Connection Timeout을 상속받지 않는다고 설명하고 있습니다.
하지만 한가지 이상한 것은 왜 Connection Timeout 에러는 발생하지 않았을까요? 
아마도 Command Timeout은 Socket을 통하여 명령을 요청하고 값을 받을 때 까지의 시간을 의미하는 것이고 Connection Timeout은 Connection Open부터 Close까지의 시간이 아니라 Connection의 Open시도가 정상적으로 완료되기 까지의 시간을 의미하지 않나 추리하고 있습니다. (혹시 아니라면 댓글 주세요 ^^)


Connection Timeout과 Command Timeout을 해결하자

Connection Timeout의 해결법은 간단합니다. ConnectionString에 아래 처럼 Timeout이나 Connection Timeout이나 Connect Timeout 값을 셋팅하면 됩니다.

string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;Timeout=100";  
string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;Connection Timeout=100";  
string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;Connect Timeout=100";  
하지만 Command Timeout은 ConnectionString으로 해결 할 수 없고, 코드에 직접 셋팅을 해 줘야 합니다.
0으로 셋팅하면 무제한 대기하게 되지만, 이는 실제 에러가 발생했을 때를 감지하지 못하므로 추가적인 문제가 발생하게 될 위험이 있습니다. 


Timeout 발생시 DBMS는 무슨 동작을 할까?

또한 ConnectionTimeout과 CommandTimeout은 오로지 Client-Side의 판단에 의하여 처리됩니다. timeout 관련정보를 검색중에 우연히 안드로메다 토끼님 블로그에서 본 글인데, 지금 생각해보면 정확한 처리를 위해 당연한 것이라고 생각됩니다. 평소 ADO 관련 클래스들은 DB Process에 의존적인 것인줄로만 알았기 때문에 저도 쵸큼 놀란터라, 
정확한 이해를 위해 다음과 같은 코드로 Connection Timeout Expire Exception을 일부러 발생시키고 SQL Profiler로 확인해 봤습니다.

<timeout 에러발생 예제 코드>

using System;  
using System.Data.SqlClient;  
using System.Threading;  
using System.Data;  
  
namespace ConnectionTimeoutTest  
{  
    class Program  
    {  
        static void Main(string[] args)  
        {  
            try  
            {  
                string constr = "Data Source=.;Initial Catalog=TestDB;User Id=sa;Password=1234;";  
  
                SqlConnection conn = new SqlConnection(constr);  
                conn.Open();  
  
                SqlCommand comm = conn.CreateCommand();  
                comm.CommandTimeout = 1;  
                comm.CommandText = "USP_WAIT";  
                comm.CommandType = CommandType.StoredProcedure;  
                comm.ExecuteNonQuery();  
  
                conn.Close();  
            }  
            catch (Exception ex)  
            {  
                throw ex;  
            }  
        }  
    }  
}  
<timeout 에러발생 예제 실행시 체크한 SQL Profiler 화면>



위 이미지에서 보신듯이 프로그램에서 Timeout 에러가 발생해도 SQL에서는 전혀 액션이 없기 때문에,
"아하~ Connection Timeout 에러는 SQL 이벤트와는 상관없구나~" 라고 결론 내릴 수 있겠습니다.


끝내며

알기만 하면 어렵지 않은 부분인데 오랫동안 모르고 사용한터라 의미를 파악하고 정리하는데 꽤 애를 먹었습니다. 사실 아니 내가 이걸 몰랐다니!!! 라며 자괴감에 빠질뻔도 했구요..ㅎㅎ 어쨌든 새로운 기술을 공부하는것도 중요하지만 알고 있었던 부분도 다시 리뷰하는게 꽤 도움이 된것 같습니다. 

참고링크
저작자 표시 동일 조건 변경 허락
신고
Posted by 귀뫄뉘
TAG

댓글을 달아 주세요

  1. 좋은 글 감사합니다.
    덕분에 고민하던 것이 한방에 해결되었습니다.
    보관을 위해 퍼갑니다.

    2011.11.01 09:10 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 지송

    잘보고 갑니다. 역시 디테일면에서 좀 다르네요 ^^;; 감사!!

    2012.03.05 10:12 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 저도 잘보고 갑니다. 테스트를 대신 해주신 것 같아서 감사합니다.
    저는 LINQ를 쓰는데 DataContext에서는 어떻게 하는지 찾아봤는데 CommandTimeout라는 프로퍼티가 있군요. (기본값은 30이더군요)

    2013.01.08 19:24 신고 [ ADDR : EDIT/ DEL : REPLY ]
  4. 와주셔서 감사합니다 ^^ Linq도 내부코드로는 SqlCommand를 래핑하고있을것으로 생각됩니다. 똑같은 매커니즘이라고 생각하시면 될것같아요 ^^

    2013.01.13 10:33 신고 [ ADDR : EDIT/ DEL : REPLY ]
  5. 좋은 정보 감사합니다.

    2013.02.14 09:57 신고 [ ADDR : EDIT/ DEL : REPLY ]
  6. mjkim

    많은 도움 되었습니다. 감사합니다~

    2017.05.10 09:01 신고 [ ADDR : EDIT/ DEL : REPLY ]


티스토리 툴바