lecture Home > Middle Tier Tech > 아놀드의 C# & COM+  

Performance

   강좌 최초 작성일 : 2004년 09월 19일
   강좌 최종 수정일 : 2004년 09월 20일

   작성자 : 박정훈
   편집자 : 지용군(성 지용)

   강좌 제목 : Connection Pooling Part2 

강좌 전 아놀드의 잡담>

이번 시간에는 Connection Pooling 2번째 시간입니다. 첫 번째 시간에 무엇을 다루었는지, 별로 기억이 나진 않지만, 어쨌든 Connection Pool에 대해서 잠시 기억을 더듬어 보면 하나의 Process내에서 제공하는 database 연결에 대한 풀입니다. 여기서 중요한 것은 하나의 Process 내에서 제공한다는 점입니다. COM+ 가 Hosting 되는 서비스를 ASP.NET(IIS) 와 Windows Service 정도로 생각을 한다면 각 프로세스 공간 안에서 풀-서비스를 제공한다는 것이네요.

오늘 다루어 볼 문제는 SqlConnection을 통해서 DB에 접근할 때 Connection String의 변경을 통해서 일어나는 현상에 대해서 살펴보려고 합니다.

소스 코드(다운로드)


강좌 시작 >

0. 시작에 앞서

몇 가지 준비해야 될 사항이 있습니다. 첨부된 Project를 보면 BSL,Web 디렉토리로 나누어져 있습니다. Web 디렉토리의 ConnectionPooling.csproj.webinfo 파일을 열어보시면 이 웹-프로젝트가 실행되어야 할 가상 디렉토리 경로가 나와 있습니다. 이 경로에 따라서 가상디렉토리를 설정해 주시면 됩니다. BSL은 COM+ 응용프로그램을 나타냅니다. 특별히 해주셔야 할 것은 없네요.

아, 처음 프로젝트를 실행하다 보면 Registry Key 관련 Access error 가 발생할 수 있습니다.
원인은 명시적으로 COM+ 컴포넌트를 등록하지 않는다면 (Regsvcs.exe), Client가 호출하는 RunTime에 등록이 일어나는데, 이 등록 과정에서 Registry에 값을 써야 하죠. Registry에 쓰기 위해서는?
당연히 Administrators 의 권한이 필요한데, Windows 2003의 웹 응용프로그램이 실행되는 기본 계정의 경우에 이 권한이 없습니다. Regsvcs.exe를 통해서 COM+ 응용프로그램을 명시적으로 등록해 주거나 웹-응용프로그램이 실행되는 풀의 계정을 변경해 주어야 합니다.
편의상 Regsvcs.exe를 통해 BLL.dll 을 등록해 주시면 되겠습니다.

1. Connection Pool Timeout vs Connection LifeTime

두 가지 개념에 대한 설명을 잠시... Connection Pool Timeout은 Connection Pool이 Minimum Size로 줄어드는 시간을 말합니다. 가령 Minimum Size가 5인 Connection Pool에 대해 Connection이 10개가 사용되고 있다고 가정하고 10개에 대한 사용이 끝나면 - 프로그램 상에서 Conn.Close()호출 - Connection은 풀로 들어갑니다. 10개의 DataBase 연결이 유지된 상태에서 ConnectionPool Timeout 이 지나면 Min Size인 5개만 남겨두고 다른 연결은 모두 끊어 버리는 것이죠.

반면 Connection LifeTime 이라는 것은 Connection이 사용되고 나서 풀에 들어 왔을 때 비교되는 시간으로 Connection이 풀에 다시 들어갈 것인지를 결정하는 시간이 됩니다.

가령 Connection LifeTime이 60(sec)인 객체가 있다고 가정할 때 Request를 처리하고 다시 풀에 들어갔을 때 소요시간이 80초라면 객체는 풀에 들어가지 못하는 것이죠. 여기서 얘기하는 소요시간이라는 것은 물리적으로 DB Connection이 최초 Open() 되고 나서 지난 시간을 말하는 것입니다. 그렇다면 풀에 들어가지 못한다는 얘기는 무엇을 의미하는지…. 그것은 물리적으로 DB Connection 자체가 Close()되는 것을 의미합니다.

2. Connection Pool 의 Default value

SqlConnection의 Connection String을 살펴보면 풀링과 관련된 몇 가지 속성들이 있습니다.

  1. Pooling : 풀링의 적용여부를 나타내고 기본값은 true입니다.
  2. Min Pool Size : 풀의 최소 연결 수를 나타냅니다. 기본 값은 0입니다.
  3. Max Pool Size : 풀의 최대 연결 수를 나타냅니다. 기본 값은 100 이죠.
  4. Connection Life Time: Connection의 수명을 나타냅니다. 기본값은 0인데, 0은 최대값을 나타낸다고 하네요.

오늘 집중적으로 살펴볼 값이 바로 4) 번에 있는 Connection Life Time입니다. 4)번을 한번 째려보죠.

"오늘 죽었어" (ㅡㅡ;;)

프로젝트 마다 나가서 Connection String 값을 살펴보면 보통 다음과 같습니다.

"Server=Arnold;uid=sa;pwd=nold;database=Northwind;"
"Server=Arnold; Integrated Security=true;Database=NorthWind"
"Server=Arnold: Integrated Security=true;Min Pool Size=1;Max Pool Size=100;"

첫 번째가 가장 일반적인 값이죠. 두 번째의 경우에는 Windows 계정으로 실행되는데, Connection Pooling을 제대로 사용할 수 없는 위험이 좀 있고, 세 번째 경우는 풀 Size를 명시해 놓았군요 ^^

우리가 사용한 Connection String이 첫 번째라고 가정하고 이 때 적용되는 Default 값을 생각해 보죠.

풀링이 적용되고 Size는 0~100, Connection Life Time은 최대값으로 적용됩니다.

Case 1 : Default 값을 사용.

테스트는 BSL(COM+) 을 웹-프로젝트에서 호출하는 방식으로 진행하였습니다. 소스 자체는 굉장히 단순하기 때문에 특별한 설명없이 진행하도록 하겠고, GetCustomer() 메서드의 쿼리를 살펴보시면,

SELECT * FROM CUSTOMERS WAITFOR DELAY '000:00:10'

로 된 것을 볼 수 있는데 테스트의 편의상 쿼리에 10초 정도의 지연을 주었습니다. 테스트를 실행하기 전에 Connection의 상태에 대해서 살펴 볼 수 있도록 SQL Profiler를 열어두는 것도 잊지 마시죠.

Default 값으로 실행하면 Min Pool Size=0, Max Pool Size=100, Connection LifeTime = 0 으로 실행된 다고 말씀 드렸습니다. Connection LifeTime이 0이란 것은 Connection이 풀로 다시 들어올지 여부를 결정할 때 풀에 대부분 들어오는 것을 의미하겠죠. (최대치 값 적용)

Min =0 이라는 것은 Connection Pool Timeout 이 지나고 풀을 정리할 때 모든 Connection을 종료시키는 것을 의미합니다. Connection Pool Timeout 의 값에 대해서는 .NET 에서 interface를 제공하지 않아 값을 설정할 수는 없지만, (설정할 수 있는 메서드를 제공하지는 않지만, Reflection을 사용하면 설정할 수 도 있습니다.) 초기값이 6분 20초입니다.
6분 20초 후에는 Min Size로 정리가 된다는 얘기죠.

실행)
BLL에 보시면 GetCustomers()라는 메서드에 strConn 이 있습니다. 이 연결문자를 다음과 같이 바꿉니다.

"server=localhost;uid=sa;pwd=;database=northwind;"

SQL Profiler를 열고 Run시키고 브라우저를 두개 열어서 WebForm1.aspx를 띄웁니다. 두개를 띄운 이유는 Connection을 두개 열기 위해서 이죠.

창을 두개 띄운 상태에서 버튼을 눌러주면 쿼리문이 실행됩니다. 그리고 SQL Profiler 에는 다음과 같이 나오겠죠.

한 가지 예상과 다른 점은 Connection이 2개가 아니라 3개가 생성된다는 점이네요. 6분 20초가 지난 시점에서는 어떤 결과가 나올까요. Connection Pool Timeout이 지나면서 Min 으로 줄어듭니다.

첫 번째 시나리오는 Connection LifeTime 을 적용하지 않은 경우인데, Connection 사용에 좀 문제가 있을 듯 합니다. 그 원인은 Connection LifeTime이 명시되지 않았기 때문에 Connection 자체는 사용되고 나서 Connection Pool에 위치합니다.
그 Connection Pool Timeout은 3분에서 7분20초 사이인데, Connection이 한번 사용되고 나서 풀에 들어간 이후에 다시 사용되지 않을 경우에는 오랫동안 열려 있을 가능성이 있다는 점이죠.

Case 2 : Connection이 사용중일 때.

Case 1번에서는 Default 값으로 주었을 때의 상황에 대해서 살펴보았습니다. Connection Pool Timeout이 되면 Connection은 Minimum Size로 되돌아 간다. 그렇다면, Connection Pool Time 시점에서 Connection이 사용중이라면 어떻게 될까.. 궁금해서 해보았습니다.

Connection String의 설정은 같고 Connection을 2개를 열고 첫 번째 Connection Pool Timeout이 걸리는 시점에서 쿼리를 실행해 보았습니다.

SELECT SPID,LOGIN_TIME,LAST_BATCH FROM SYSPROCESSES WHERE LOGINAME='SA' AND HOSTNAME='ARNOLD'

쿼리 분석기에서 실행시키면 현재 샘플 프로젝트에서 사용되고 있는 Connection이 나옵니다.
(로컬에서 다른 프로그램이 SA의 계정으로 실행되지 않고 있다는 가정에서죠.. ^^;;) 결과를 보니, Timeout이 된 시점에서도 Connection은 Min Size인 0으로 돌아가지 않습니다.
그렇다면 Connection은 언제 다시 Minimum으로 줄어드는 것일까.. 첫번째 TimeOut을 지난 Connection은 다음 번 Timeout이 실행된 시점에서 Close됩니다.
즉, Connection이 12시 정각에 열렸다면 첫 번째 Timeout인 12:06:20 에서는 사용 중이기 때문에 Close 되지 않고, 다시 6분 20초가 경과된 12:12:40 에서 종료되는 것을 볼 수 있습니다.

Case 3 : Connection LifeTime을 주었을 때.

Connection String에 LifeTime을 20초로 주어 실행합니다. 즉, 다음과 같이.

"server=localhost;uid=sa;pwd=xxx;database=northwind;Connection LifeTime=20"

웹-브라우저를 띄워서 쿼리를 실행시킵니다. 앞에서 보신 것 같이 쿼리에는 Delay를 10초정도 주었습니다. 즉, 쿼리의 예상수행 시간은 10-11초 사이입니다. Connection LifeTime이 20초라는 것은?

Connection이 풀로 들어올 때 자신이 Open된 시간과 이 시간을 비교하는 시간이죠. 처음 쿼리를 실행하고 Connection이 풀에 들어오면 10-11초 정도라서 Connection은 풀에 들어가서 사용됩니다.

Connection Pool TimeOut이 발생하여 Minimum Size로 줄어들거나, 다른 쿼리 수행에 의해서 사용되기 전까지 이 Connection은 계속 풀에 남아있습니다. 즉, LifeTime은 Connection이 풀에 들어간 이후의 시간은 신경 쓰지 않는 것이죠. 한번 실행된 이후에 다시 들어갈 때 검사가 이루어 집니다.

결론.

지금까지 테스트 한 것을 가지고 결론을 내어보죠. Default 값을 사용한 경우에 문제가 될 수 있는 점은 LifeTime이 최대값이므로 Connection Pool TimeOut에만 의존하게 되는데, 상황에 따라서는 Connection 에 대해서 낭비가 될 수도 있다는 점입니다. 대략 4-7분정도 대기하게 되는데, Load가 많이 걸리는 시간에서는 중요한 문제가 될 수도 있죠. 따라서 Connection LifeTime에 대해서 명시적인 값을 주어 DataBase 연결이 일정시간 이상 지났을 때는 연결이 해지 되어 다른 프로그램에서 사용될 수 있도록 해야 합니다. 다음은 Minimum 값에 대한 얘기입니다.

Min 값의 경우 기본값이 0이고 그 이외의 값을 주어 항상 일정 수 만큼 연결이 대기하고 있도록 하는 것입니다. 상황에 따라서 다른 값이 적용될 수 있겠지만, 제 생각에는 기본값이나 최소값을 주는 것이 맞을 것 같습니다. 이유는 Min 값만큼 Connection이 계속 열려 있어야 하기 때문이죠.

Connection 이 계속 열려 있어서 바로 바로 서비스를 제공해야 되는 것이 아니냐 라고 생각할 수도 있지만, Case 2에서 보신 것과 같이 Connection Pool Time이 되어도 연결이 사용되고 있다면 Close되지 않습니다. Connection에 대해서 Load가 많이 걸리는 경우에는 Close되지 않고 다음 Pool Timeout이나 Life Timeout 을 기다리게 되는 것이죠. Min 값을 주었을 때는 다른 프로그램에서 사용하고 있는 연결 수를 고려해야 합니다. 여기서 잠시 Connection Pooling 의 범위를 생각해 보면, Connection Pooling은 프로세스 별로 관리됩니다. 웹-프로젝트 라면 ASP.NET이 실행되는 프로세스, Windows Service에서 실행되는 .NET Remoting이라면 그 서비스 프로세스 수 만큼의 Connection Pool 이 생성되는 것입니다…… 라고는 했지만, 거기에 연결 문자열도 포함되죠.

가령 A 프로세스에서 Northwind, Pubs DataBase에 대한 2개의 연결문자열을 사용한다면 A프로세스에는 2개의 Connection Pool이 생성되겠죠.

두서없이 얘기를 쭉 한 것 같은데, 결론을 얘기하자면 Default로 Connection Pool에 대해서 값을 명시하지 않은 경우 Connection에 대한 오류가 발생하지 않는다면 그대로 사용하셔도 상관없지만, Connection에 대한 Timeout (Connection에 대한 요청이 일정시간을 초과한 경우) 등의 문제가 발생하는 경우 Connection LifeTime을 적용해 주시면 될 것 같습니다.

LifeTime을 너무 짧게 주면 기존에 사용하던 Connection을 Close하고 새로운 연결이 pool에서 사용되기 때문에 피해야 하고, Connection Pool Time(4~7 min) 보다는 짧은 시간으로 주셔야 겠네요.

그간 Connection Pool에 대해 좀 추상적으로 가지고 있었던 생각들이 조금은 정리되는 느낌이네요.

바람이 좀 시원해 지면서 가을이 오나 보네요. 저는 인라인을 좋아해서 시원한 바람을 맞으며 인라인 탈 생각에 많은 기대가…ㅋㅋㅋ. 프로그램만 한다구 너무 실내에만 계시지 말구, 나다니고 운동도 좀 하고 그러시죠… 쫌~~~ 싫으면 말구… (--;;)

Back