적시 활성화(Just-in-Time Activation) 서비스 01.

등록일시: 2005-01-14 17:44,  수정일시: 2018-04-07 12:00
조회수: 13,025
본문은 최초 작성 이후, 약 19년 이상 지난 문서입니다. 일부 내용은 최근의 현실과 맞지 않거나 동떨어져 있을 수 있으며 문서 내용에 오류가 존재할 수도 있습니다. 또한 본문을 작성하던 당시 필자의 의견과 현재의 의견에 많은 차이가 존재할 수도 있습니다. 이 점, 참고하시기 바랍니다.

필자가 지금까지 참여했던 여러 프로젝트들에서의 개인적인 경험을 바탕으로, 실무에서 흔히 겪기 마련인 다양한 문제점들을 어디까지나 주관적인 관점에서 몇 가지 정도 정리해보면, 그 목록에서 그런대로 제법 높은 순위를 차지하고 있는 것 중 하나가 바로 COM+ 서비스와 관련된 곤란함들이다. 그런데, 재미있는 사실은 필자의 경우 기술적 측면보다는 COM+ 서비스에 대한 일반적인 인식에서 비롯된 곤란을 더 많이 겪었다는 점인데, 즉 프로젝트의 핵심 멤버들 중 한 분이 COM+ 서비스를 논리적인 이유도 없이 극단적으로 배척한다거나 거꾸로 맹목적으로 맹신하는 상황 등이 바로 그런 경우이다. 사람을 설득하는 기술이 많이 부족한 필자로서는 참 난감한 상황이 아닐 수 없었고, 당연히 프로젝트 자체로도 이런 상황은 긍정적인 영향을 주지는 못하기 마련이었다.

필자가 처음 COM+ 서비스에 관심을 갖게 됐던 시기는 보편적으로 윈도우즈 NT 4.0 서버와 IIS 4.0, 그리고 SQL 서버 6.5 또는 7.0의 조합이 널리 운영되던 때였으며, 아직 윈도우즈 2000 제품군은 출시되지 않았던 시점이었다. 그리고, 당시에는 기술의 명칭도 COM+ 서비스가 아닌 MTS였으며 지금의 COM+ 서비스와는 많은 차이점들이 존재하고 있었다. 그러나, 이미 당시에도 MTS에 관해서 매우 깊이 있는 지식을 보유하고 계신 분들이 많이 계셨었고, 필자는 그런 분들의 게시물을 비롯해서 얼마되지 않는 관련 서적들을 보면서 감탄해하는 동시에 나름대로 스스로도 깊이 있는 학습을 하고자 노력했었다. 그리고, 지극히 당연한 얘기겠지만 조금씩 기술을 이해할 수 있게 되었을 때부터는 실무에서 MTS를 활용해보고 싶다는 개인적인 욕심이 생기기 시작했는데, 막상 MTS를 실무에 도입하려고 하자 미처 예상하지 못했던 현실적인 문제점들이 조금씩 드러나기 시작했다. 무엇보다도 가장 큰 문제점은 프로젝트의 의사 결정권을 갖고 있는 핵심 담당자들이 도무지 MTS나 COM+ 서비스를 수용하려고 들지 않는 것이었다. 물론, 이는 근본적으로는 필자의 숙련되지 못한 기술 자체가 그분들에게 신뢰감을 주지 못한 것이 가장 큰 원인이었겠지만, 마이크로소프트의 기술을 경시하는 당시 업체들의 보편적인 풍조를 비롯해서 그리 널리 알려지지 못한 기술이라는 이유와 함께 거의 찾아보기 힘든 레퍼런스 프로젝트의 부재 같은 여러 가지 복합적인 이유들이 이런 상황에 전반적으로 일조했던 것이라고 생각한다. 이처럼 필자가 MTS나 COM+ 서비스에 관심을 갖기 시작했던 초기에는 COM+ 서비스를 제대로 설계하거나 본격적으로 적용해 볼 수 있을 만한 프로젝트를 찾는 일 자체가 힘든 시기였으며 필자로서는 내심 그 점이 항상 커다란 불만이었다.

다행스럽게도 최근에는 이런 양상에 많은 변화가 생긴 것 같다. 무엇보다 COM+ 서비스 자체가 매우 보편적으로 인식된 상태며, 어느 정도 규모가 있는 프로젝트들 중에서도 COM+ 서비스를 적절히 활용하고 있는 사례를 찾아보는 것이 크게 어렵지만은 않은 실정이다. 그리고, 이에 더하여 .NET 프레임워크에서 제공되는 COM+ 서비스 관련 기반 구조라고 말할 수 있는 .NET 엔터프라이즈 서비스에 대한 여러 가지 활발한 논의들이 진행되고 있다는 점을 감안해 볼 때 앞으로도 이러한 추세에는 단기적으로 큰 변화가 있을 것 같지는 않다. 아무튼 이런 점들만 감안해서 생각해본다면 필자가 예전에 느꼈던 많은 어려움들이 이제는 어느 정도 해소되었을 것이라고 예상할 수 있을 것이다. 그런데, 실제로는 여전히 COM+ 서비스를 프로젝트에 도입하는데 있어서 많은 어려움을 느끼고 있다. 왜냐하면 이제는 거꾸로 COM+ 서비스를 마치 전가의 보도인 것처럼, 혹은 만능의 도구로 여기는 관리자나 개발자들을 의외로 많이 접하게 되었기 때문이다. 그러나, 세상 대부분의 이치가 그런 것처럼 모든 것은 제각기 쓰임새가 따로 존재하기 마련이다. 물론, 필자의 이러한 생각에 동의하지 못하시는 분들도 계시리라고 생각되지만 그런분들은 일단 필자를 질책하시기에 앞서 먼저 필자가 왜 이런 얘기를 하는지 본문을 한 번 읽어보시고 의견을 말씀해주시면 언제라도 겸허하게 수용할 수 있도록 노력하겠다.

본문을 계속 진행해 나가기에 앞서, 먼저 필자가 겪었던 몇 가지 경우들을 참고삼아 소개해보도록 하겠다. 굳이 COM+ 서비스를 도입할 필요가 없는 경우임에도 불구하고 도입을 강행하는 가장 대표적인 경우 중 한 가지가 바로 실제로 시스템을 사용하는 사용자가 그다지 많지 않은 경우다. 조그마한 기업체의 홍보 사이트나 일일 방문 인원이 수 백명 정도 되는 전자 상거래 사이트, 또는 개인 홈페이지등이 이 경우에 해당된다. 일반적으로 COM+ 서비스가 그 힘을 발휘하는 경우는 트랜잭션의 관리가 매우 중요시되거나 피크 타임에 동시 접속자수가 평균적인 수준 이상으로 높은 경우다. 물론, 전자 상거래 사이트 같은 경우에는 그 규모에 상관 없이 트랜잭션 처리가 중요시되긴 하지만 트랜잭션 처리는 반드시 COM+ 서비스로만 가능한 것은 아니다. 이런 경우에는 그리 익숙하지도 않을 뿐더러 문제가 발생할 경우 숙련자가 아니면 신속한 처리가 힘든 COM+ 서비스의 자동 트랜잭션 서비스보다는 보다는 직관적이고 신속한 대응이 가능한 SQL 서버 자체에서 제공되는 내부 트랜잭션 관련 기능이나 ADO 또는 ADO.NET에서 제공해주는 트랜잭션 관련 기능들을 이용하는 것이 바람직하다. 정말 COM+ 서비스의 자동 트랜잭션 서비스가 큰 힘을 발휘하는 대표적인 경우는, 복잡한 비지니스 로직으로 얽혀있는 트랜잭션을 관리해야만 하는 경우나 이기종 데이터베이스간의 분산 트랜잭션을 관리해야만 하는 경우다. 이 중 후자의 경우를 예로 들어본다면, SQL 서버에 대한 작업과 오라클에 대한 작업이 동시에 하나의 트랜잭션으로 관리되어야 하는 경우라던가 같은 SQL 서버간이라도 물리적으로 다른 여러 대의 SQL 서버간에 이루어지는 작업이 하나의 큰 트랜잭션으로 관리되어야만 하는 경우가 바로 그것이다. 그러나, COM+ 서비스를 도입하여 보다 완성도 높은 시스템을 구축하기 위한 것이 목적이라면 필자로서도 굳이 COM+의 도입을 반대할 만한 경우는 아니라고 생각한다.

두 번째 경우는 해당 업체나 조직에 유지 보수가 가능한 인력이 없거나 부족한 경우이다. 이 경우에는 절대로 필요 없이 COM+ 서비스를 도입하면 안된다. 기업체의 SI 프로젝트나 SM 관련 업무에서 유지 보수가 어렵거나 불가능하다는 것은 거의 죄악에 가깝다는 것이 필자의 평소 사견이다. 특히나 영세한 규모의 웹 에이전시에서 이런 식으로 COM+ 서비스를 도입해버리면, 담당 개발자 자신은 잠시 개인적인 만족감을 누릴 수는 있겠지만 인수인계를 받은 후임자가 COM+ 서비스에 익숙하지 않을 경우에는 그 후임자뿐만 아니라 해당 업체 자체까지도 엄청난 곤란을 겪는 경우가 발생할 수 있다. COM+ 서비스는 절대로 단 몇 일간의 인수인계나 학습만으로는 관리가 불가능한 기술이다. 실제로 필자는 이런 경우를 직접 겪어본 적이 있다. 당시 필자가 근무하던 업체는 국내 유수의 대기업이었고 필자는 그 업체의 동남아시아 헤드쿼터 법인에 해당하는 싱가포르에서 근무를 하고 있었다. 그리고, 그 하위에는 각 동남아시아 국가별로 한 개나 두 개씩 법인이 존재한다는 식의 구성이었는데, 문제는 그 동남아시아 각국에 위치한 법인들 중에는 숙련된 전산인력이 크게 부족한 법인들이 대부분이었다는 점이다. 심지어는 그 중 가장 상황이 양호하다고 평가할 수 있는 싱가포르 법인에서 조차도 전체 전산 인력 중에서 필자를 제외하고는 COM+ 서비스 컴포넌트는 커녕 비주얼 베이직 스크립트의 클래스문을 작성할 수 있는 능력을 가진 인력조차도 존재하지 않는 상황이었던 것이다. 이런 상황에서 본사로부터 COM+ 서비스를 도입한 하나의 시스템이 개발되었고 일괄적으로 해당 시스템을 설치하여 사용해야만 하게 되었다. 어떤 일이 발생했을지 상상해보기 바란다. 필자와 필자의 싱가포르인 동료 한 명은 전 하위 법인에 해당 시스템을 구축해주고 마이그레이션 작업을 해주는 것만으로 몇 개월을 보냈다. 게다가 각각의 법인별로 발생하기 마련인 수정 사항들중에서 COM+ 서비스와 관련된 작업들은 당연히 필자 혼자서 모두 처리해야만 했다. 만약, 해당 프로그램 파트가 일반적인 ASP 프로그램으로 구성되었다면 필자는 동료의 도움을 받아서 훨씬 수월하게 업무를 처리할 수가 있었을 것이다. 그리고, 결정적으로 필자는 해당 시스템의 두 번째 버전을 구축하기 직전에 개인적인 사정으로 퇴사를 하고 귀국해버렸다. 이제 그 후에 해당 시스템을 혼자서 관리하게 된 필자의 싱가포르 동료의 심정을 잠시 상상해보기 바란다. 비록 COM+ 서비스와 관련된 부분은 그 시스템의 극히 일부분일 뿐이었지만, 일단 문제가 발생하면 무작정 본사의 도움을 기다릴 수 밖에는 없게 되었던 것이다.

그리고, 마지막으로 그 누구라도 동의할 것이라고 생각되는 세 번째 경우는 정말로 어이가 없는 경우인데, 간단하게 말해서 COM+ 서비스로부터 제공되는 어떠한 서비스도 사용되지 않거나 사용하더라도 비효율적으로 사용하고 있는 경우다. 가장 대표적인 사례가 SELECT문 위주의 데이터베이스 조회가 전체 시스템 기능의 거의 대부분을 차지하는데도 불구하고 시스템 전반에 걸쳐서 일괄적으로 자동 트랜잭션 서비스를 사용하고 있는 경우. 이 경우에는 어쩔수 없이 적시 활성화 서비스까지 강제적으로 사용되어야만 하므로 일반적인 트랜잭션 관리 기법을 사용하는 것보다 퍼포먼스가 저하되는 반면 대신 얻어지는 이득이라고 할 만한 것은 전무하다. 게다가 비주얼 베이직 6.0으로 작성된 컴포넌트는 개체 풀링 서비스를 이용할 수 없으므로 퍼포먼스의 저하를 상쇄시킬만한 어떠한 장치도 존재하지 않는 셈이 된다. 그래서, COM+ 서비스를 도입하기로 결정을 내릴 때에는 반드시 타당한 이유가 있어야만 한다. 무조건 COM+ 서비스를 도입한다고 해서 퍼포먼스가 증가한다거나 대단한 이득이 생기는 것이 아니기 때문이며, 조금은 극단적으로까지 표현을 하자면 차라리 그럴 시간에 데이터베이스 쿼리문을 조금이라도 더 최적화하는 것이 퍼포먼스 향상에는 더 많은 도움이 될 것이라는 의견이다.

그럼에도 불구하고 이런 상황은 대부분 일부 개발자들의 욕심으로 인해서 자주 비롯되는데, 새로운 기법을 실무에 도입해 보고 싶다는 욕구와 함께 타 개발자들이 하지 못하는 일을 할 수 있다는 일종의 우월감을 증명하기 위한 것이라고 생각한다. 필자 역시도 이런 욕심을 느끼는 경우가 많고, 실제로도 이런 작업을 한 경우가 몇 번 있다는 점을 솔직하게 고백한다. 그러나, 현명한 개발자라면 이런 욕심은 자제할 수 있어야 하지 않을까 하고 생각해보게 된다. 이런 사례말고도 크고 작은 몇 가지 사례들을 겪으면서 결국 필자가 내리게 된 결론은 이미 얘기했듯이 COM+ 서비스는 절대로 만능의 도구가 아니며 반드시 필요한 곳에만 신중하게 도입해야 한다는 것이다. 그래서, 필자는 이런 개인적인 경험들을 통해서 이해하게 된 몇 가지 논제들을 이제 막 COM+ 서비스에 관심을 갖게 된 개발자분들에게 전달하고자 본문을 마련하게 되었다. 물론, 필자보다도 COM+ 서비스를 더 깊게 이해하고 계신 분들에게는 본문에서 다루고 있는 내용들이 너무나도 당연한 이야기일 수도 있고 아니면 내용 중에 현실과 맞지 않거나 틀린 부분이 존재할 수도 있을 것이다. 그런 부분들은 언제라도 지적해주시면 감사하게 반영을 하도록 하겠다. 본문은 COM+ 서비스에 관심을 갖고 있고 일반적인 COM 컴포넌트를 작성할 수는 있지만 COM+ 서비스에 대해서 그다지 많은 지식이나 경험을 가지고 있지는 않은 분들을 그 대상으로 작성된 것이다.

그리고, 본문의 제목에서도 미루어 짐작할 수 있겠지만 현재 시점에서 필자는 일단 집중적으로 적시 활성화(Just-in-Time Activation) 서비스에 관해서만 논의하려고 한다. 왜냐하면 적시 활성화 서비스는 COM+ 서비스로부터 제공되는 가장 기본적인 서비스이기도 하거니와, 앞으로 다루게 될 다른 모든 COM+ 서비스들을 이해하기 위한 좋은 출발점이 될 수 있기 때문이다. 또한, 적시 활성화 서비스는 COM+ 서비스의 장점과 단점을 보여주기 위한 가장 좋은 논제라고 판단되기 때문인데, 가급적 자세하게 설명하기 위해서 노력했지만 어느 정도는 COM+ 서비스에 관한 기초 지식을 가지고 있어야만 수월하게 본문을 이해할 수 있을 것이다. 그리고, 적시 활성화 서비스를 보다 자세하게 설명하는데 꼭 필요하다는 판단이 들 때만 예외적으로 자동 트랜잭션 서비스와 개체 풀링 서비스에 관해서 일부 논의를 하려고 한다. 그 밖의 서비스들에 관해서는 본문에서 거의 거론하지 않을텐데 그 이유는 현실적으로 지금 거론한 이 세 가지 서비스들이 실제로 프로젝트에서 활용되는 COM+ 서비스들의 거의 70% 이상을 차지한다고 생각하므로 부가적인 이슈들로 인해서 논제를 흐리지 않기 위함이다. 마지막으로 한 가지만 더 전제를 두자면 본문에서는 비주얼 베이직 6.0을 사용해서 제작한 컴포넌트를 기준으로 모든 논의를 진행하려고 한다. 따라서, 실직적으로 개체 풀링 서비스에 관해서는 이론적인 부분만을 다루게 될 것이다. 그리고, 컴포넌트 자체에 관해서도 오직 적시 활성화 서비스만 구현된 컴포넌트를 대상으로 논의를 진행할 계획인데, 이는 적시 활성화 서비스만 구현된 경우, 동시에 적시 활성화 그리고 자동 트랜잭션 서비스가 구현된 경우, 동시에 적시 활성화, 자동 트랜잭션 서비스 그리고 개체 풀링 서비스가 구현된 경우, 그리고 마지막으로 동시에 적시 활성화와 개체 풀링 서비스가 구현된 경우가 각각 고려해야 할 부분들이나 그 효과가 매우 상이하고 또 방대하기 때문이다.

COM_Plus_JIT_Src.zip (17.6k)

그리고, 위의 링크를 통해서 본문에 사용된 ASP 프로그램과 비주얼 베이직 6.0으로 작성된 모든 테스트 코드를 다운로드 받을 수 있으므로 참고하기 바란다. 하지만 본문의 내용을 보다 확실하게 이해하기 위해서는 본인이 직접 코드를 작성해서 테스트해 보는 것이 바람직 할 것이다.

COM 컴포넌트

먼저 비주얼 베이직 6.0으로 간단하게 COM 컴포넌트를 하나 작성해보도록 하자. 지금 작성하고자 하는 컴포넌트는 COM+ 서비스의 기능을 이용하는 컴포넌트가 아니라, 그저 일반적인 COM 컴포넌트라는 점에 유의하기 바란다. 아무튼 이 COM 컴포넌트는 상당히 간단한 기능만을 구현하고 있는데, 다음 코드와 같이 Multiplication() 이라는 그다지 의미없는 작업을 실행하는 메서드 하나와 Class_Initialize() 이벤트 헨들러, 그리고 Class_Terminate() 이벤트 헨들러만 작성하면 된다.

  Option Explicit


  '********************************************************************
  '* Class_Initialize() 이벤트 헨들러
  '********************************************************************
  
  Private Sub Class_Initialize()

      Dim i               As Long

  On Error Resume Next

      For i = 0 To 100
          i = i * i
      Next

  End Sub

  
  '********************************************************************
  '* Class_Terminate() 이벤트 헨들러
  '********************************************************************
  
  Private Sub Class_Terminate()

      Dim i               As Long

  On Error Resume Next

      For i = 0 To 100
          i = i * i
      Next

  End Sub


  '********************************************************************
  '* Multiplication() 메서드
  '********************************************************************

  Public Sub Multiplication(lngNumFirst As Long, lngNumSecond As Long)

      Dim i               As Long

  On Error Resume Next

      For i = 0 To lngNumSecond
          lngNumFirst = lngNumFirst * i
      Next

  End Sub

코드를 살펴보면 대번에 알 수 있겠지만 별다른 의미가 있는 컴포넌트는 아니고, 단지 임의의 작업을 처리하는 것을 나름대로 흉내내고자 하는 의도에서 의미 없는 계산을 실행하고 있을 다름이다. 만약, 비주얼 베이직 6.0을 사용해서 COM 컴포넌트를 작성해본 경험이 많으신 분이라면, 굳이 실제로 이 코드를 사용해서 COM 컴포넌트를 작성하지 않고 눈으로만 본문을 따라와도 전혀 지장이 없을 정도로 간단하다. 필자는 일단 위의 코드를 사용하여 EgoCube.General이라는 COM 컴포넌트를 General.dll이라는 이름의 파일로 작성했다. 그런데, 갑자기 어떤 이유로 인해서 이 COM 컴포넌트를 사용하는 ASP 프로그램을 작성할 일이 생겼고, 루프문으로 Multiplication() 메서드를 여러 차례 호출해야만 하는 상황이 발생했다고 가정해보도록 하자. 이 경우, 대부분 다음과 같은 유형의 ASP 프로그램을 작성하게 될 것이다.

<%

    '****************************************************************
    '*  
    '*  # PROGRAM TITLE : 컴포넌트 퍼포먼스 테스트
    '*  
    '*  # PROGRAM CONT. : 컴포넌트의 메서드를 호출하고 전체 수행 시간
    '*                    을 출력한다.
    '*  
    '*  # FILE NAME     : Normal.asp
    '*  
    '*  # MODIFICATIONS : 
    '*      1. 2004/10/12   송원석  프로그램 처음 작성
    '*  
    '****************************************************************
    
    Option Explicit
    
    With Response
        .AddHeader "Pragma", "No-Cache"
        .Expires = 0
        .CacheControl = "Private"
        .Buffer = True
        .Clear
    End With
    
    
    '****************************************************************
    '* 변수 선언
    '****************************************************************
    
    Dim objGeneral
    Dim TimeOfStart
    Dim TimeOfEnd
    Dim lngLoop
    
    
    '****************************************************************
    '* 컴포넌트 메서드 호출
    '****************************************************************
    
    TimeOfStart = Timer()
    
    Set objGeneral = Server.CreateObject("EgoCube.General")
    For lngLoop = 1 To 2000
        '** 메서드 호출 1.
        objGeneral.Multiplication CLng(lngLoop), CLng(lngLoop)
        '** 메서드 호출 2.
        objGeneral.Multiplication CLng(lngLoop), CLng(lngLoop)
    Next
    Set objGeneral = Nothing
    
    TimeOfEnd = Timer()
    
    
    '****************************************************************
    '* 전체 수행 시간 출력
    '****************************************************************
    
    Response.Write FormatNumber(TimeOfEnd - TimeOfStart, 6)
  
%>

이 프로그램에서는 먼저 컴포넌트의 개체를 생성하고 루프를 2000번 돌면서 루프를 돌 때마다 매번 두 차례에 걸쳐서 Multiplication() 메서드를 호출한다. 그리고, 마지막으로는 Timer() 함수를 사용해서 루프문이 실행되는데 걸린 대략의 시간을 소숫점 여섯째 자리까지 출력한다. 코드 자체에 특이한 부분도 없을 뿐더러 별다른 문제점도 없어보인다. 일단 이 프로그램을 Normal.asp 라는 이름으로 저장하고 다음 코드와 비교를 해 보기로 하자.

<%

    '****************************************************************
    '*  
    '*  # PROGRAM TITLE : 컴포넌트 퍼포먼스 테스트
    '*  
    '*  # PROGRAM CONT. : 컴포넌트의 메서드를 호출하고 전체 수행 시간
    '*                    을 출력한다.
    '*  
    '*  # FILE NAME     : Abnormal.asp
    '*  
    '*  # MODIFICATIONS : 
    '*      1. 2004/10/12   송원석  프로그램 처음 작성
    '*  
    '****************************************************************
    
    Option Explicit
    
    With Response
        .AddHeader "Pragma", "No-Cache"
        .Expires = 0
        .CacheControl = "Private"
        .Buffer = True
        .Clear
    End With
    
    
    '****************************************************************
    '* 변수 선언
    '****************************************************************
    
    Dim objGeneral
    Dim TimeOfStart
    Dim TimeOfEnd
    Dim lngLoop
    
    
    '****************************************************************
    '* 컴포넌트 메서드 호출
    '****************************************************************
    
    TimeOfStart = Timer()
    
    For lngLoop = 1 To 2000
        '** 메서드 호출 1.
        Set objGeneral = Server.CreateObject("EgoCube.General")
        objGeneral.Multiplication CLng(lngLoop), CLng(lngLoop)
        Set objGeneral = Nothing
        '** 메서드 호출 2.
        Set objGeneral = Server.CreateObject("EgoCube.General")
        objGeneral.Multiplication CLng(lngLoop), CLng(lngLoop)
        Set objGeneral = Nothing
    Next
    
    TimeOfEnd = Timer()
    
    
    '****************************************************************
    '* 전체 수행 시간 출력
    '****************************************************************
    
    Response.Write FormatNumber(TimeOfEnd - TimeOfStart, 6)
  
%>

이 프로그램과 앞에서 살펴본 프로그램의 결정적인 차이점은 바로 컴포넌트의 개체를 생성하는 위치인데 아마도 실무에서 이런 식으로 코드를 작성한다면 주변의 동료들이나 관리자로부터 심한 비난을 면치 못할 것이다. 조금이라도 프로그래밍에 대한 지식을 갖고 있는 사람이라면 절대로 이런 식으로는 프로그램을 작성하지 않을 것이라고 믿는다. 그러나, 앞으로 본문에서는 이 코드에 대해서 반복적으로 논의를 하게 되므로 주의 깊게 살펴봐두기 바란다. 필자의 컴퓨터에서 직접 위의 두 ASP 프로그램간의 실행 시간을 비교해본 결과 다음 표와 같이 현저하게 큰 속도 차이가 발생한다는 사실을 확인할 수 있었다. 참고로 이 결과는 펜티엄 4 모바일 CPU 1.60 GHz, 512MB 메모리 환경에서 실행되고 있는 윈도우즈 2003 서버 엔터프라이즈 에디션에서 처리한 것으로서, 표에서 Abnormal.asp 항목으로 나타나는 결과가 비정상적인 두 번째 코드의 결과를 나타낸다.

Normal.asp Abnormal.asp
1 회 0.164063 sec. 0.335938 sec.
2 회 0.156250 sec. 0.359375 sec.
3 회 0.148438 sec. 0.351563 sec.
4 회 0.140625 sec. 0.367188 sec.
5 회 0.148438 sec. 0.359375 sec.
평균 0.151563 sec. 0.354688 sec.

동일한 COM 컴포넌트를 사용하는 프로그램임에도 불구하고 단 몇 줄의 코드 때문에 두 배가 넘는 수행 시간의 차이가 발생하게 되는 것을 확인할 수 있다. 그런데, 지금까지 설명한 사실들은 굳이 필자가 얘기하지 않더라도 이미 여러분도 대부분 알고 있던 내용일 것이다. 더군다나, 본문은 COM+ 서비스의 적시 활성화 서비스에 대하여 논의하는 문서로서 이 테스트 결과에 관한 얘기는 본문의 주제와도 어느 정도 거리가 있어보이는 내용이다. 그런데, 왜 굳이 이런 얘기를 이 시점에 거론하는 것일까? 바로 이 의문에 대한 해답이 본문에서 논의하고자 하는 내용의 핵심이라고도 말할 수 있는데, 그 이유는 적시 활성화 서비스를 정확하게 구현한 COM+ 컴포넌트를 클라이언트 프로그램에서 사용하게 되면 비록 Normal.asp 프로그램에서 살펴본 방식으로 코딩을 한다고 하더라도 결국 내부적으로는 Abnormal.asp 프로그램에서 살펴본 방식으로 동작하기 때문이다. 그리고, 근본적으로는 이것이 바로 적시 활성화 서비스가 제공해주는 본래의 기능이다.

필자가 COM 서비스 관련 서적들을 보면서 가장 답답하게 생각했던 부분이 바로 이런 부분들인데, 대부분의 서적에서는 COM+ 서비스가 적시 활성화 서비스를 제공해주므로 그저 좋다라고만 설명할뿐이지, 어떤 경우에 어떻게 사용해야만 하고 반대로 어떤 경우에는 왜 사용하지 말아야 하는지에 대한 언급은 거의 없다. 그런데, 위의 결과가 말해주듯이 필자의 말대로 COM+ 컴포넌트를 Normal.asp 프로그램에서 살펴본 방식으로 사용한다고 해도, 결국 내부적으로는 Abnormal.asp 프로그램에서 살펴본 방식으로 동작하게 된다면 결국 적시 활성화 서비스는 성능의 향상을 가져오기는 커녕 엄청난 지장만 초래하는 셈이 된다. 따라서, 이 문제는 상당히 중요한 비중으로 다루어져야만 한다는 것이 필자의 개인적인 생각이다. 그래서, 이러한 문제점에도 불구하고 적시 활성화 서비스 자체를 과연 사용해야만 하는지, 그렇다면 어떤 효과를 갖고 있으며 어떤 방식으로 사용하는 것이 보다 적절한 방법인지 등등을 다양한 관점에서 알아보고자 하는 것이 필자가 본문을 작성하는 근본적인 목적이다.

그러면 이번에는 앞에서 작성한 COM 컴포넌트를 구성 요소 서비스에 등록해서 동일한 테스트를 반복해보도록 하자. 물론, 이번에는 적시 활성화 서비스를 이용하도록 설정을 하고 테스트를 실시하려고 하는데, 비록 우리가 작성한 COM 컴포넌트는 적시 활성화 서비스를 고려하여 제작된 것은 아니지만, 몇 가지 설정만 마치면 정상적으로 적시 활성화 서비스를 이용할 수 있으므로 지금부터 필자가 설명하는 과정들을 직접 따라해보기 바란다. 당연한 얘기겠지만 이를 위해서는 먼저 COM+ 응용 프로그램을 만들어야만 하는데 본문에서는 COM+ 응용 프로그램을 만드는 방법에 관해서는 자세하게 설명하지 않을 것이므로 COM+ 응용 프로그램을 만드는 실제 방법에 대해서는 관련 서적이나 문서를 참고하기 바란다. 필자의 경우에는 JIT_Test라는 이름으로 테스트용 COM+ 응용 프로그램을 하나 생성했으며, 그 활성화 유형은 서버 응용 프로그램으로, 응용 프로그램 아이디는 글의 진행상 편의를 위해서 간단하게 Administrator로 설정했다. 본문은 매우 높은 수준의 기술적인 이슈들을 다루고 있는 것은 아니지만 이 정도 난이도의 작업들은 여러분들이 별다른 어려움 없이 바로 처리할 수 있다고 가정하고 작성된 문서임을 감안해주시기 바란다.

JIT_Test 테스트용 COM+ 응용 프로그램

이제 COM+ 응용 프로그램을 생성했으므로 앞에서 작성했던 COM 컴포넌트를 등록하기만 하면 대부분의 작업이 마무리 된다. 그런데, 한 가지 재미있는 사실은 COM+ 응용 프로그램에 COM 컴포넌트를 등록하는 구체적인 방법에는 대략 다섯 가지 정도의 방법이 있는데 그 중에서 어떤 방법을 사용하여 COM 컴포넌트를 등록했는지에 따라서 약간씩 다른 결과가 나타난다는 것이다. 윈도우즈 2003 제품군을 기준으로 살펴본다면 가장 일반적인 방법으로 해당 COM+ 응용 프로그램 노드의 하위에 존재하는 구성 요소 노드를 마우스 오른쪽 버튼으로 누르면 나타나는 팝업 메뉴에서 새로 만들기(N)구성 요소(C) 메뉴를 선택하여 COM+ 구성 요소 설치 마법사를 실행시켜서 COM 컴포넌트를 등록하는 방법이 있다. 이 경우, 두 가지 방법 중에서 한 가지를 선택할 수 있는데 우선 새 구성 요소 설치(|)를 선택하여 아직까지 레지스트리에 등록되지 않은 말 그대로 새로운 COM 컴포넌트를 등록할 수가 있고, 아니면 이미 등록된 구성 요소 가져오기(M)를 선택하여 이미 레지스트리에 등록되어져 있는 COM 컴포넌트를 등록할 수가 있다. 이것이 각각 COM+ 응용 프로그램에 COM 컴포넌트를 등록하는 첫 번째 방법과 두 번째 방법이다. 세 번째 방법은 가장 쉬우면서도 일반적으로 여러분들께서 잘 모르고 계신 방법인데 파일 탐색기에서 구성 요소 노드로 해당 DLL 파일을 드래그 & 드롭하는 방법이다. 이 방법은 등록해야만 하는 COM 컴포넌트들의 갯수가 많고 폴더의 여기저기에 흩어져 있는 경우 매우 유용한 방법이다. 즉, 파일 탐색기의 검색 기능을 이용해서 특정 폴더 하위에 존재하는 DLL 파일들을 모두 검색한 다음 검색된 결과창에서 전체 선택을 하고 드래그 & 드롭을 해버리면 상당히 간단하게 많은 갯수의 COM 컴포넌트들을 단번에 등록하는 것이 가능한 것이다. 네 번째 방법은 내보내기(E)... 메뉴를 이용하여 작성된 MSI 파일을 통해서 COM 컴포넌트들을 설치하는 방법이고, 마지막으로 다섯 번째 방법은 프로그래밍적인 방식을 사용하여 직접 COM+ 카탈로그에 접근하는 방법이다.

일반적으로 그다지 자주 사용된다고는 말할 수 없는 네 번째 방법과 다섯 번째 방법에 대해서는 일단 이 자리에서는 더 이상 생각하지 말고 처음 세 가지 방법에 대해서만 논의해보자. 결론부터 말하자면 필자는 첫 번째 방법과 세 번째 방법, 즉 COM+ 구성 요소 설치 마법사에서 새 구성 요소 설치(|)를 선택하여 레지스트리에 등록되어 있지 않은 새로운 COM 컴포넌트를 등록하는 방법이나, DLL 파일을 마우스로 드래그 & 드롭하는 방법으로 컴포넌트를 등록하는 방법을 권장한다. 심지어는 이미 레지스트리에 등록되어져 있는 COM 컴포넌트라고 할지라도 두 번째 방법 대신, 첫 번째 방법이나 세 번째 방법으로 등록하는 것이 바람직하다. 왜냐하면, 두 번째 방법을 사용하여 COM 컴포넌트를 등록하는 경우, 다음과 같이 컴포넌트의 인터페이스 정보가 제외된 채로 등록되기 때문이다.

인터페이스 정보가 등록되지 않은 COM 컴포넌트

반면, 첫 번째 방법이나 세 번째 방법을 사용해서 COM+ 응용 프로그램에 COM 컴포넌트를 등록하면 다음과 같이 컴포넌트의 인터페이스 정보까지 정확하게 등록이 된다. 각각의 인터페이스나 메서드별로 세밀하게 제어해야 할 필요성이 있는 경우에는 반드시 이렇게 인터페이스 노드 및 메서드 노드에 접근할 수 있어야하므로, 가급적이면 이와 같은 결과를 얻을 수 있는 첫 번째 방법이나 세 번째 방법을 사용하기를 권장하는 것이다.

인터페이스 정보까지 등록된 COM 컴포넌트

필자는 처음에 이런 현상을 발견하고 나서 이 특성이 구성 요소 서비스 스냅인이 가지고 있는 버그의 일종이 아닌가 하고 의심했었다. 그러나 이는 프로그램 디자인 상 의도되어진 동작으로 생각된다. 윈도우즈 2003 제품군의 COM+ 구성 요소 설치 마법사에는 이미 등록된 구성 요소 가져오기(M) 버튼 이름 아래에 다음과 같은 주의 사항이 적혀있다. '경고: 인터페이스 및 메서드 정보는 등록되지 않습니다.' 여담으로 윈도우즈 2000 제품군에는 어디에도 이런 주의 사항이 적혀있지 않았었기 때문에 가끔 개발자들이 혼란을 겪는 경우가 있었다.

정상적으로 적시 활성화 서비스를 이용하기 위해서는 추가적으로 몇 가지 간단한 설정을 더 마쳐야 한다. 그리고, 지금 우리가 작성하여 테스트에 사용하고 있는 EgoCube.General 컴포넌트는 기본적으로 COM+ 서비스를 고려하여 제작된 컴포넌트가 아니라는 점을 다시 한 번 명심하도록 하자. 물론, 지금 적용하고자 하는 방법이 편법이라던가 비정상적인 방법이라는 말은 아니지만 COM+ 서비스를 감안하여 치밀하게 설계된 COM 컴포넌트는 아니라는 점은 일단 염두에는 두고 있는 것이 바람직할 것이다. 이 섹션에서 다루고 있는 설정에 대한 기술적인 논의는 다음 글에서 다시 한 번 자세하게 언급하도록 할 것이다. 그러므로 일단 이 자리에서는 실제로 눈으로 확인할 수 있는 결과들에 대해서만 집중하도록 하자.

당연한 얘기겠지만 가장 먼저 확인해봐야 할 점은 컴포넌트 자체가 적시 활성화 서비스를 사용하도록 설정되어 있는지 여부이다. 구성 요소 서비스 스냅인에서 EgoCube.General 컴포넌트의 등록 정보를 살펴봤을 때 반드시 다음과 같이 활성화 탭의 Just in Time 활성화(J) 항목이 선택되어 있어야 한다. 대부분 컴포넌트를 등록하고 나면 기본적으로 선택되어 있을 텐데, 만약 Just in Time 활성화(J) 항목이 선택되어 있지 않다면 선택을 해주고 확인 버튼이나 적용(A) 버튼을 눌러서 변경 사항을 적용해준다. 참고로 다음 이미지는 윈도우즈 2003 제품군에서 제공되는 컴포넌트 등록 정보 대화 상자이다.

EgoCube.General 등록 정보 - 윈도우즈 2003

만약, 여러분이 윈도우즈 2000 제품군을 사용하고 있다면 컴포넌트 등록 정보 대화 상자의 형태나 항목의 이름 등이 약간씩 차이날 것이다. 그러나, 전체적인 의미 파악에는 전혀 지장이 없으므로 다음 이미지를 참고로 동일하게 설정하도록 한다. 윈도우즈 2003 제품군에서 제공되는 등록 정보 대화 상자쪽이 조금 더 세밀한 조정이 가능하다는 사실을 알 수 있다.

EgoCube.General 등록 정보 - 윈도우즈 2000

컴포넌트 등록 정보 대화 상자를 닫은 다음, 콘솔 트리에서 EgoCube.General 컴포넌트 노드의 하위에 존재하는 인터페이스 노드를 확장해보면 _General 이라는 인터페이스가 하나 등록되어 있는 것을 확인할 수 있을 것이다. 만약, 인터페이스 노드에 어떠한 인터페이스도 존재하지 않는다면 필자가 앞에서 설명한 방법대로 컴포넌트를 등록하지 않은 것이다. 본문을 계속 진행하기 위해서는 반드시 컴포넌트를 재등록하여 인터페이스가 나타나도록 설정해야만 한다. 참고로 이 _General이라는 인터페이스는 비주얼 베이직 6.0에서 내부적으로 자동 생성된 COM 인터페이스로서 비주얼 베이직 6.0을 사용해서 컴포넌트를 작성하는 경우 개발자의 임의대로 변경하거나 설정할 수는 없다. 이 인터페이스 노드를 다시 확장해보면 그 하위에 메서드라는 노드가 있으며 이 노드의 하위에는 해당 컴포넌트의 해당 인터페이스에 존재하는 모든 메서드들이 나타나게 된다. 물론, 지금 테스트하고 있는 EgoCube.General 컴포넌트에는 Multiplication() 메서드 하나만 존재하므로 역시 이 노드에도 Multiplication() 메서드 하나만 나타날 것이다. Multiplication() 메서드의 등록 정보 대화 상자를 열고 다음 이미지와 같이 '이 메서드가 반환하면 자동으로 이 개체 비활성화(A)' 항목을 선택하여 설정하고 확인 버튼이나 적용(A) 버튼을 눌러서 변경 사항을 적용해준다. 참고로 메서드 등록 정보 대화 상자는 윈도우즈 2003 제품군이나 윈도우즈 2000 제품군 모두 외양이나 기능이 그다지 차이나지 않는다.

Multiplication() 메서드 등록 정보

지금까지 설정한 내용들을 다시 한 번 간단하게 정리해보도록 하자. 먼저, 적당한 COM+ 응용 프로그램을 새로 생성하고 컴포넌트를 등록해준다. 그 다음에 해당 컴포넌트가 적시 활성화 서비스를 이용할 수 있도록 설정되어져 있는지 컴포넌트의 등록 정보 대화 상자에서 설정을 확인한다. 그리고, 이 마지막 부분이 전체 과정중에서 가장 중요한 부분인데, 테스트에 사용하고자 하는 메서드의 등록 정보 대화 상자에서 '이 메서드가 반환하면 자동으로 이 개체 비활성화(A)' 항목을 설정해준다. 이 간단한 세 단계의 작업중에서 첫 번째 단계와 두 번째 단계는 별도의 설명이 필요 없을 정도로 당연한 것이다. 그런데 세 번째 단계에 관해서는 약간의 설명이 필요하다. 앞에서도 말했듯이 지금 우리가 테스트하고 있는 EgoCube.General 컴포넌트는 COM+ 서비스를 염두에 두고 만들어진 컴포넌트가 아니다. 즉, 그냥 우리가 주변에서 흔하게 접할 수 있는 일반적인 컴포넌트와 전혀 다를 바가 없는 컴포넌트인 셈이다.

결론적으로 이 컴포넌트는 적시 활성화 서비스를 이용하고자 하는 컴포넌트가 가지고 있어야만 하는 어떤 조건을 충족시키지 못하고 있다고 얘기할 수 있으며, 바로 세 번째 단계의 설정 작업이 그런 부족한 부분들을 보완해주는 역활을 하게 된다. 즉, '이 메서드가 반환하면 자동으로 이 개체 비활성화(A)' 항목이 설정되어 있는 경우, COM+ 서비스는 해당 메서드가 아무런 오류 없이 정상적으로 실행이 종료되면 자동적으로 ObjectContext 개체의 SetComplete() 메서드가 호출된 것으로 간주하고, 반대로 오류가 발생해서 비정상적으로 메서드가 종료되면 SetAbort() 메서드가 호출된 것으로 간주하여 각각 적절한 처리를 하게 되는 것이다. 따라서, 코드에서 명시적으로 SetComplete() 메서드나 SetAbort() 메서드를 호출해줄 필요가 없게 된다. 이 기능이 유용한 경우는 단 하나의 COM 컴포넌트만을 이용해서 COM+ 서비스를 이용하지 않는 환경과 COM+ 서비스에서 실행되는 환경, 양쪽을 오가면서 테스트하거나 사용해야만 하는 경우다. 또는, 컴포넌트 개발 기간 중에도 매우 유용하게 사용될 수 있는데, 즉 코드를 수정하거나 컴파일을 다시 하지 않으면서도 양쪽의 환경을 오가면서 테스트가 가능하므로 비지니스 로직에 조금 더 집중하는 것이 가능하고 디버깅 환경에 있어서도 비교적 자유로울 수가 있는 것이다. 또한, 지금 본문과 같은 경우에도 논제를 흐리지 않고서 논의를 계속 진행하는데 매우 유용하게 이용할 수가 있는 셈이다.

이제 앞에서와 동일한 하드웨어에서, 같은 방법을 사용해서 이 컴포넌트의 성능을 측정해보자. 이 두 번째 테스트에서 유일하게 차이가 나는 부분은 구성 요소 서비스에 EgoCube.General 컴포넌트를 등록한 다음 적시 활성화 서비스를 이용하도록 설정했다는 점 뿐이다. 그리고 테스트를 하기 전에 반드시 다음과 같은 명령어를 실행해서 IIS를 재시작하도록 한다. 이는 IIS 자체의 캐쉬 효과를 초기화시키기 위해서이다.

C:>iisreset /restart

다음 표가 그 테스트의 결과인데, 어처구니 없을 정도로 커다란 차이가 난다는 점을 그다지 어렵지 않게 알아낼 수 있을 것이다. 다시 한번 강조하지만 테스트 방법은 첫 번째 테스트 때와 정확하게 동일하다. 다시 말해서 Normal.asp 프로그램과 Abnormal.asp 프로그램을 반복적으로 실행하여 그 시간을 측정하고 평균값을 얻은 것인데, 전자의 경우에는 대략 23배, 후자의 경우에는 대략 56배의 차이가 발생했다. 필자로서도 테스트 전부터 어느 정도는 이와 비슷한 결과가 나올 것이라고 예상은 했지만 이 결과는 그저 놀라울 다름이다.

Normal.asp Abnormal.asp
1 회 3.562500 sec. 20.046880 sec.
2 회 3.632813 sec. 20.140630 sec.
3 회 3.625000 sec. 20.054690 sec.
4 회 3.593750 sec. 20.093750 sec.
5 회 3.625000 sec. 20.078130 sec.
평균 3.607813 sec. 20.082816 sec.

그러나, 반드시 다음과 같은 점들을 명심하고서 본문을 계속 읽어나가기 바란다. 무엇보다도 다시 한 번 여러분들에게 강조하고자 하는 바는 필자가 지금 이러한 테스트들을 통해서 얻어낸 결론을 바탕으로 이끌어내고 싶어 하는 결론이 COM+ 서비스를 절대 사용하면 안된다고 결정내리고자 하는 것이 아니라는 점이다. 그 반대로 COM+ 서비스를 적극 이용하되 그냥 무턱대고 사용할 것이 아니라 동작 원리를 파악하고 자신이 마주하게 된 상황에 적절하게 사용하자는 것이다. 그리고, 그러기 위해서는 COM+ 서비스의 장점뿐만이 아니라 단점까지 파악하고 있는 것이 더 바람직하기 때문에 이러한 테스트를 진행하고 있는 것이다. 또한, 지금의 테스트 결과에서는 Normal.asp 프로그램의 실행 결과가 23배까지 나타나지만 실제로는 2000번 정도를 루프문으로 반복하여 테스트한 결과이므로 실제로 메서드를 한 차례 호출하여 발생하게 되는 시간적인 차이는 단순한 계산으로도 0.001728125초, 결국 대략 1.7 밀리세컨드에 불과하다는 점이다. 따라서, 같은 논리로 계산을 한다고 생각해본다면 Abnormal.asp 프로그램의 경우도 9.8 밀리세컨드 밖에는 차이가 나지 않는다. 결국 배수로 계산을 하면 대단한 차이로 느껴지지만 일반적인 환경하에서 인간이 인식하기에는 불가능한 범위안에서의 차이인 셈이다. 따라서, 이 정도 수준의 퍼포먼스 감소는 병목 현상의 원인에만 그치는 것이 아니라, 그에 상응되는 어떤 적절한 대가를 얻을 수가 있다는 전제 조건하에서는 무시할 수 있는 수준이라고 말할 수가 있다. 더군다나 그 특성상 적시 활성화 서비스는 병목 현상을 일으키는 원인이 된다기보다는 그 병목 현상을 해소하는 도구로 사용된다는 점을 감안해야 한다.

그리고, 이 테스트에 사용된 컴포넌트의 코드는 사실 필자가 일부러 이런 결과가 극적으로 크게 발생하도록 의도적으로 작성한 코드라는 점을 알아야만 한다. 다름 아닌 컴포넌트의 Class_Initialize() 이벤트 헨들러 그리고 Class_Terminate() 이벤트 헨들러에 작성된 의미없는 루프문과 관련된 전체 코드가 바로 그것인데, 아마 실제로는 이런 패턴으로 작성되는 COM+ 서비스용 컴포넌트란 극히 드물다는 사실을 이미 알고 있을 것이다. 일반적으로 COM+ 서비스용으로 작성된 컴포넌트는 메서드 자체에 코드가 집중되는 경향이 많다. 그럼에도 불구하고 필자는 테스트 결과의 효과를 극대화하기 위해서 이런 코드를 의도적으로 작성한 것이다. 이 부분에 관한 기술적인 내용들은 적시 활성화 서비스에 관해서 계속 논의하면서 다시 한 번 자세하게 다루도록 할 것이다. 아무튼 이제 직접 눈으로 확인했겠지만 COM+ 서비스가 언제나 긍정적인 효과를 가져오는 것만은 아니다. 그렇다면, 이런 결과가 발생하게 되는 근본적인 기술적 원인은 무엇일까? 아니 그 원인에 대해서 생각해보기 이전에 필자가 여러분들에게 얘기했던 것들이 사실이기는 한 것일까? 다시 말해서 적시 활성화 서비스를 이용하도록 제작된 컴포넌트는 Normal.asp 프로그램 같은 방식으로 동작하도록 코드를 작성해도 결과적으로는 Abnormal.asp 프로그램에서 살펴본 방식으로 동작하게 된다는 말이 정말 사실인지 확인해보도록 하자. 서적이나 문서의 의존하지 않고 바로 자신의 눈으로 직접 말이다.

COM+ 컴포넌트

먼저 이번에도 비주얼 베이직 6.0으로 간단한 COM 컴포넌트를 하나 작성해보도록 하자. 그러나, 앞의 경우와는 달리 컴포넌트에 적시 활성화 서비스와 관련된 기본적인 코드를 구현하고 추가적으로 간단하게나마 텍스트 파일 형식으로 로그를 출력할 수 있는 기능을 작성할 것이다. 우선, 다음과 같이 COM 컴포넌트의 가장 기본이 되는 일부 코드들을 구현한다. 기술적으로 특별하게 어려운 부분은 없으므로 코드에 관해서 따로 설명하거나 하지는 않겠다. 다만 프로젝트에 COM+ Service Type Library와 Microsoft Scripting Runtime을 참조시켜야만 한다는 점을 잊지 말기 바란다. 전자는 COM+ 서비스를 구현하는데 필요한 타입 라이브러리고, 후자는 텍스트 파일에 로그를 작성하는 기능을 구현하는데 필요한 타입 라이브러리다.

  Option Explicit


  '********************************************************************
  '* Class_Initialize() 이벤트 헨들러
  '********************************************************************
  
  Private Sub Class_Initialize()
    
  On Error Resume Next

    Call LogWrite("클래스의 Initialize() 이벤트 헨들러 호출.")
    
  End Sub

  
  '********************************************************************
  '* Class_Terminate() 이벤트 헨들러
  '********************************************************************
  
  Private Sub Class_Terminate()
    
  On Error Resume Next

    Call LogWrite("클래스의 Terminate() 이벤트 헨들러 호출.")
    
  End Sub


  '********************************************************************
  '* Multiplication() 메서드
  '********************************************************************

  Public Sub Multiplication(lngNumFirst As Long, lngNumSecond As Long)

  End Sub
  
  
  '********************************************************************
  '* LogWrite() 메서드 : 텍스트 파일에 로그를 기록한다.
  '********************************************************************
  
  Private Sub LogWrite(strLogText As String)

    Dim objFSO          As Scripting.FileSystemObject
    Dim objTS           As Scripting.TextStream
    
  On Error Resume Next

    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objTS = objFSO.OpenTextFile(App.Path & "\Trace.log", ForAppending, True)
    objTS.WriteLine "[" & Now() & "] " & strLogText
    objTS.Close
    Set objTS = Nothing
    Set objFSO = Nothing

  End Sub

코드를 보면 쉽게 알 수 있겠지만, 아직까지 Multiplication() 메서드는 구현되지 않은 상태로 별다르게 주의를 기울여 살펴봐야 될만한 부분은 찾아볼 수 없다. 그리고, LogWrite() 메서드는 그리 효율적일 것처럼 보이지는 않지만 로그를 기록한다는 기본적인 목표에 충실하게 작성되었으며, Class_Initialize() 이벤트 헨들러와 Class_Terminate() 이벤트 헨들러는 이 LogWrite() 메서드를 호출해서 자신이 호출되었다는 로그를 기록하도록 되어 있다. 필자는 이 지극히 기본적인 컴포넌트에 적시 활성화 서비스와 관련된 코드들을 추가하고 적절한 시점마다 LogWrite() 메서드를 호출해서 로그를 기록하도록 구현할 것이다. 그리고, 컴포넌트가 완성되고 나면 구성 요소 서비스에 등록하고 또 다른 ASP 프로그램을 사용해서 인스턴스를 생성한 다음 메서드를 몇 번 호출하여 기록된 로그 파일을 분석하는 방법으로 컴포넌트의 동작 패턴을 분석하고자 한다.

이제 극히 평범한 위의 코드에 적시 활성화 서비스와 관련된 코드들을 하나씩 추가해보도록 하자. 다만, 본문은 어디까지나 논제를 제시하기 위한 문서로 각각의 코드들에 대해서 본격적인 논의는 하지 않는다. 각각의 코드들에 대한 더 자세한 설명은 다음 글에서 살펴볼 것이다. 본문에서는 그저 간단한 설명 정도만으로 만족하기 바란다. 먼저 코드 상단에 다음과 같은 문장을 한 줄 추가한다.

Implements ObjectControl

이 문장은 비주얼 베이직 6.0에게 이 컴포넌트가 적시 활성화 서비스를 이용하기 위한 ObjectControl 인터페이스를 구현하려고 한다는 것을 선언하는 문장이다. ObjectControl 인터페이스에는 구현해야 될 프로시저가 모두 세 개 존재하는데, 물론 이 자리에서 프로시저라는 표현을 사용하고 있는 것은 어디까지나 비주얼 베이직 6.0의 관점에서라는 점을 감안하도록 한다. 아무튼 일단 이처럼 Implements 문을 선언하면 컴포넌트에서는 해당 인터페이스에 존재하는 모든 Public 프로시저들을 구현해줘야만 한다. 따라서, 앞의 코드에 다음과 같은 코드를 추가적으로 작성해준다. 이번에도 역시 각각의 프로시저에서 텍스트 파일에 로그를 기록하도록 구현되었다는 점 외에는 그다지 주의할만한 코드는 존재하지 않는다.

  '********************************************************************
  '* ObjectControl_Activate() 이벤트 헨들러
  '********************************************************************
  
  Private Sub ObjectControl_Activate()

  On Error Resume Next

    Call LogWrite("ObjectControl 인터페이스의 Activate() 이벤트 헨들러 호출.")
    
  End Sub


  '********************************************************************
  '* ObjectControl_Deactivate() 이벤트 헨들러
  '********************************************************************
  
  Private Sub ObjectControl_Deactivate()

  On Error Resume Next

    Call LogWrite("ObjectControl 인터페이스의 Deactivate() 이벤트 헨들러 호출.")
    
  End Sub


  '********************************************************************
  '* ObjectControl_CanBePooled() 이벤트 헨들러
  '********************************************************************
  
  Private Function ObjectControl_CanBePooled() As Boolean

  On Error Resume Next

    Call LogWrite("ObjectControl 인터페이스의 CanBePooled() 이벤트 헨들러 호출.")
    
    ObjectControl_CanBePooled = False

  End Function

이제 컴포넌트의 뼈대가 되는 부분들은 대부분 완성된 셈이다. 그렇다면 이제 직접적으로 무언가 의미있는 작업을 처리하면서 적시 활성화 서비스를 이용하는 비지니스 로직을 담고 있는 메서드를 만들어보자. 물론 말은 이렇게 하지만 본문에서는 그리 의미있는 로직을 담고 있는 메서드를 구현하지는 않는다. 그러나, 지금부터 구현하는 메서드에서 이뤄지는 작업들은 실제로 프로젝트에서 사용될 COM 컴포넌트의 메서드들이 구현해야만 되는 그것과 완벽하게 동일한 것이다. 먼저 다음과 같이 전역 변수로 ObjectContext 개체 변수를 하나 선언해준다.

  Private objObjectContext As ObjectContext

그리고, 이번에는 앞에서 살펴보았던 Multiplication() 메서드를 다음과 같이 구현해준다. 물론, 여러분 중에서 지금까지 단 한 번도 COM+ 서비스에서 동작할 컴포넌트를 작성해본 경험이 없는 분들은 비록 몇 줄 안되는 코드긴 하지만 이 코드의 많은 점들에 대해서 궁금할 것이라고 생각한다. 그러나, 일단 지금은 그 궁금증들을 잠시만 접어두기 바란다. 다만, 지금은 단 한 가지 규칙에 관해서만 머리속에 담아두면 충분하다. 그것은 바로 메서드를 구현한 프로시저에서 오류가 발생하면 ObjectContext 개체의 SetAbort() 메서드를 호출해주고, 메서드가 정상적으로 실행되면 프로시저를 빠져나가기 전에 ObjectContext 개체의 SetComplete() 메서드를 호출해줘야 한다는 사실이다.

  '********************************************************************
  '* Multiplication() 메서드
  '********************************************************************
  
  Public Sub Multiplication(lngNumFirst As Long, lngNumSecond As Long)

  On Error GoTo Error_Handler

    Call LogWrite("클래스의 Multiplication() 메서드 호출.")
    
    Set objObjectContext = GetObjectContext()
    Call objObjectContext.SetComplete
    Set objObjectContext = Nothing
    
    Exit Sub

  Error_Handler:

    If Not objObjectContext Is Nothing Then
        Call objObjectContext.SetAbort
        Set objObjectContext = Nothing
    End If

  End Sub

이렇게해서 직접 작성한 최초의 COM+ 컴포넌트가 완성되었다. 당연한 얘기겠지만 컴포넌트를 테스트해보기 위해서는 먼저 컴포넌트를 구성 요소 서비스에 등록해야만 한다. 앞에서와 동일한 방법으로 COM+ 응용 프로그램을 만들고 컴포넌트를 등록해주는데, 이 경우 한 가지 다른 점은 이번에는 메서드의 등록 정보 대화 상자에서 '이 메서드가 반환하면 자동으로 이 개체 비활성화(A)' 항목을 설정해줄 필요가 없다는 점이다. 왜냐하면, 컴포넌트의 코드 내부에서 필요한 작업들을 모두 처리해주고 있기 때문이다. 그리고, 또 한 가지 재미있는 것은 적시 활성화 서비스를 이용하기 위하여 구현한 ObjectControl 인터페이스 역시 구성 요소 서비스의 인터페이스 노드 하위에 노출된다는 점이다. 다음 이미지는 그 실제 결과를 보여주고 있다.

Multiplication() 메서드 등록 정보

이제 컴포넌트를 테스트하기 위해서 다음과 같은 ASP 프로그램을 하나 작성하도록 하자. 역시 코드를 살펴보면 기술적으로 특별한 부분은 별다르게 존재하지 않는다. 단, 빨간색으로 강조한 라인들을 주의해서 살펴보기 바란다. 즉, 어떤 방식으로 개체 인스턴스를 생성하고 메서드를 호출하며, 그리고 다시 제거하는지를 주의 깊게 살펴보면 된다. 이는 여러분들이 예상하는 결과와 실제 테스트 결과가 어떻게 다르게 나타나는지를 파악하기 위한 것으로 코드 그 자체의 패턴은 평소에 늘 접하던 방식과 동일한 것이다.

<%
    
    '****************************************************************
    '*  
    '*  # PROGRAM TITLE : COM+ 컴포넌트 추적 로그 생성
    '*  
    '*  # PROGRAM CONT. : 컴포넌트의 메서드를 호출하고 추적 로그를 생
    '*                    성한다.
    '*  
    '*  # FILE NAME     : Trace.asp
    '*  
    '*  # MODIFICATIONS : 
    '*      1. 2004/12/06   송원석  프로그램 처음 작성
    '*  
    '****************************************************************
    
    Option Explicit
    
    With Response
        .AddHeader "Pragma", "No-Cache"
        .Expires = 0
        .CacheControl = "Private"
        .Buffer = True
        .Clear
    End With
    
    
    '****************************************************************
    '* 변수 선언
    '****************************************************************
    
    Dim objJustInTime
    
    
    '****************************************************************
    '* 컴포넌트 메서드 호출
    '****************************************************************
    
    Set objJustInTime = Server.CreateObject("EgoCube.JustInTime")
    
    '** 메서드를 두 번 호출
    objJustInTime.Multiplication 1, 1
    objJustInTime.Multiplication 1, 1
    
    Set objJustInTime = Nothing
    
    
    '****************************************************************
    '* 전체 수행 시간 출력
    '****************************************************************
    
    Response.Write "추적 로그 생성 완료"
    
%>

이 테스트 프로그램이 성공적으로 실행되면 컴포넌트 DLL 파일이 위치한 폴더에는 일반적인 텍스트 파일 형식으로 Trace.log라는 이름의 로그 파일이 생성된다. 그런데, 지금 테스트 프로그램을 실행시켜서 로그 파일을 생성하기에 앞서 잠시 그 결과를 미리 예상해보는 시간을 가져보도록 하자. 과연 어떤 결과가 나타나게 될까? 만약, 테스트에 사용된 컴포넌트가 COM+ 서비스의 적시 활성화 서비스를 사용하는 컴포넌트가 아닌 일반적인 COM 컴포넌트라면 그 결과는 매우 쉽게 예상될 수 있을텐데 아마도 다음과 같은 결과가 나타날 것이다. 참고로 이 결과는 실제로 테스트를 한 결과가 아니라, 단지 필자가 예상한 결과이며 살펴보기 편리하도록 로그 출력 시간 부분을 생략하고 임의로 번호를 설정한 것이다.

  1. 클래스의 Initialize() 이벤트 헨들러 호출.
  2. 클래스의 Multiplication() 메서드 호출.
  3. 클래스의 Multiplication() 메서드 호출.
  4. 클래스의 Terminate() 이벤트 헨들러 호출.

이런 결과는 어떤 면에서는 당연하다라고까지 말할 수 있을 것이다. 그러나, 지금처럼 테스트 대상 컴포넌트가 COM+ 서비스의 적시 활성화 서비스를 이용하는 COM 컴포넌트라면 전혀 예상 밖의 로그 내용이 작성되어진다. 아마 처음 접하시는 분들에게는 상당히 놀랍기까지한 결과일 것이다. 다음이 바로 테스트 프로그램이 생성해내는 로그 파일의 내용인데 일단 혼란을 줄이기 위해서 ObjectControl 인터페이스와 관련된 로그들은 희미한 색상으로 처리했고, 이번에도 역시 로그 출력 시간 부분은 생략하고 필자의 편의대로 번호를 설정했다.

  1. 클래스의 Initialize() 이벤트 헨들러 호출.
  2. ObjectControl 인터페이스의 Activate() 이벤트 헨들러 호출.
  3. 클래스의 Multiplication() 메서드 호출.
  4. ObjectControl 인터페이스의 Deactivate() 이벤트 헨들러 호출.
  5. 클래스의 Terminate() 이벤트 헨들러 호출.
  6. 클래스의 Initialize() 이벤트 헨들러 호출.
  7. ObjectControl 인터페이스의 Activate() 이벤트 헨들러 호출.
  8. 클래스의 Multiplication() 메서드 호출.
  9. ObjectControl 인터페이스의 Deactivate() 이벤트 헨들러 호출.
  10. 클래스의 Terminate() 이벤트 헨들러 호출.

분명히 테스트 ASP 프로그램을 작성하면서 컴포넌트의 인스턴스를 단 한 번만 생성했으며, 메서드를 연달아 두 번 호출한 다음 마지막으로 컴포넌트의 개체 인스턴스를 해제했다. 따라서, Initialize() 이벤트 헨들러와 Terminate() 이벤트 헨들러의 로그는 전체 로그에서 가장 첫 부분과 마지막 부분에서 각각 한 번씩 나타나야만 한다. 그러나, 테스트 로그의 결과는 컴포넌트가 실제로는 이런 예상과는 다르게 동작하고 있음을 보여주고 있다. 어처구니 없게도 첫 번째 메서드 호출이 리턴되자마자 Terminate() 이벤트 헨들러가 호출됐는데, 이 결과가 의미하는 바는 실제로 컴포넌트의 개체 인스턴스가 해제됐다는 뜻이다. 그리고, 두 번째 메서드 호출이 일어나기 직전에 다시 Initialize() 이벤트 헨들러가 호출되는데 이는 컴포넌트의 개체 인스턴스가 새롭게 생성됐다는 뜻이다. 결국, 첫 번째 메서드가 호출되는 시점의 컴포넌트 개체 인스턴스와 두 번째 메서드가 호출되는 시점의 컴포넌트 개체 인스턴스는 동일한 인스턴스가 아니라는 결론이 나온다.

만약, 메서드를 두 번만 호출한 것이 아니라면 어떤 결과가 나올까? 또는 컴포넌트에 여러 개의 메서드가 존재하고 필요에 따라서 무작위로 호출이 되는 상황이라면 또 어떤 결과가 나오게 될까? 그 답은 항상 하나의 메서드가 호출되고 난 뒤에는 위의 결과와 같은 과정이 반복된다는 것이다. 물론 개발자의 의도에 따라 이런 동작을 의도적으로 제어할 수 있는 방법도 제공이 되기는 하지만 이 자리에서는 잠시 접어두기로 한다. 아무튼 앞에서 필자가 얘기했던 '비록 Normal.asp 프로그램에서 살펴본 방식으로 코딩을 한다고 하더라도 결국 내부적으로는 Abnormal.asp 프로그램에서 살펴본 방식으로 동작하기 때문'이라는 말의 진위 여부를 여러분들의 눈으로 직접 확인한 셈이다. 그리고, 이런 동작 패턴 자체가 바로 '적시 활성화 서비스'의 본질인 것이다. 또한, 바로 그렇기 때문에 COM+ 서비스 컴포넌트는 상태가 유지되지 않는다는 이제 거의 관용어구가 되어버린 결론이 자연스럽게 얻어지게 되고 전역 변수로 대표되는 컴포넌트의 상태라는 개념이 무의미하게 변해버리는 것이다.

개인적으로 필자는 COM+ 서비스에 관해서 혼자 공부를 시작하면서 '적시 활성화'라는 용어의 '적시'라는 단어가 의미하는 바가 정확하게 무엇인지 이해하지 못해서 무척이나 고민을 했었다. 물론, 단어 자체만 놓고 보자면 적절한 시점을 의미하는 '적시'라는 정도는 알 수가 있다. 즉, 용어만 단순하게 풀이하자면 적절한 시점에 COM+ 서비스가 자동적으로 개체를 활성화 또는 비활성화 시켜준다는 뜻이 되겠지만, 필자가 고민했던 근본적인 부분은 왜 메서드가 호출되고 난 직후의 시점이 개체가 비활성화되는 '적시'라고 생각되는 것인지, 그리고 왜 메서드가 호출되기 직전의 시점이 개체가 활성화되는 '적시'라고 생각되는 것인지 바로 그런 부분들이었던 것이다. 또한, 이런 논리의 배경에 깔려있는 기술적인 사실들을 이해하고 난 뒤에도 그런 작업 자체는 또 어떤 의미를 지니는지에 대한 설명을 찾을 수가 없었다. 필자가 본문을 통해서 논의하고 싶어하는 부분이 바로 이런 부분들이다.

그리고, 결론적으로 이런 로그의 결과는 본문의 앞 부분에서 우리가 실시했던 테스트 결과에서 왜 컴포넌트를 일반적인 상태에서 실행했을 때보다 COM+ 서비스에 등록시킨 상태에서 실행했을 때가 더 극적으로 느린지에 대한 한 가지 이유를 설명해준다. 메서드를 한 번 호출할 때마다 각각 컴포넌트 개체의 인스턴스의 생성과 해제를 반복하므로 이는 지극히 당연한 결과였던 것이다. 물론, 적시 활성화 서비스 외에도 컴포넌트의 퍼포먼스에 영향을 미치는 요인들은 몇 가지가 더 있겠지만 적시 활성화 서비스로부터 받는 영향은 지대한 것이다. 그리고, 필자가 EgoCube.General 컴포넌트의 Initialize() 이벤트 헨들러와 Terminate() 이벤트 헨들러의 코드에 의도적으로 무의미한 루프문을 작성했던 것이 컴포넌트의 퍼포먼스에 어떻게 부정적인 영향을 미쳤는지도 비교적 명확해진다. 그렇다면 이런 테스트 결과들을 종합해서 그 결과를 고려해보도록 하자.

필자가 본문에서 중점적으로 논의하고자 했던 주제 중 하나가 무분별한 COM+ 컴포넌트의 사용이 시스템에 미치는 부정적인 영향에 관한 것이었다. 이 부분에 대해서는 지금까지의 테스트 결과가 그 이유를 충분히 설명해주고 있다고 생각하므로 더 이상 그 이유에 대해서는 거론하지 않을 것이다. 특히 이러한 문제는 비주얼 베이직 6.0으로 작성된 COM+ 컴포넌트를 그 고려의 대상으로 하는 경우에 더욱더 중요한 문제가 되는데, 왜냐하면 적시 활성화 서비스의 이와 같은 단점을 보완해 줄 수 있는 개체 풀링 서비스의 구현이 불가능하기 때문이다. 그런데 여기서 주의해야 할 점은 그렇다고 해서 개체 풀링 서비스가 모든 문제를 해결해주는 것도 아니라는 점이다. 나중에 기회가 되면 다시 설명하도록 하겠지만 개체 풀링 서비스를 사용할 때도 나름대로 주의 깊게 감안해야만 하는 부분들이 당연히 존재한다.

적시 활성화 서비스와 시스템 리소스 점유 관리

그렇다면 이렇게 작성도 쉽지 않고, 그렇다고 별다른 장점도 없는것 같아만 보이는 적시 활성화 서비스를 반드시 이용해야만 하는 것일까? 아니 조금 말을 다르게 바꿔서 극단적으로 얘기해 본다면 COM+ 서비스를 이용해야만 하는 이유가 무엇일까? 게다가 배우기도 쉽지 않을 뿐더러 유지보수는 더욱 까다로워 보이는데 말이다. 마이크로소프트사의 개발자들이 필자나 여러분들보다 무지한 것은 분명히 아닐텐데 무엇 때문에 이런 기술을 개발한 것일까? 무엇인가 장점이 있기는 한 것일까? 이 질문에 대한 필자의 답은 '분명히 이용하기 쉽지만은 않은 기술이지만 그래도 배울만한 가치가 있다.'라는 것이다. 과연 그런 것인지 이제 다시 논점을 적시 활성화 서비스에 집중해보도록 하자.

결론적으로 말해서 적시 활성화 서비스가 개발자들에게 제공해주는 이점은 크게 두 가지 정도로 정리가 가능하다. 첫 째, 적시 활성화 서비스는 트랜잭션의 격리성과 일관성 보장이라는 중요한 목적을 달성하기 위해 제공되는 COM+ 자동 트랜잭션 서비스 메커니즘의 핵심 기법 가운데 하나다. 사실 이 문장은 COM+ 서비스와 관련된 서적을 한 권 이상 정독해서 읽어보신 분들이라면 거의 외우다시피 하는 문장일 것이다. 비록 이 주제가 적시 활성화 서비스가 제공되는 가장 큰 이유기는 하지만 일단 본문에서는 이 부분에 관해서 언급하지 않을 것이다. 서두에서 이미 선언한 바와 같이 본문은 순수하게 적시 활성화 서비스만을 다룰 예정이며 필자의 계획대로라면 앞으로도 최소한 두 번 정도는 적시 활성화 서비스에 관해서 논의하고 난 후에야 비로소 적시 활성화 서비스에 관한 얘기들을 어느 정도 마무리 할 수 있을 것으로 생각된다. 이 주제에 관해서는 나중에 별도의 글에서 자동 트랜잭션 서비스에 대해 논의하면서 같이 집중적으로 다루도록 하겠다.

그리고 둘 째, 해당 컴포넌트를 사용하는 클라이언트 응용 프로그램, 그것이 ASP 프로그램이든 아니면 윈도우즈 응용 프로그램든 관계 없이 프로그램의 성능을 향상시킬 수 있다. 그런데, 이 얘기가 사실이라면 지금까지 우리들이 테스트를 통해서 얻어낸 결과와는 뭔가 이치적으로 앞뒤가 맞지 않는다. 테스트 결과는 오히려 적시 활성화 서비스가 프로그램의 속도를 저하시킨다는 사실을 말해주고 있다. 그렇다면 필자는 지금 시점에서 무슨 말을 하고 싶은 것일까? 여기에서 우리가 주의를 기울여야 할 부분은 '성능 향상'이라는 단어가 의미하는 바를 정확하게 이해해야만 한다는 점이다. 일반적으로 '성능 향상'이라고 지칭을 하면 대부분 떠올리는 것이 퍼포먼스, 즉 프로그램 실행 속도의 향상이다. 그러나, 다른 관점에서 본다면 '성능 향상'이라는 단어는 가용성을 의미하기도 한다. 제한된 서버 리소스만을 사용해서 동시에 최대한의 서비스를 클라이언트에게 제공해주는 것이 바로 그것이다. 그리고, 그 대가로 어느 정도의 퍼포먼스 감소가 동반되는데 이는 주어진 환경에서 물리적인 리소스의 확장없이 가용성이라는 이득을 얻기 위해서 지불해야만 하는 비용 정도로 받아들일 수 있을 것이다. 게다가 재미있는 것은 대개의 경우 가용성이 증가되면 대단위 규모의 서비스를 제공하는 경우, 특정 조건이 만족된다는 전제하에서 결과적으로 퍼포먼스의 향상까지도 기대가 가능하다는 점이다. 따라서, 결과적으로 우리 개발자들이 해야할 일들 중의 하나는 바로 이 가용성 증가와 퍼포먼스 감소 사이의 상관 관계를 면밀하게 따져서 적시 활성화 서비스의 도입 여부를 결정하는 것이다.

일반적으로 엔터프라이즈 환경이라고 불리는 큰 기업체나 대규모의 서비스가 이루어지는 인터넷 관련 업체에서 가용성의 문제는 예상보다도 더 큰 의미를 지닐 수 밖에 없다. 아무리 다중 프로세서와 고용량의 메모리를 장비한 고가의 머신을 도입했다고 하더라도 일단 프로그램 구현상의 문제등으로 인한 병목 현상이 발생하게 되면 프로세서는 거의 놀고 있는데 사용자들은 서비스를 받지 못해서 아우성치는 사태가 발생하게 된다. 적시 활성화 서비스는 바로 이런 유형의 문제점들을 해결하기 위한 하나의 실마리가 될 수 있다. 대부분 가장 민감한 리소스들 중의 하나로 여겨지는 것이 바로 데이터베이스 커넥션인데 이해를 돕기 위해서 다음과 같은 경우를 한 번 가정해보겠다.

어떤 가상의 기업체에서 임의의 시스템을 구축하는 프로젝트가 진행중이며, 어떤 이유로 인해서 데이터베이스에서 허용할 수 있는 동시 접속자의 수가 단지 10명 뿐이라고 생각해보자. 그런데, 만약 프로젝트가 끝나고 난 뒤에 시스템을 사용하게 될 사용자들의 전체 인원이 고작 한 두 명뿐이라면, 즉 10명 이하라면 자동 트랜잭션 서비스를 필요로 하는 상황이 아닌 이상 적시 활성화 서비스를 도입할 필요는 전혀 없다. 그럼에도 불구하고 적시 활성화 서비스를 도입하는 경우가 있다면, 필자는 단호하게 그것을 개발자들의 유희이거나 시간 낭비일 뿐이라고 단정지을 것이다. 아무튼 이런 상황에서는 비주얼 베이직 6.0으로 윈도우즈 응용 프로그램을 작성하는 경우 극단적으로 프로그램의 시작 부분에서 데이터베이스 커넥션을 열고, 프로그램이 종료될 때 데이터베이스 커넥션을 닫는다고 하더라도 전혀 문제가 되지 않는다. 오히려 그렇게 프로그램을 작성하는 것이 아주 약간의 차이이긴 하겠지만 퍼포먼스는 더 높을 것이다. 이런 경우에서 적시 활성화 서비스의 도입은 퍼포먼스의 저하만 초래할 다름으로 그 대가로 얻게 되는 이득이란 거의 전무하다고 말해도 과언이 아니다. 그리고, 사용자가 조금 더 늘어나서 이를테면 정확하게 10명의 사용자가 존재하는 경우에도, 대게 이런 경우가 발생할 확률은 현실 세계에선 거의 없긴 하지만, 약간 꺼림직한 기분이 들기는 하겠지만 역시 기존의 상황과 비슷한 상태가 유지될 것이다.

그런데 사용자가 10명을 넘어서기 시작하면 문제가 조금씩 복잡해지기 시작한다. 그나마 사용자가 11명이나 12명 정도인 경우라면 일정한 수준까지는 큰 무리 없이도 사용을 계속할 수도 있을 것이다. 왜냐하면 전체 사용자의 수가 곧 동시 사용자는 아니기 때문인데, 물론 11번째로 시스템에 접근하는 사용자는 프로그램 장애를 겪게 되겠지만 그다지 높은 빈도로 발생하는 일이 아닐터이므로 너그러운 사용자들을 만나기만 한다면 그럭저럭 넘어갈 수도 있을지 모른다. 그러나, 사용자의 수가 그 이상이 되어버리면 결국에는 프로그램 개발자나 시스템 관리자들이 결단을 내려야만 하는 시기가 오고야 만다. 즉, 라이센스를 추가로 구입해서 데이터베이스가 허용할 수 있는 동시 접속자의 수를 근본적으로 늘린다던가 프로그램의 구현 방법을 변경해야만 하는데, 대부분 이런 상황에서 개발자들이 취할 수 있는 가장 일반적인 방법은 바로 유명한 '최대한 늦게 데이터베이스 커넥션을 얻고 최대한 빨리 데이터베이스 커넥션을 닫는다.'라는 프로그램 작성법이 아닐까 한다. 이 방법을 사용하면 각각의 비지니스 로직이 실행되기 직전에 데이터베이스 커넥션을 얻고 작업이 끝나면 최대한 빨리 데이터베이스 커넥션을 닫게 되므로 일정 수준까지는 동시 접속자 수에 추가적인 여유가 생기게 된다. 즉, 시스템에 동시에 접속하고 있는 사용자들의 수는 10명을 넘어서더라도 그 사용자들이 동시에 데이터베이스에 연결하고 있을 확률이 현저하게 낮아지므로 10명의 동시 접속자라는 제한에도 불구하고 실제로는 윌등하게 많은 수의 시스템 동시 접속자를 허용할 수 있게 된다. 물론, 이런 방법을 사용하더라도 언젠가는 한계에 부딛히게 될 것이고 결국에는 어쩔수 없이 라이센스를 추가로 구입하거나 클러스터링을 구성하는 등 보다 근본적인 대안이 요구되겠지만 제한된 리소스만으로 최대한의 효과를 얻는다는 목표, 즉 가용성을 높인다는 근본적인 취지는 매우 훌륭하게 달성하는 셈이다. 이 사례는 적시 활성화 서비스의 기본적인 개념을 설명하기 위한 아주 좋은 예가 된다.

먼저, 이 사례에서 우리는 적시 활성화 서비스의 '적시'라는 단어에 대한 훌륭한 설명을 찾아낼 수 있다. 언제 데이터베이스의 커넥션을 얻어야만 할까? 바로 '최대한 늦게', 즉 최대한 늦은 시점이 바로 특정 리소스를 얻기 위한 '적시'이다. 언제 데이터베이스의 커넥션을 닫아야만 할까? 바로 '최대한 빨리', 즉 최대한 빠른 시점이 바로 특정 리소스에 대한 점유를 해제하기 위한 '적시'이다. 그렇다면 왜? 그것은 바로 리소스를 사용하기 위해서 대기하고 있는 다른 프로그램들이 그 특정 리소스를 얻을 수 있도록 해당 리소스에 대한 점유를 풀어주기 위해서다. 비록 이 사례에서는 데이터베이스 커넥션만을 예로 들었지만 메모리나 그 밖의 각종 리소스들에 대한 모든 대상에 같은 룰이 적용될 수 있다. 이는 마치 몇 개 밖에 되지 않는 컵을 갖고서 중대나 대대급의 인원이 효율적으로 갈증을 해소해야만 하는 상황과도 비슷한데, 누군가가 하나의 컵을 혼자 독차지하고서 차를 음미한다거나 한다면, 또는 먼저 컵을 손에 넣은 사람들이 자신의 갈증을 다 해소할 때까지 컵을 독점한다면 다른 사람들은 갈증에 괴로워할 수 밖에 없다. 일단 자신의 목을 축이고 어느 정도 갈증이 해소되었다면 재빨리 컵을 다음 사람에게 넘겨야한다. 운이 좋다면 빠른 시간안에 자신에게 다시 컵이 되돌아오는 기쁨을 누릴 수도 있을 것이다. 그리고, 최소한 지도자나 매우 중요한 업무를 담당하는 사람 정도는 되야만 자신만의 컵을 가지고서 여유를 부릴 수 있을텐데 프로그램적인 관점에서는 서비스 프로세스나 민감한 작업을 담당하는 프로그램 등을 이 범주에 적용시킬 수 있을 것이다. 이런 방법은 분명히 한 사람, 한 사람 개개인의 입장에서는 매우 답답한 방법일런지도 모른다. 그러나, 가장 마지막으로 컵을 갖게 될지도 모를 어떤 불운한 사람의 입장에서는, 그리고 그 사람이 누가 될지 아무도 예상할 수 없는 상황에서는 꽤나 효과적인 방법이라고 말할 수 있을 것이다. 즉, 리소스를 움켜쥐고 있지 않는 것 그 자체가 엔터프라이즈급의 환경에서는 대단한 미덕이 되는 것이다.

적시 활성화 서비스는 바로 이런 기법을 제공해주기 위한 기반 기술이다. 물론 적시 활성화 서비스를 사용하지 않더라도, 또는 COM+ 서비스 전체를 사용하지 않더라도 동일한 목적을 달성하기 위해 나름대로 프로그램을 최적화 할 수는 있을 것이다. 그러나, 대부분 그런 경우에는 프로젝트의 전체 구성원들이 작성한 결과물들 사이의 편차가 매우 크고, 그 세부적인 구현 방법이 통일되기 어려우며, 작성된 코드의 품질이 일관되기가 힘들다. 그러나, 적시 활성화 서비스를 이용하면 그 구현 방법이 매우 단순해진다. 설령 해당 코드를 제작하는 개발자가 실질적인 목적이나 환경에 대해서 이해하지 못하고 있다고 할지라도 그저 적시 활성화 서비스의 룰만 지키면서 코딩을 해주면 최종적으로는 가용성을 높인다는 목적을 달성하게 된다. 게다가 그 룰이라는 것도 매우 간단한데, 여러분들이 본문에서 직접 눈으로 확인한 내용들이다. 테스트를 위해서 만들었던 컴포넌트에서 언급한 몇 가지 조건, 그것이 적시 활성화 서비스를 이용하기 위한 기본적인 필수조건의 전부인 것이다. 즉, ObjectControl 인터페이스를 구현해주고 SetAbort() 메서드나 SetComplete() 메서드를 적절히 호출해주기만 하면 된다. 더군다나 클라이언트측 프로그램의 코드는 전혀 신경쓸 필요가 없다.

그러나, 적시 활성화 서비스가 자신의 목적을 달성하기 위한 방법으로는 너무 부담스럽다고 판단되거나 개발자가 선호하는 다른 기반 기술이 존재한다면, 또는 마이크로소프트의 COM 컴포넌트 기반 기술에 익숙하지 않다면 당연히 본인이 원하는 다른 방법을 선택할 수도 있을 것이다. 그 부분에 대한 결정은 필연적인 개발자들의 몫이자 의무이기도 하다. 그러나, 원하기만 한다면 COM+ 서비스에서 제공해주는 이미 존재하는 적시 활성화라는 서비스를 이용함으로서 간단하게 문제를 해결할 수가 있는 것이다. COM+ 서비스를 일종의 프레임워크라는 관점에서 바라본다면, 존재하지 않거나 굳이 사용하지 않아도 다른 방법으로도 충분히 목적을 달성할 수는 있지만 제공되는 기반 구조를 활용하는 경우 보다 빠르고 편리하게 목적을 달성할 수 있는 방법을 제공해주는, 단어의 의미 그대로인 하나의 기반 구조라고 볼 수 있는 것이다.

게다가 적시 활성화 서비스는 COM 컴포넌트를 그 구현 기반으로 하고 있다는 점에서 또 하나의 긍적적인 특징을 갖게 된다. 시스템이 프리젠테이션 계층과 비지니스 로직 계층, 그리고 데이터 계층으로 구분되어지는 분산 시스템인 경우를 생각해보자. 엔터프라이즈 환경에서 이 각각의 계층들은 물리적으로 분리된 장소에 위치해 있을 가능성이 매우 높은 편이다. 예를 들어서, 비주얼 베이직 6.0으로 작성된 윈도우즈 응용 프로그램(프리젠테이션 계층)에서 원격 서버에 위치한 COM+ 서비스(비지니스 로직 계층)에 구성된 컴포넌트의 인스턴스를 생성하고, 해당 비지니스 로직 컴포넌트가 역시 물리적으로 다른 위치에 존재하는 SQL 서버(데이터 계층)에 접근해서 실제의 데이터를 처리하는 경우가 비로 그것이다. 이런 환경에서는 비지니스 로직 컴포넌트를 일종의 DCOM 컴포넌트로 작성하는 수 밖에 없다. 만약, 그 대상이 ASP나 ASP.NET 기반의 웹 시스템이라고 할지라도 역시 조건은 같을 수 밖에 없으며 유일하게 예외가 되는 경우는 웹 서비스가 이뤄지는 모든 물리적인 웹 서버에 동일한 비지니스 로직 컴포넌트가 전부 중복되어 설치되는 경우나 웹 서비스와 COM+ 서비스가 물리적으로 동일한 서버에서 실행되는 경우뿐이다. 직접 DCOM 컴포넌트를 구현해보았거나 관련 서적을 읽어보신 분들은 아시겠지만 그와 같은 작업은 절대로 만만한 작업이 아니다. 그런데 흥미롭게도, 정확하게 동일한 DLL 형태의 컴포넌트임에도 불구하고 해당 컴포넌트를 COM+ 서비스에 등록해서 약간의 부가적인 설정을 해주면 마치 애초부터 DCOM 컴포넌트로 제작된 것처럼 원격 인스턴스를 생성하는 것이 가능해진다. 게다가 그 방법도 어처구니 없을 정도로 간단한데 그 자세한 방법에 관해서는 나중에 따로 논의를 하도록 하겠다. 아마도 무척 재미있을 것이라고 자신있게 장담한다.

다른 부분에서도 적시 활성화 서비스의 진정한 가치는 여지없이 발휘된다. 프리젠테이션 계층에서 비지니스 로직 계층에 위치한 컴포넌트의 원격 인스턴스를 생성하는 경우를 생각해보자. 즉, 비주얼 베이직 6.0으로 작성한 프로그램에서 원격지 서버의 COM+ 서비스에 구성된 컴포넌트의 인스턴스를 생성하는 경우다. 이 경우 원격지 서버에서 컴포넌트의 인스턴스를 생성함에 있어서 가장 비용이 많이 요구되는 작업은 무엇일까? 먼저, 그 과정을 차례차례 살펴보면 비주얼 베이직 6.0으로 작성된 프로그램으로부터 해당 컴포넌트의 프록시가 활성화되고 RPC 채널이 생성되어 원격지 서버와의 연결이 이루어진다. 그리고, 비지니스 로직 계층이 구현된 원격지 서버에서는 해당 컴포넌트의 스텁이 생성되고 마지막으로 컴포넌트의 실제 인스턴스가 생성된다. 일단 현재 시점에서는 컨텍스트라든가 COM+ 서비스에 너무 깊게 연관된 부분들에 관해서는 언급하지 않도록 하겠다. 아무튼 이 과정을 간단하게 정리를 해보자면 비주얼 베이직 6.0 프로그램 → 컴포넌트 프록시 → RPC 채널 → 컴포넌트 스텁 → 컴포넌트 인스턴스의 순서가 된다. 이 각각의 단계들 중에서 비용이 가장 많이 요구되는 작업은 바로 RPC 채널을 생성하는 단계다. 데이터베이스와의 작업에서 커넥션을 얻는 단계가 가장 고비용의 작업이라는 점을 머리 속에 떠올려본다면 쉽게 이해가 가능할 것이다. 그리고, 일반적으로 개발자들이 커넥션 풀링 기법을 이용하여 데이터베이스 관련 작업에서의 퍼포먼스 증가를 얻는 것처럼 적시 활성화 서비스를 이용하면, 그 세부적인 방법에 조금 차이가 존재하기는 하지만 RPC 채널과 관련하여 커넥션 풀링이 데이터베이스 커넥션에 관해서 주는 결과와 비슷한 효과를 얻을 수 있다.

일반적인 범주에서 적시 활성화 서비스를 사용하지 않는 경우 해당 윈격 컴포넌트가 점유하고 있는 원격지 서버의 리소스를 해제하기 위한 방법은 오로지 컴포넌트 인스턴스의 완벽한 해제뿐이다. 문제는 컴포넌트의 인스턴스가 제거되면서 RPC 채널이나 프록시, 스텁까지 모두 한꺼번에 사라진다는 점에 있다. 이렇게 되서는 매우 곤란한데 이런 결과는 원격지 서버의 리소스를 자유롭게 풀어준다는 이득보다도 매번 RPC 채널을 다시 생성해줘야만 하는 또 다른 부하를 유발하게 되는 것이다. 다행스럽게도 적시 활성화 서비스는 이런 문제점을 발생시키지 않는다. 나중에 다시 자세하게 논의를 하겠지만 적시 활성화 서비스가 실제로 제거를 하는 자원은 정확하게 원격지 서버에 생성된 컴포넌트의 인스턴스뿐이다. 즉, 비주얼 베이직 6.0 프로그램 자체와 클라이언트에 생성된 컴포넌트 프록시, RPC 채널, 그리고 비지니스 로직 계층을 구현한 서버상에 존재하는 컴포넌트의 스텁은 전혀 해제를 시키지 않는다. 따라서, 자연스럽게 원격지 서버의 리소스를 자유롭게 풀어주면서도 고비용이 요구되는 RPC 채널 생성은 반복할 필요가 없어지는 것이다. 더군다나 클라이언트 프로그램측에서는 윈격지 서버에 생성됐던 컴포넌트의 인스턴스가 해제되었다는 사실을 인지할 수가 없다. 왜냐하면 컴포넌트의 스텁이 해제되지 않고 남아있기 때문인데 이런 특성으로 인해서 한 가지 장점이 더 생기게 된다. 앞에서도 한 번 간단하게 얘기했지만 클라이언트측 프로그램을 작성하면서 지금까지 설명한 적시 활성화 서비스와 관련된 제반 사항들을 전혀 고려하지 않고도 평소와 동일하게 코드를 작성하는 것이 가능하다는 사실이다. 나머지 필요한 모든 세부적인 처리는 적시 활성화 서비스가 내부적으로 적절하게 제어해주며, 심지어는 프로그램이 처음 실행될 때 컴포넌트의 인스턴스를 생성하고 프로그램이 종료될 때 비로소 컴포넌트의 인스턴스를 해제하도록 프로그램을 작성해도 전혀 문제가 되지 않는다.

적시 활성화 서비스의 양면성

마지막으로 지금까지 논의해온 내용들을 정리해보고 본문을 마무리하도록 하겠다. 각각의 테스트 결과들로부터 알 수 있는 것처럼 적시 활성화 서비스를 사용한다고 해서 반드시 긍정적인 효과만 기대할 수 있는 것은 절대 아니다. 적시 활성화 서비스를 이용해서 구체적인 이득을 얻기 위해서는 시스템의 환경이 대체적으로 어떤 특징들을 만족해야만 한다. 그리고, 그 중에서도 가장 중요한 부분이 바로 적시 활성화 서비스를 이용하는 시스템의 규모가 일정한 수준 이상이 되어야 한다는 점이다. 반드시 그런 것은 아니겠지만, 대체적으로 대규모 시스템일수록 적시 활성화 서비스를 사용해서 기대할 수 있는 이득의 규모가 커지게 된다. 굳이 비유를 한다면 100에 대한 1%는 고작 1에 불과하지만 1,000에 대한 1%는 100이라는 커다란 차이를 얻을 수 있는 것과 비슷하다. 가령, 메모리 1M를 절약하기 위해서 적시 활성화 서비스를 도입할 필요는 없겠지만 절약되는 메모리의 양이 100M라면 얘기가 근본적으로 달라지는 것이다. 그러므로 규모가 어느 수준 이하에 불과한 소규모 시스템에서는 자동 트랜잭션 서비스를 이용하는 경우가 아닌 이상 버거운 노력을 들여서 굳이 적시 활성화 서비스를 도입할 필요가 없다. 중소기업의 고객 홍보 사이트라던가 개인이 운영하는 자그마한 규모의 쇼핑몰 같은 경우에는 적시 활성화 서비스를 도입함으로서 얻게 되는 있는 이득보다도 장차 필연적으로 겪을 수 밖에 없는 유지보수의 문제가 더 크게 다가오게 될 수 밖에 없다. 그리고, 한 가지 명심할 것은 적시 활성화 서비스가 가져다주는 이득은 기존 상태에 추가적으로 발생하는 순수한 이득이 아니라, 약간의 퍼포먼스를 희생함으로서 얻어지는 것이라는 점이다. 따라서, 두 요소의 상관 관계를 보다 치밀하게 따져서 이득의 규모가 퍼포먼스의 저하를 상회할 경우에만 적시 활성화 서비스를 도입하는 것이 바람직하다.

조금 엄격하게 말해본다면, 트랜잭션 처리 역시도 반드시 필요한 경우가 아닌 바에야 굳이 자동 트랜잭션 서비스를 이용하여 구현할 필요는 없는 것이다. 그리고, 한 가지 여러분들에게 질문을 던져보고 싶은 것이 있다. 여러분은 프로그램을 작성하면서 트랜잭션 처리를 정말 충실하게 구현하는가? 예를 들어서, 게시판 프로그램을 작성하면서 트랜잭션 처리를 충실하게 구현하는가? 또는, 포탈이나 커뮤니티 사이트의 메인 페이지를 구성하면서 트랜잭션 처리를 충실하게 구현하는가? 설문 조사 페이지를 작성하면서 트랜잭션 처리를 충실하게 구현하는가? 필자가 너무 과장해서 짐작하는 것일지도 모르겠지만 대부분 여러분들의 대답은 '아니오'일 것이다. 그럼에도 불구하고 완벽한 트랜잭션 처리를 위해서 COM+ 서비스의 자동 트랜잭션 서비스를 이용한다고 대답한다면 그것은 어폐에 불과하다. 이런 종류의 시스템들을 작성하면서 트랜잭션 처리를 구현하는 개발자들은 거의 없을 것이다. 오히려 이런 종류의 시스템들은 트랜잭션 처리보다는 퍼포먼스가 훨씬 더 중요하고, 특수한 몇몇 경우를 제외한다면 트랜잭션 처리를 하지 않는 것이 더 바람직하다. 자동 트랜잭션 서비스가 정말로 요구되는 시스템들은 예를 들어 기업체의 무슨 무슨 시스템과 같이 트랜잭션 처리에 민감한 시스템 같은 것들이다. 그리고, 그 중에서도 이기종 데이터베이스간의 분산 트랜잭션 처리가 요구된다거나 컴포넌트를 기반으로 한 복잡한 비지니스 로직의 구현이 중요시 되는 시스템에서 비로소 그 진가가 발휘된다. 결과적으로 이런 면면들을 종합적으로 고려해 볼 때, 필연적으로 일반적인 시스템에서의 적시 활성화 서비스 도입 요구는 더욱 낮아질 수 밖에 없다.

그리고, 이론적으로 단일 시스템 환경에서보다는 분산 시스템 환경에서 적시 활성화 서비스의 기대 효과가 월등히 높아진다. 이 얘기를 조금 다른 관점에서 바꿔본다면 적시 활성화 서비스를 구현한 단일 컴포넌트의 재사용 빈도와 적시 활성화 서비스의 기대 효과는 비례하여 증가한다는 말과도 동일하다. 필자가 참여했던 대부분의 프로젝트에서는 주로 다음과 같은 방식으로 시스템이 구성되곤 했다. 전체 시스템의 가장 앞단에 L4 스위치가 위치해 있으면서 두 대 이상의 웹 서버에게 부하에 근거하여 클라이언트의 요청을 분산해준다. 그리고, 당연한 얘기겠지만 각각의 웹 서버에는 동일한 웹 응용 프로그램들이 설치되어 있는데, 이 웹 서버에는 웹 응용 프로그램뿐만 아니라 비지니스 로직을 구현한 컴포넌트들이 구성 요소 서비스에 등록되어 데이터베이스 서버와 작업을 처리하는 구조이다. 물론, 이런 구조가 틀렸다고 말을 하려는 것은 아니다. 그렇지만 필자 개인적으로는 이런 구조는 적시 활성화 서비스의 효과를 극대화시킬 수 있는 구조는 아니라고 믿는다. 애시당초 COM+ 서비스를 도입하지 않은 상태라면 모르겠지만 일단 도입한 상태라면 물리적으로 컴포넌트들를 최대한 한 곳에 위치시키고 재사용 빈도를 극대화 해야한다. 그리고, 그런 노력들은 자연스럽게 윈도우즈 DNA의 개념에 보다 근접한 결과를 얻을 수 있게 해준다. 기존 구성의 가장 큰 문제점은 비지니스 로직을 구현한 컴포넌트가 하나의 물리적인 서버에 집중되어 있지 않고 모든 웹 서버마다 각각 한 본씩 존재한다는 점에 있다. 즉, 물리적으로 4대의 웹 서버가 존재한다면 동일한 비지니스 로직 컴포넌트도 결과적으로 4본이 존재하게 되는 것이다. 간단하게 계산을 해봐도 이런 방식으로는 비지니스 로직 컴포넌트의 재사용 빈도는 4분의 1로 줄어들게 된다. 또한, 컴포넌트가 업데이트되기라도 하면 동일한 작업을 네 차례 반복해서 각각의 웹 서버마다 적용을 해주어야만 한다.

비지니스 로직 컴포넌트가 분산되어 존재하는 경우

이런 경우, 필자가 생각하고 있는 이상적인 구성은 다음과 같다. 먼저, 현재 구성 상태에서 다른 부분들은 그대로 유지하되 비지니스 로직 컴포넌트들을 웹 서버들로부터 모두 걷어내어 별도의 물리적인 서버에 재설치한다. 만약, 여러가지 이유로 인해서 별도의 서버를 둘 수 없다면 웹 서버들중에서 가장 사양이 좋은 머신에 컴포넌트를 설치해도 무방할 것이다. 그 뒤에 컴포넌트가 설치되지 않은 웹 서버들에는 비지니스 로직 컴포넌트의 프록시들만을 설치하는 것이다. 이와 같은 형태로 시스템 구성을 변경하면 거의 온전하게 비지니스 로직 컴포넌트들을 재사용할 수 있으며 적시 활성화 서비스의 효과가 극대화된다. 게다가, 비지니스 로직에 변경이 발생하는 경우에도 단 하나의 서버를 대상으로만 변경 사항을 적용해주면 된다. 물론, 프록시까지 다시 설치해야 할 경우가 발생할 수도 있겠지만, 애시당초 인터페이스가 변경된 컴포넌트는 근본적으로 전혀 다른 컴포넌트라고 생각하는 편이 올바른 접근 방법일 것이다. 더군다나 프록시까지 재설치해야 한다고 하더라도 믿기지 않을 정도로 재설치가 쉽고 편리하므로 전혀 문제가 되지 않는다. 아무튼 필자가 제시하는 것과 같은 전체 시스템 구성이 가능해지려면 비단 프록시 문제뿐만 아니라 DCOM 환경을 어렵지 않게 구성할 수 있어야만 한다. 만약, 그게 불가능하다면 이러한 논의 자체가 무의미한 것일 터이다. 다행스러운 사실은 앞에서도 간단하게 언급을 했던바와 같이 애초에 COM+ 서비스 자체가 이런 형태의 구성을 염두에 두고 제작된 기반 구조이기 때문에, 그 관리 도구에 해당하는 구성 요소 서비스 차원에서 필요한 기능들을 지원해주기 위한 편리한 도구들을 제공해주고 있다는 점이다. 이 기능들에 과해서는 적시 활성화 서비스에 관한 마지막 글에서 자세하게 살펴보려고 한다.

비지니스 로직 컴포넌트가 한 곳에만 존재하는 경우

그러나, 이런 점들을 모두 감안하다고 하더라도 필자가 지금 제시하고 있는 방법이 모든 상황에 여과없이 곧바로 적용될 수 있는 것은 아니라는 점을 명심해야한다. 필자가 본문의 논의를 통해서 강력하게 주장하고자 하는 바는 오직 한 가지 뿐이다. 그것은 바로 철저한 분석이 선행되지 않은 시스템을 대상으로, 좁은 의미에서는 적시 활성화 서비스를 넓은 의미에서는 COM+ 서비스를 함부로 도입하지 말라는 것이다. 그리고, 본문의 대다수 내용들은 여러분이 그 분석을 진행하면서 어떤 결정을 내려야 할 때 조금이나마 판단을 도와주기 위해 마련된 지극히 일반론적인 사실들일 뿐이다. 실제 프로젝트를 통해서 접하게 되는 시스템들의 유형은 실로 다양하다. ASP 또는 ASP.NET을 기반으로 하는 웹 시스템인 경우도 있고 비주얼 베이직 6.0이나 비주얼 베이직 .NET 기반의 윈도우즈 응용 프로그램 시스템인 경우도 있다. 단 한대의 서버에 모든 시스템 구성 요소가 집중되어 있는 경우도 있고, 여러 대의 서버에 걸쳐서 분산되어 있는 경우도 존재한다. 마이크로소프트사의 솔루션들만으로 전체 구성이 이루어진 시스템도 존재하고 가끔은 IBM 호스트나 SAP으로부터 데이터를 가져와야만 하는 경우도 존재한다. 그리고, 누누이 얘기하는 것이지만 SI 프로젝트에서는 시스템이 반드시 기술적인 면만을 감안하여 결정되는 것은 아니라는 사실도 주지해야만 한다. 이렇게 다양한 시스템 환경에 모두 들어맞는 하나의 방법론은 아마도 존재하지 않을 것이다. 오로지 적절한 실제 테스트와 다양한 각도에서의 분석만이 각각의 시스템에 적절한 시스템 구현을 이끌어 낼수 있을 것이다.

다음글에서는...

본문을 마무리하면서 한 가지 짚고 넘어가고 싶은 점은, 본문은 절대로 적시 활성화 서비스에 관한 모든 내용들을 다루고 있는 결정판, 가령 시중에 출간되어 나와 있는 무슨무슨 바이블류의 서적과 같이 관련된 모든 내용들을 다루고 있는 문서는 아니라는 사실이다. 그보다는 전문적인 컨설턴트나 강사가 아닌, 여러분들과 동일한 입장에 서 있는 한 사람의 개발자인 필자가 몇 년 동안 직접 겪고, 고민하고, 학습했던 내용들을 요약한 글이다. 분명히 여러분들 중 어떤 분들에게는 본문이 많은 도움이 될 것이라고 믿는다. 그러나, 필자보다도 훨씬 뛰어난 실력을 갖추고 계신 어떤 분들에게는 미숙하게만 보이는 부분들이 많을 것임을 겸허하게 인정한다. 그런 부분들은 언제라도 지적을 해주시면 열린 마음으로 수용할 것임을 미리 밝혀두도록 하겠다. 그리고, COM+ 서비스에 관해서 지금까지 그다지 관심을 가지고 계시지 않으셨던 분들에게는 본문에서 다루고 있는 내용들이 조금 난해할 것이라고 생각한다. 그것은 최소한 한 번 정도는 COM+ 서비스와 관련된 고민을 직접 해보신 분들을 대상으로 작성된 글이기 때문인데, 그런 분들은 먼저 관련 기초 서적들을 바탕으로 COM+ 서비스에 관한 이해를 어느 정도 선행해야만 할 것이다.

개인적으로 이번글은 적시 활성화 서비스에 관해서 깊이 알아봤다기 보다는 대략 정도 운만 띄운 정도라고 생각한다. 다음글에서는 적시 활성화 서비스 자체에 대해서 보다 깊게 살펴보려고 하며, 현재로서는 단지 계획에 불과할 뿐이지만 다음과 같은 순서를 밟으려고 생각하고 있다. 먼저, 적시 활성화 서비스를 이용하기 위해서 컴포넌트에 구현되어야만 하는 실제 코드들과 그 의미, 그리고 주의점들에 대해서 알아볼 것이다. 그리고, 그 뒤에는 적시 활성화 서비스와 개체 풀링 서비스와의 상관 관계에 대해서 알아볼 것이다. 그러나, 자동 트랜잭션 서비스와의 상관 관계에 대해서는 차후에 다룰 것이며, 일단 적시 활성화 서비스와 관련된 일련의 문서에서는 다루지 않는다. 그 다음에는 프로그래머의 임의대로 개체의 활성화와 비활성화를 제어하는 방법을 논의할 것이며, 마지막으로 비주얼 베이직 .NET을 사용한 구현에 관해서 다룰 생각이다. 물론, 논제 중간 중간에 반드시 필요하다고 판단되는 부수적인 주제들, 이를테면 구성 요소 서비스에서 제공하는 기능들을 이용한 DCOM 환경 구현 방법과 같은 내용들도 포함된다. 전체적으로는 본문을 제외하더라도 적어도 두 번 내지 세 번 정도는 적시 활성화 서비스와 관련된 일련의 글들이 필요하리라고 생각하고 있으며 기간적인 측면에서도 역시 상당한 시간이 필요하리라고 본다.