Silverlight를 설치하려면 여기를 클릭합니다.*
Korea 대한민국변경|Microsoft 전체 사이트
MSDN
|개발자 센터
MSDN Home   MSDN Home
MSDN 홈 > MSDN Magazine > 2000년 기사 > COM+ 및 Windows 2000: COM+ 성능 최대화를 위한 10가지 팁과 트릭

COM+ 및 Windows 2000: COM+ 성능 최대화를 위한 10가지 팁과 트릭

David S. Platt 저
이 문서는 독자가 COM+를 잘 알고 있다는 전제 하에 작성되었습니다.

개요: COM+의 성능을 극대화하기 위한 방법은 여러 가지가 있으며, 이 문서에서는 저자가 제공하는 10가지 방법을 소개합니다. 팁에서는 트랜잭션 처리의 중요성과 COM+ 카탈로그의 사용 그리고 3계층 분산 시스템의 설계에 대해 설명합니다. 또한, 올바른 스레딩 모델을 사용한 구성 요소 작성, 구성 요소 트랜잭션을 사용하는 시기, 프로세스 초기에 수행하는 스트레스 테스트의 중요성 등에 대해서도 설명합니다.?

기타 제안에서는 개체 상태의 위치 인식, COM+ 응용 프로그램에 필요한 적절한 인증 수준의 선택, 대기 중인 구성 요소의 올바른 사용, 개체 풀링 등의 중요성에 대해 강조하여 설명합니다.?


COM+은 3계층 분산 환경의 중간 계층에서 발생하는 일반적인 문제를 해결하기 위해 사전 구축된 인프라를 제공하는 Microsoft Windows 2000 런타임 환경입니다. 다른 강력한 도구와 마찬가지로, COM+를 올바른 방향으로 적절하게 사용하면 뛰어난 기능을 발휘할 수 있지만, 잘못 사용하면 기능이 저하되고 심지어 위험할 수도 있습니다. 1년 전 Understanding COM+(Microsoft Press)를 집필하는 동안, COM+를 사용하는 방법은 알고 있었지만, 최소의 노력으로 최대의 성능을 달성하는 방법에 대해서는 확신하지 못했습니다. 이후로 COM+를 사용하고 있는 많은 고객과 학생들을 상대하면서 보다 많이 알게 되었습니다. 이러한 경험을 바탕으로 COM+를 최대로 활용하기 위한 10가지 팁과 트릭을 목록으로 만들었습니다. 한편으로는 COM+ 환경의 기본 원리를 다루고, 다른 한편으로는 구체적인 구현 문제를 다루었습니다.

? 이 팁과 트릭이 사용자에게 도움이 되기를 바랍니다. 앞으로의 모든 기사, 서적 및 저자가 4개월마다 발행하는 전자 메일 COM+ 뉴스레터에서 이 팁과 트릭을 사용할 것입니다. 뉴스레터는 http://www.rollthunder.com/?에서 무료로 구할 수 있습니다. 의견이 있으시면 dplatt@rollthunder.com으로 전자 메일을 보내주십시오.

맨 위로


1. 트랜잭션 처리 관련 서적
Philip A. Bernstein 및 Eric Newcomer가 집필한 Principles of Transaction Processing(1997년, Morgan Kaufmann 출판)을 읽어보십시오. 이 책을 가장 먼저 언급한 이유는, 제가가 트랜잭션에 대한 공부를 시작하기 전에 먼저 이 책을 읽지 못했기 때문입니다. 아마 먼저 읽었더라면 시간을 상당히 절약하고 보다 정확한 시각을 가졌을 것입니다. 트랜잭션은 Windows 환경에서 생소할 수 있지만, 컴퓨팅 환경에서는 생소하지 않습니다. 트랜잭션은 60년대 초 SAABRE 항공 예약 시스템에서 처음으로 상용화되었습니다. 이 시스템을 사용하여 전세계 여러 사용자들은 당시로서는 대용량인 데이터베이스에 동시에 액세스할 수 있었습니다. 하지만 대규모의 이 시스템은 이전의 컴퓨팅 환경에서 볼 수 없었던 문제들에 직면했습니다. Bernstein과 Newcomer는 이 문제들과, 이를 해결하기 위한 아키텍처 원리들을 훌륭하게 설명했습니다.

제가 가르치는 학생들은 자신들의 마음에 들지 않는 COM+의 여러 부분들을 파고드는 방법에 대해 질문하고 있습니다. 예를 들어, 학생들은 트랜잭션에 참여하는 구성 요소를 작성하고 싶지만, COM+에서 요구하는 JIT(just-in-time) 활성을 귀찮게? 여기고 있습니다. JIT 활성에서 트랜잭션이 종료되면 트랜잭션에 참여하는 모든 개체는 소멸되므로, 학생들은 개체 상태를 주의해서 관리해야 합니다. 비트랜잭션 환경에서는 주의할 필요가 없으므로, 학생들은 개체 상태를 주의해서 관리해야 하는 이유를 알지 못합니다. 비트랜잭션 환경에서 보면 학생들은 트랜잭션 격리가 무엇인지 그리고 왜 중요한지를 이해하지 못합니다. 학생들은 마치 생화학을 이해하지 않고서 의학을 공부하는 것과 같습니다.??

맨 위로


2. COM+ 카탈로그에 대한 이해
예를 들어, 클래스를 구현하는 특정 서버 DLL와 요약 CLSID 사이의 매핑과 같이, 운영 체제가 COM 구성 요소와 상호 작용하는 방법을 나타내는 정보를 저장하기 위해 클래식 COM은? Windows 레지스트리를 사용합니다. 처음에는 저자도 레지스트리가 어렵고 다소 막막했지만, 작업해야 하는 레지스트리 엔트리를 이해하고 운영 체제에서 이 레지스트리의 의미를 이해한 후에는 클래식 COM을 훨씬 정확하게 이해했습니다.

COM+은 구성 요소의 관리를 보다 쉽게 제어할 수 있으며, 따라서 클래식 COM보다 많은 관리 정보를 필요로 합니다. 레지스트리는 새로운 정보를 저장할 만큼 크거나 빠르지 않으므로, COM+는 COM+ 카탈로그라는 새로운 시스템 데이터베이스를 사용합니다. 그림 1에 나타난 구성 요소 서비스 탐색기를 사용하면, 사용자는 카탈로그에서 엔트리를 조작할 수 있습니다. 이 도구는 편리하지만 수행하려는 모든 작업에 충분하지는 않습니다. 우선, 이 도구는 인간에 의해서만 사용될 수 있으므로, 사용자는 프로그램 제어를 통해서 카탈로그에 빈번하게 쓰고 읽어야 합니다. 또한 이 도구는 카탈로그에 있는 모든 등록 정보(예: 일시적 가입의 집합)를 액세스할 수는 없습니다. 응용 프로그램이 실행될 환경을 완벽하게 제어하려면 우선 COM+ 카탈로그를 완전하게 학습해야 합니다.


Figure 1 Component Services Explorer
그림 1 구성 요소 서비스 탐색기

다행히 카탈로그 학습은 그다지 어렵지 않습니다. 일련의 시스템 제공 개체를 통해서 모든 관련 프로그램에서 카탈로그를 사용할 수 있습니다. 구성 요소 서비스 탐색기는 개체에 대한 편리한 사용자 인터페이스를 제공하는 별개의 응용 프로그램입니다. 프로그램은 단순히 이 셸을 무시하고 카탈로그에 직접 연결할 수 있습니다.

카탈로그의 입력 지점은 ProgID가 COMAdmin.COMAdminCatalog라는 개체입니다. 카탈로그를 조작하려는 프로그램은 이 클래스 개체를 만들고 이 개체의 메서드를 불러옵니다. 이 메서드를 사용하여 카탈로그의 개체 계층을 탐색하고 메서드의 속성을 얻을 수 있습니다. 계층 다이어그램이 그림?2?에 나와 있습니다. 이 다이어그램은 복잡해 보이지만, 사용자는 대부분의 시간을 응용 프로그램/구성 요소/인터페이스 트리에서 보낼 것입니다. 트리에서 각 노드는 고유의 등록 정보 세트를 가지는 개체입니다.

카탈로그 등록 정보를 보기 위한 가장 좋은 방법은 Platform SDK와 함께 제공되거나 MSDN Online에서 구할 수 있는 예제 프로그램 뷰어입니다(그림 3 참조). 그림에서 저자는 응용 프로그램 집합을 선택했습니다. 관련 집합 목록은 응용 프로그램에서 사용할 수 있는 다른 집합을 나타냅니다. 계층 차트에서 구성 요소 및 역할 집합을 볼 수 있습니다. 기타 목록(RelatedCollectionInfo, PropertyInfo, ErrorInfo)들은 다른 집합에 존재하므로, 차트에서 생략했습니다. 이 목록들은 자주 사용되지 않으므로 이 문서에서는 자세하게 설명하지 않습니다.


Figure 3 Catalog Property Viewer
그림 3 카탈로그 등록 정보 뷰어

개체 목록은 선택 집합에 있는 다양한 요소를 표시합니다. 이 경우 카탈로그에 있는 응용 프로그램을 나타냅니다. 이 목록을 그림 1의 탐색기에 나타난 목록과 비교해 보십시오. 등록 정보 목록은 카탈로그에 있는 COM+ 응용 프로그램을 설명하는 모든 등록 정보를 표시합니다. 저자는 ShutdownAfter라는 목록을 선택했고, 창 하단에 있는 등록 정보 값 필드에 3(분: 시스템 기본값)이 나와 있습니다.

프로그램에 의해 카탈로그를 조작하는 응용 프로그램을 예로 들기 위해서, 저자가 작성한 이벤트 시스템 감시 프로그램과 연결된 COM+의 일부 코드 목록이 나와 있습니다( 그림?4?). 이 프로그램은 시스템에 등록된 모든 이벤트 클래스의 목록을 표시하며, 감시하려는 임의의 클래스를 선택할 수 있습니다. 그리고 이벤트 클래스에 대한 종류 라이브러리를 읽음 다음, 라이브러리에 대한 VTBL을 설치하고, 이벤트를 일시적으로 가입시킵니다. COM+로부터 이벤트 통보를 받은 프로그램은 사용자가 볼 수 있도록 이 통보를 창에 나타냅니다.

그림?4?의 코드는 MFC 응용 프로그램의 코드입니다. 이 코드의 InitInstance 메서드를 사용하여? 카탈로그 개체를 만들고 GetCollection 메서드를 사용하여 루트 집합을 불러옵니다. 그리고 나서 프로그램의 다른 부분에서 사용하기 위해 이 개체들을 전역 변수에 저장합니다. 시스템에 등록된 이벤트 클래스의 목록을 표시하도록 메뉴를 사용자가 선택한 경우 InitDialog 메서드가 호출됩니다. 특정 이벤트 클래스를 나타내는 구성 요소를 찾기 위해서 시스템에 있는 모든 응용 프로그램의 구성 요소를 반복해서 찾아야 합니다. 응용 프로그램의 집합을 구하기 위해 호출된 GetCollection의 루트 상의 위치를 알 수 있습니다. 그 다음 응용 프로그램 집합 상에서 Populate라는 비직관적인 메서드를 호출해야 합니다. 이 호출 작업을 실행한 후에야 비로소 카탈로그 개체는 데이터베이스에 액세스해서 집합 목록을 읽을 수 있습니다. 응용 프로그램 집합을 구하기만 하면 데이터베이스에 액세스할 수 있다고 생각할 수 있지만, 그런 방식으로 프로그램이 작성되지 않았습니다. 컬렉션의 카운트 등록 정보를 사용하여 각각의 응용 프로그램에 대해 찾기를 반복합니다. 또한 각 응용 프로그램 내에서 구성 요소의 집합에 대해 찾기를 반복합니다.

맨 위로


3. 중간 계층에서 클라이언트로 가장하지 마십시오.
일반적으로 3계층 분산 시스템은 대용량 벡엔드 다중 사용자 데이터베이스에 액세스할 수 있습니다. 액세스 인증을 보유한 데이터에만 사용자가 액세스하도록 보장하는 것이 상당히 중요합니다. 예를 들어, 일반 직원들은 인력 자원 시스템을 사용하여 자신들의 기록을 볼 수 있지만 다른 직원들의 기록은 볼 수 없습니다. 인력 자원 부서 직원들은 모든 직원의 기록을 볼 수 있지만 기록을 변경할 수는 없으며, 일부 특정 직원만이 실제로 기록을 변경할 수 있습니다.

시스템 아키텍처에서 인증 결정을 수행하는 위치 및 시간을 설계하는 것은 시스템 처리 속도에 상당한 영향을 미칩니다. 두 가지 기본적인 설계 방법이 있습니다. 가장-위임(impersonation-delegation) 모델이라고 알려진 첫 번째 모델에서, 중간 계층 개체는 데이터 계층에 액세스하기 이전에 호출자의 신분을 획득합니다(클라이언트로 가장). 각 사용자가 액세스할 수 있는 데이터 영역을 나타내는 규칙은 데이터 계층 시스템에 저장되어 있습니다. 이 접근 방식이 그림 5에 나와 있습니다.

Figure 5 Impersonation-delegation Model
그림 5 가장-위임 모델

이 방식이 간단해 보일 수 있습니다. 단순히 사용자는 중간 계층에 있는 CoImpersonateClient를 호출하고 데이터베이스가 이를 이해하도록 합니다. 하지만 이 방식에는 두 가지 단점이 있습니다. 우선, 모든 액세스에는 하나가 아닌 두 개의 인증이 필요합니다. 중간 계층은 기본 클라이언트를 인증해야 하고, 데이터 계층은 중간 계층의 호출을 인증해야 합니다. "당신은 실제 사용자입니까?"라는 질문에 대답하는 서버 및 클라이언트 사이의 핸드셰이크를 인증을 사용하여 나타냅니다. 이 문서의 후반에 설명된 것처럼, 일반적으로 클라이언트가 서버에 개체를 만드는 경우, 인증이 자동으로 발생하도록 서버가 설정되어 있습니다. 사용자는 서버를 위한 코드를 작성할 필요가 없지만, 이 서버에는 수 마이크로 초 동안 부하가 집중되고, 도메인 서버로 부하를 되돌려야 합니다. 결국 서버에는 부하가 더 증가하게 되고, 병목 현상을 유발합니다. 한 번의 인증보다 두 번의 인증이 보다 악영향을 미칩니다.?

이 방식의 두 번째 문제는 데이터 계층이 비인증 액세스를 감지하는 경우 프로세스가 지연된다는 점입니다. 사용자는 이미 중간 계층에서 후위 계층(대개 저속 계층)으로 네트워크 홉을 실행해서, 데이터 계층 시스템의 속도가 느려졌습니다. 실패가 예상되는 동작은 가능하면 프로세스 초기에 실패가 발생해서, 이 동작으로 시간을 소모하지 않으려고 할 것입니다. 마치 식대를 지불할 때 지갑 분실 사실을 발견한 것이 아니라 자동차에 탔을 때 발견하기를 원하는 경우와 같습니다. 이 방식은 2계층 클라이언트/서버 시절의 유물과도 같습니다. 이 시절에는 인증 논리가 위치하는 중간 계층이 존재하지 않았습니다.

Figure 6 Trusted Server Model
그림 6 트러스트된 서버 모델

최신 3계층 시스템을 위한 향상된 접근 방식이 그림 6에 나와 있습니다. 이 모델에서 중간 계층은 비즈니스 프로세스의 일환으로 필수적인 모든 인증 확인을 수행합니다. 또한 정보를 요청한 특정 클라이언트가 이 정보를 보기 위한 권한이 있는지를 결정한 다음에야 비로소 데이터베이스로 호출합니다. 중간 계층 서버는 특정한 하나의 ID를 가지고 실행됩니다. 데이터 계층은 요청하는 모든 곳에 이 ID 액세스를 부여하기 때문에 그 이름이 "트러스트된 서버" 모델입니다. 당신의 지갑을 사용하는 아내를 신뢰하기 때문에, 그녀에게 돈의 용도를 묻지 않습니다. 이 경우에는 중간 계층이 기본 클라이언트를 인증할 때 단 하나의 인증이 필요합니다. 따라서 하나의 동작이 실패하는 경우, 시간과 리소스를 소모하지 않고 일찌감치 실패합니다.?

맨 위로


4. 스레드 유사성(Thread Affinity) 방지
COM 및 스레드는 언제나 불안정한 상태로 공존합니다. Windows NT 3.1은 32비트 COM을 지원하지 않습니다. Windows NT 3.5는 프로세스당 하나의 스레드 상에서 COM을 지원합니다. 프로세스의 다중 스레드에서 COM을 처음으로 사용하게 되었을 때(Windows NT 3.51 및 Windows 95), 개체가 두 가지 다른 스레드 상에서 동시 호출을 수신하는 문제가 발생했습니다. 이 문제를 해결하기 위해, 위 버전의 운영 체제들은 단일 스레드 아파트(STA)의 개념을 도입하면서도, 여전히 구성 요소들을 쉽게 작성할 수 있습니다.

STA의 개체는 자신이 생성된 스레드로부터 오는 모든 호출을 수신합니다. 다른 스레드에서 발생한 호출은 메시지 펌프를 통과하므로, 개체는 단 하나의 스레드에서만 호출을 수신합니다. STA? 외부에서 구성 요소를 실행하는 데 필요한 연속 코드를 작성하는 것보다는 ThreadingModel 레지스트리 엔트리를 Apartment로 설정해서 STA에서 구성 요소를 실행하도록 표시하는 것이 훨씬 간단합니다.?

STA 모델에서 OS는 메시지 펌프를 통해서 필요한 모든 연속화(serialization)를 처리하기 때문에, 구성 요소를 비교적 간단하게 작성할 수 있습니다. 하지만 STA 모델은 스레스 유사성을 희생해서 연속화를 달성합니다. 즉, 구성 요소는 STA 모델이 생성된 스레드에서 호출한 호출만을 수신합니다. 몇 가지 이유로 단일 데스크톱에서는 이 점이 문제가 되지 않습니다. 첫 번째 이유로, COM 개체가 수행하는 대부분의 작업이 UI와 관련이 있고 따라서 창과 관련이 있습니다. 창은 이 창을 생성한 스레드 상에서 모든 메시지를 수신하기 때문에, 창에 의해 생성된 개체는 이 창을 생성한 스레드 상에 존재할 것입니다. 개체 및 창은 동일한 스레드에 속하기 때문에, 이들은 서로 통신하기 위해 메시지 펌프를 통과할 필요가 없습니다. 또한 단일 데스크톱은 대부분의 시간을 사용자 입력을 기다리면서 소모하므로, 메시지 펌프를 통과한 상호 아파트(cross-apartment) 호출이 거의 존재하지 않습니다.

불행하게도, 단일 데스크톱에서 사용자의 환경을 간편하게 해 주는 스레드 유사성이 분산 시스템에서는 악영향을 미칩니다. 중간 계층 시스템에 STA 개체가 존재한다고 가정합시다. 하나의 클라이언트가 개체로 DCOM 호출을 보낸다면, 이 호출은 먼저 임의의 스레드에 의해 서버에서 처리됩니다. 이 임의의 스레드는 오직 이 목적만을 위해 존재하는 RPC 풀에 있습니다. 하지만 호출이 향하는 개체가 STA에 존재하기 때문에, 수신 스레드는 개체의 STA를 보유하는 특정 스레드로 이 개체를 마샬링하고, 스레드가 호출을 처리하도록 기다린 다음 결과를 다시 마샬링해서 돌려 보냅니다.

이 스레드 전환은 상당한 시간 및 CPU 주기를 소모하며, 결과적으로 나쁜 영향을 미칩니다. 눈에 띄진 않지만 악영향을 미칠 수 있는 것이 병목 현상입니다. 원하는 STA 스레드가 사용 중이거나 다른 요청을 서비스하지 못할 수도 있습니다. 이 경우 클라이언트 및 수신 스레드는 원하는 스레드를 기다리며 동작을 중단합니다. 비록 100개의 스레드와 50개의 CPU를 사용할 수 있더라도, 특정 스레드를 기다리기 위해 동작을 중단합니다. 마치 옆 창구의 다섯 직원들은 놀고 있는데 특정한 은행 출납 직원을 기다리기 위해 줄을 길게 서는 것과 같습니다. 아마 다른 은행으로 갈 것입니다.

이제 어떻게 하면 될까요? 다른 임의의 스레드가 호출할 수 있도록 구성 요소를 작성해야 합니다. 다시 말하면 구성 요소들은 STA에 존재할 수 없으며, 그 대신 다른 종류의 아파트, 또는 Windows NT 4.0에 최초로 나타난 다중 스레드 아파트(MTA, ThreadingModel = "free"), 또는 Windows 2000에 나타난 새로운 중립 아파트(NA, ThreadingModel = "neutral")에 존재해야 합니다. 각 경우에, 클라이언트에서 오는 호출을 RPC 수신 스레드로부터 개체로 직접 전달할 수 있습니다. 특정한 직원을 기다릴 필요가 없으며, 비어 있는 처음 직원을 이용하면 됩니다. 이 방식으로 보다 신속하게 은행 업무를 마칠 수 있을 것입니다.?

하지만 이 개체가 다른 스레드로부터 호출을 수신하는 경우 연속화에 문제가 발생합니다. 이제 더 이상 스레딩 모델을 사용할 수 없습니다. 연속화된 다중 스레드 코드를 모든 경우에 대해 적절하게 작성하는 것은 상당히 어렵습니다. 그러면 이 코드를 스스로 작성해야 할까요? Windows NT 4.0에서는 그렇습니다. 개발자들이 이 기술을 거의 사용하지 않는 이유도 이 때문입니다. 하지만 COM+을 사용하면 사용자는 운영 체제로부터 연속화를 실행할 수 있습니다. 그림 7과 같이 COM+ 카탈로그에 있는 엔트리를 표시해서 MTA 또는 NA에 존재하는 개체를 요청 동기화로 표시할 수 있습니다. 이 동기화에 의해 COM+는 스텁 및 채널 사이의 정책 개체를 서버쪽으로 보냅니다. 이 정책 개체는 한번에 단 하나의 스레드가 특정 개체의 메서드에 액세스하도록 보장하고, 재입력을 제대로 처리하기 위해서 Mutex를 사용합니다.

Figure 7 Requiring Synchronization
그림 7 요청 동기화

MTA 또는 NA에서 실행되는 구성 요소를 작성하기 위해 연속화 이외에 필요한 것은 무엇입니까? 특정 스레드를 방해하는 개체 호출을 생성할 수 있는 코드를 작성하지 않아야 합니다. 예를 들어, 사용자는 스레드-로컬 저장을 사용하면 안됩니다. 왜냐하면 데이터를 특정 스레드에 저장하는 경우, 이 스레드로부터 오는 다른 호출을 알 수 없기 때문입니다. 일부 개발 환경에서는 스레드-로컬 저장을 사용하기 때문에, MTA 또는 NA에서 실행되는 코드를 작성할 수 없습니다. 이 개발 환경 중에서 Visual Basic 6.0이 가장 우수하지만, MFC에도 역시 이 문제가 존재합니다. 사용자는 어느 환경에서도 스레드 코드를 작성할 수 없습니다. 따라서 이 환경에서 개발된 구성 요소들은 스레드 유사성 병목 현상의 영향을 받을 것입니다.

Visual C++은 ATL을 사용하여 스레드 구성 요소를 생성할 수 있습니다. 이 마법사를 사용하여 개체를 생성하는 경우 MTA를 위해 "free" 스레딩 모델을 선택한 다음, NA를 원하는 경우 코드에서 수동으로 "neutral"로 변경하십시오. Visual Studio.NET 뿐만 아니라 Visual Studio.NET에 있는 C# 및 다른 언어들을 사용하여 스레드 코드를 작성할 수 있으며, 따라서 MTA 또는 NA에서 존재하는 구성 요소를 생성할 수 있습니다.



맨 위로


5. 간결한 트랜잭션 유지 또는 보상 트랜잭션의 사용
트랜잭션을 간결하게 유지하는 것이 다중 사용자 트랜잭션 시스템의 처리 속도를 향상시키기 위한 가장 좋은 방법이 될 수 있습니다. 트랜잭션은 다른 트랜잭션으로부터 격리되어 있어야 합니다. 다시 말하면, 현재 트랜잭션 A에서 실행 중인 개체는 트랜잭션 B에서 실행 중인 다른 개체가 사용하는 데이터를 볼 수 없습니다. 이와 같이 격리하는 이유는 트랜잭션이 다른 트랜잭션의 커밋 및 중단 여부를 알지 못하므로, 진행 중인 다른 트랜잭션에 있는 데이터의 유효 여부를 알 수 없습니다. 사용자는 데이터가 유효한지를 알지 못하므로, 사용자가 데이터를 오용하지 않도록 격리를 사용하여 데이터를 볼 수 없도록 합니다.

데이터베이스 및 기타 리소스 관리자는 트랜잭션 격리를 실행하기 위한 잠금 기능을 제공합니다. 트랜잭션 개체가 COM+ 리소스 관리자 데이터베이스에 있는 잠금이 해제된 데이터베이스 레코드에 처음으로 액세스하는 경우, 데이터베이스는 다른 트랜잭션이 이 레코드에 액세스할 수 없도록 잠금을 활성화합니다. 원하는 레코드를 격리시키기 위해 잠금을 실행해야 하는 인접 데이터의 양을 나타내는 잠금 범위는 데이터베이스마다 서로 다르며, 대개 데이터베이스에서 설정할 수 있습니다. 다른 개체가 잠긴 레코드(또는 잠금 영역에 있는 모든 것)에 액세스하려는 경우, 데이터베이스는 이 요청 개체가 소속된 트랜잭션을 검사합니다. 만약 트랜잭션이 잠금의 소유자와 동일하다면 액세스를 허용하지만, 그렇지 않다면 두 번째 개체는 처음 개체가 잠금을 해제할 때까지 기다려야 합니다. 개체가 잠금을 오래 보유할수록 백로그 및 병목 현상이 발생할 가능성이 높아집니다.

신용 카드 번호를 입력하는 것처럼 인간의 속도로 인간이 하는 작업과 관련된 트랜잭션이 발생하는 비즈니스 동작에서는 잠금 시간이 실제적인 문제를 유발합니다. 예를 들어, 저자는 최근에 온라인 티켓 판매 업체에서 콘서트 티켓을 구입했습니다. 티켓을 주문하기 위해 사용자가 원하는 티켓의 종류와 매수를 선택하면, 컴퓨터는 데이터베이스를 검색해서 비어 있는 좌석을 결정합니다. 사용자가 이 좌석을 원하느냐에 따라 구입 여부가 결정됩니다. 사용자가 이 좌석을 심사 숙고해서 선택한 다음 신용 카드 번호 정보와 배달 정보를 입력하는 데는 일정한 시간이 소요될 것입니다. 이 시간 동안 티켓 업체는 다른 사람에게 이 좌석을 팔 수 없습니다. 즉, 지불만 하면 이 좌석은 사용자의 것입니다.

사용자가 결정하는 동안 다른 사람이 티켓을 가로채지 못하도록 공연장에 일종의 잠금 장치를 사용할 필요가 있습니다. 반면에, 사용자가 오케스트라의 왼쪽과 오른쪽을 놓고 고민 하는 경우 다른 사람이 티켓을 예약할 수 없으므로 심각한 병목 현상을 유발할 수 있습니다. 사용자가 아무리 과감하고 신속하게 입력을 하더라도, 컴퓨터 처리 시간에 비해서 이 시간을 엄청난 시간입니다. 또한 데이터베이스의 각 좌석을 잠그기 위한 비용은 엄청날 것입니다. 따라서 적절한 시간 만에 티켓을 구입하면서도, 사용자가 고민 중인 좌석을 다른 사람이 구입하지 않도록 할 수 있는 다른 솔루션이 필요합니다.

이 문제에 대한 올바른 접근 방식은 보상 트랜잭션(compensation transaction)을 사용하는 것입니다. 이 방식은 이전 트랜잭션 작업을 취소하는 역트랜잭션(opposite transaction)과 거의 유사합니다. 이 방식은 지나치게 길거나 불확실한 잠금 시간에 대한 적절한 대안이 될 수 있습니다. 사용자가 티켓을 신청한 경우, 티켓 판매 시스템은 전체 데이터베이스 풀에서 티켓을 찾아서 사용자의 티켓으로 표시하는 단일 트랜잭션을 실행합니다. 이 티켓이 제거될 때까지 티켓 데이터베이스는 일정 시간 동안 잠겨야 하지만, 이 과정은 컴퓨터 속도로 수행되므로 문제가 되지 않습니다. 여전히 처리 속도가 충분하지 않은 경우, 사용자는 공연장 섹션마다 잠금을 사용할 수 있으며, 섹션의 최적 범위는 상관없습니다. 일단 이 잠금 작업이 완료되면, 사용자가 티켓을 고민하는 동안 누구든지 다른 유효 티켓을 구입할 수 있습니다. 사용자가 자신에게 제공된 티켓을 구입하지 않으려는 경우, 시스템은 다른 트랜잭션(보상 트랜잭션)을 수행해서 다른 사용자가 구입할 수 있도록 데이터베이스 풀에 보관합니다.

보상 트랜잭션에서 주의할 점은 전체 트랜잭션(모든 당사자에 의한 티켓 구입)의 격리 수준이 완전하지 않다는 점입니다. 사용자가 특정 티켓을 구입하려고 고민하는 동안, 이 티켓은 아직 사용자의 것이 아니며 구입하지 않는 경우 다른 사람의 것이 될 수 있지만, 공연장을 찾은 다른 사람들은 이 티켓을 찾을 수 없습니다. 사용자가 티켓을 포기하고 보상 트랜잭션이 실행되면, 잠시 후에 매진을 알리는 공연에서 티켓을 더 구할 수 있습니다. 다음 고객은 처음 고객이 좌석을 좋아하지 않아서 포기한 티켓을 가질 수 있습니다. 이와 같이 모든 티켓의 소유자가 이미 결정되어 있다는 결정론을 약간 희생해서 사용자의 주관심사인 처리 속도를 향상시킬 수 있습니다. 만약 티켓 2장을 판매하는 데 5분이 소요되고 하루 24시간 1주일 내내 줄을 선다고 가정하면, Madison Square Garden에서 열리는 이벤트의 티켓이 매진되기 위해서는 대략 34일이 소요됩니다.

맨 위로


6. 구축 이전에 스트레스 테스트를 수행
COM+ 시스템은 처리 속도에 관심이 있으며, 병목 현상은 시스템 처리 속도를 가장 빠르게 저하시킵니다. 3차선에서 2차선으로 줄었다가 다시 3차선으로 늘어나는 100미터의 고속도로를 통과하기 위해 한시간 동안 교통 체증 속에서 기다려야 한다고 가정해 보십시오. Boston 도심 도로는 이런 경우가 흔히 있습니다. 특정 부하율을 초과하는 이 짧은 도로로 인한 교통 체증 속도를 개선하기 위해 엄청난 비용이 소모되었습니다.

병목 현상은 매우 나쁜 영향을 미칩니다. 그러면 응용 프로그램에서 병목 현상을 찾은 다음 제거하는 방법은 무엇입니까? 병목 현상의 일반적인 원인은 이미 알려져 있으며, 마지막 세 개의 팁에서 설명한 것처럼 해결 방법도 문서화되어 있습니다. 사용자의 응용 프로그램에도 틀림없이 여러 병목 현상이 존재하지만 그 위치는 알 수 없습니다. 만약 위치를 알고 있었다면 이미 찾아서 해결했을 것입니다. 사용자가 아무리 우수한 설계자라 하더라도, 상당한 용량이 생성되어 병목 현상이 발생할 때까지는 발견할 수 없습니다. 이 때에는 이미 병목 현상이 명백하게 드러납니다. 병목 현상을 발견하기 위해 사용자는 테스트 제품군을 사용하여 직접 발견하거나, 고객에게 병목 현상을 발견해 주도록 요청할 수 있습니다. 테스트 제품군을 프로젝트 초기 예산에 포함시키는 것이 상근 감시원 또는 새로운 ID를 사용하는 것보다 저렴합니다. 어떤 방법이 최종 결과에 도움이 된다고 생각하십니까?

모든 개발자나 관리자가 위의 사실을 알고 있다고 생각할 수도 있습니다. 하지만 상당수의 개발자나 관리자는 자신들이 해결하지 않았던 병목 현상을 많은 고객이 발견하는 경우 상당히 놀라게 됩니다. 병목 현상은 여러 상위 계층이 의존하고 있는 하위 시스템 수준에서 발생하기 때문에, 이들은 전반적인 시스템 구성을 다시 설계해야 합니다.

일반적으로 개발 공정이 끝난 후 최종 성능을 조정하기 위해 개발 설비를 프로젝트에서 제거한 후에 스트레스 테스트를 수행합니다. 하지만 이것은 매우 좋지 않습니다. 때로는 출시 날짜를 맞추기 위해 이 테스트가 완전히 생략되기도 합니다. 이 경우는 심각한 정도가 아니라 자살 행위입니다. 사용자는 블록 다이어그램 아키텍처를 설계하자마자 인프라가 예상 부하를 처리할 수 있는지를 확인하기 위해 빈 개체를 사용하여 간단한 스트레스 테스트를 실행해야 합니다. 만약 부하를 처리할 수 없는 경우에는 업무 분배를 재고하고, 많은 양의 코드 대신 설계도에 대해 다시 작업을 재고해야 합니다. 그리고 개발이 진행됨에 따라 정기적인 QA 공정의 일환으로 테스트를 계속해서 수행합니다. 저자는 오늘 한 고객으로부터 절망적인 요청이 담긴 전자 메일을 받았습니다. 이 고객은 한달 후에 18개월 기간의 프로젝트를 구축하려고 하는데, 고객의 응용 프로그램 성능이 원하는 성능 이하로 저하되고 있습니다. 하지만 설계가 잘못된 이유와 위치를 알 수 없다고 합니다. 성능 테스트를 초기에 자주 수행했다면, 이 고객은 “긴급 고객” 요금을 지불할 필요가 없었을 것입니다.

시스템을 로드하는 여러 테스트 프로그램을 작성해 보십시오. 그렇게 어렵지 않습니다. 실제로 사람을 시스템에 앉히고 이들이 시스템을 사용하는 방법을 배우십시오. 이들이 하는 방식은 당신이 생각한 방식과 분명히 다르며, 아마 성능 향상에 필요한 예산을 변경시킬 것입니다. 생산을 시작한다고 생각하고 엄격하게 스트레스 테스트를 수행하고, 다시 한번 엄격하게 테스트를 수행합니다. 예상 부하에 근접했는지를 확인합니다. 대개는 그렇지 못합니다.

마지막으로 주의할 점은, 스트레스 테스트를 소프트웨어로 제한하지 마십시오. 물론 프로그래머로서 소프트웨어를 가장 고려한다는 것은 알고 있습니다. 하지만 상당히 우수한 알고리즘을 불명확한 모든 상황에서 즉시 사용할 수 없다면, 25센트짜리 퓨즈가 끊어지고 여분의 퓨즈가 없는 것처럼 이 프로그램은 쓸모가 없을 것입니다. 대부분의 프로그래머들은 하드웨어를 고려하지 않지만, 일부 프로그래머들은 고려합니다.

맨 위로


7. 상황에 맞추어 상태(state)를 적용
상태(Stateful) 및 비상태(Stateless) 구성 요소에 관한 논쟁으로 저자는 화가 났습니다. 어떤 사람은 COM+가 비상태를 강요한다고 말하고, 다른 사람은 사용자가 원하지 않으면 강요하지 않는다고 말합니다. 한 가지 사실을 확실히 하겠습니다. COM+는 개체를 비상태로 강요하지 않습니다. 모든 시스템의 트랜잭션 코드를 개발하는 사람들은 트랜잭션 개념(특히 격리 요구 사항)으로 인해서 개체 상태가 존재하는 위치를 주의해서 고려해야 합니다.

Figure 8 Turning on JIT Activation
그림 8 JIT 활성 설정

COM+에 있는 트랜잭션 구성 요소는 JIT 활성을 사용해야 합니다. 비트랜잭션 구성 요소는 원하지 않는 경우 이 활성을 사용할 필요가 없습니다. 그림 8과 같이 COM+ 카탈로그에 있는 적절한 설정을 선택하여 JIT 활성을 설정합니다. JIT 활성 동작이 그림 9에 나와 있습니다. 클라이언트가 JIT 개체를 만드는 경우, COM+는 클래식 COM에서와 마찬가지로 프록시, 채널 및 스텁을 만듭니다. 개체 트랜잭션이 완료되면 서버쪽의 실제 개체는 소멸되거나, 또는 이 문서의 팁10에서 설명된 것처럼 개체 풀에 저장됩니다. 프록시, 스텁 및 채널이 변경되지 않으므로 클라이언트는 개체 소멸 사실을 알지 못합니다.

Figure 9 JIT Activation
그림 9 JIT 활성

클라이언트가 개체를 다시 호출하는 경우, 운영 체제는 동일한 클래스의 새로운 개체를 만들고, 이 개체를 스텁에 첨부하고, 하단 예제처럼 이 개체를 호출합니다. 클라이언트로부터 두 번째 호출을 받는 개체는 클라이언트가 초기에 만든 개체가 아니라 개체의 다른 인스턴스입니다. 따라서 이 개체의 구성원 변수에는 처음 클라이언트 호출에 의해 생성된 어떠한 정보도 포함되어 있지 않습니다. 이 경우 사람들은 JIT 개체가 비상태라고 말합니다.

트랜잭션 격리에서는 이 점이 매우 중요합니다. COM+ 트랜잭션에 참여하는 개체는 트랜잭션의 커밋 또는 중단 여부를 절대로 알지 못합니다. 가령 COM+ 트랜잭션 데이터베이스에 저장된 사용자의 은행 계좌에 미화 1000달러의 잔고가 있고, 트랜잭션의 일환으로 한 개체가 미화 200달러를 계좌에서 인출했다고 가정합시다. 트랜잭션이 완료되면 개체는 잔고800달러를 구성원 변수에 기억합니다. 만약 트랜잭션이 커밋되었다면 이 잔고가 맞지만, 중단되었다면 잔고가 틀릴 것입니다. 사용자의 개체는 트랜잭션의 상태를 알 수 있지만 다른 트랜잭션 참가자의 상태를 알 수는 없으므로, 이 값이 유효 여부를 알지 못합니다. 잠재적인 무효 정보를 개체에게 제공하는 대신, JIT는 트랜잭션 격리를 유지하기 위해 개체를 소멸시킵니다.

개체가 소멸되더라도 사용자의 은행 잔고는 여전히 기본 데이터베이스에 존재합니다. 그리고 동작의 커밋 또는 중단 여부에 상관 없이 올바른 값을 가집니다. 이것이 바로 데이터베이스를 구입하고 트랜잭션을 사용하는 이유입니다. 이 가설 시스템의 개발자는 시스템을 신중하게 고려하고 설계했기 때문에, 모든 상태는 사라지는 것이 아니라 개체 구성원 변수가 아닌 다른 어딘가에 저장될 뿐입니다. COM이 상태 또는 비상태라고 주장하는 것이 무의미하다는 이유도 바로 이 때문입니다. 오히려 상태가 존재하고 존재해야 하는 위치를 신중하게 고려하는 것이 현명합니다.

이 개념은 새로운 것이 아닙니다. COM이 시작될 때부터 개체의 상태 및 동작은 다른 위치에 존재할 수 있습니다. 예를 들어, 세계 최초의 내장형 OLE 서버인 Microsoft Excel은 각 개체 상태를 개체 컨테이너의 문서 파일에 보관하고, 개체 동작을 Microsoft Excel 서버 .EXE에 보관합니다. 가령 편집 세션을 지원하기 위해서 클라이언트가 해당 클래스의 개체를 만드는 경우, Microsoft Excel은 문서 파일에 저장된 상태로부터 개체의 내부 상태를 초기화합니다. ActiveX 제어를 포함하는 HTML 페이지는 제어, 배경색 등의 상태를 HTML 페이지 상에서 보관하고, 생성을 제어하기 위해 상태를 제공합니다. 프로그래머가 비용 효율적이라고 결정한 장소에 상태를 보관합니다.

개체가 작업을 실행하는 데 사용하는 상태는 그림?10?과 같이 네 가지 종류의 다른 위치에 존재할 수 있습니다. 이 위치들의 특징은 서로 다릅니다. 첫째로, 상태가 클라이언트에 존재할 수 있고 메서드 호출에서 개체에 상태를 공급할 수 있습니다. 예를 들어, 은행 계좌를 조작하는 경우 클라이언트는 매개 변수를 통해서 계좌 번호 및 금액을 개체로 전달할 수 있습니다. 이 위치는 클라이언트에서 발생하는 상태에 적합합니다. 상태는 클라이언트가 필요로 하는 동안 존재할 수 있습니다.

둘째로, 상태는 개체의 구성원 변수에 존재할 수 있습니다. 쉽게 프로그래밍하고 액세스할 수 있지만, 트랜잭션이 지속되는 동안에만 상태가 존재합니다. 동일한 트랜잭션 내의 하나의 함수 호출로부터 다른 호출로의 상태를 저장하는 데 이 위치가 가장 적합합니다.

셋째로, 공유 등록 정보 관리자 또는 특별한 비트랜잭션 개체 클래스에 있는 정적 변수와 같은 특정 중앙 비트랜잭션 위치에 상태가 존재할 수 있습니다. 가령 은행 계좌 트랜잭션에 필요한 일련 번호를 생성하는 구성 요소를 원한다고 가정합시다. 특정 중앙 위치에서 생성된 마지막 일련 번호를 보관해서, 모든 트랜잭션이 이 번호를 액세스하도록 합니다. 데이터베이스보다 프로그래밍이 용이하지만, 일련 번호가 발급된 트랜잭션이 중단되는 경우 이 일련 번호를 재사용하지 않습니다.

마지막으로, 상태는 전체 리소스 관리자 데이터베이스에 존재할 수 있습니다. 프로그래밍이 어렵고 실행 속도가 느리지만, 어떤 경우에도 상태가 일관적으로 존재합니다. 상태가 존재할 수 있는 위치는 여러 가지가 있으며, 각 위치는 여러 장점과 단점을 가지고 있습니다. 개체 상태를 저장하기 위한 가장 적합한 위치는 사용자에게 달려 있습니다.

여기서 다음과 같은 질문을 할 수 있습니다. 개체의 상태 및 동작을 결합하는 것이 개체의 근본적인 특성입니까? 이 두 가지를 분리하지 않으면 더 이상 개체 프로그래밍이 아닙니까? 개체를 사용한 프로그래밍은 좋은 것입니까? 이와 같은 어려운 질문으로 괴롭히지 마십시오.

맨 위로


8. 네트워크로 전송되는 모든 것은 종류에 상관없이 반드시 암호화
단일 데스크톱 PC에서는 보안에 대한 문제가 발생하지 않습니다. PC 본체나 이동식 미디어가 물리적으로 보호되어 있다면, 대규모 NSA 공격에 미치지 못하는 모든 문제들로부터 비교적 안전합니다. 하지만 데이터를 네트워크 상으로 전달하는 경우에는 문제가 전혀 달라집니다. (실제로는 거의 불가능하지만) 모든 네트워크 배선의 보안을 확보할 수 없다면, 사용자가 네트워크에 올린 임의의 자료가 내일자 USA Today 또는 컨텐트에 따라서 The National Enquirer의 일면에 오를 수도 있습니다.

최근 저는 병원 진료실에서 기다리다가 벽에 있는 이더넷 포트를 보았습니다. 앞에는 다른 한 명의 고객이 있었고, 가방에는 네트워크 동글과 네트워크 감시 프로그램이 있는 노트북 PC가 있었습니다. 저자는 속으로 “도대체 이 병원에서 사용하는 암호 체계는 무엇일까?”라고 생각했습니다. 사실 특별한 일은 아니고 누구든지 그렇듯이 병원은 데이터 회선을 물리적으로 보호하지 않았기 때문에, 네트워크에서 전달되는 모든 패킷을 기록할 수 있었을 것입니다. 이 네트워크는 대형 대학 부속 병원에서 사용하는 것이었습니다. 데이터 회선이 암호화되어 있지 않다면 모든 패킷을 읽을 수 있을 것입니다. 만약 제가 몸이 조금만 덜 아팠거나 마음을 잘못 먹었다면, 아마 패킷을 읽었을 것입니다.

의료 기관은 프라이버시에 관해 집착하고 있습니다. 예를 들어, 환자의 이름을 다른 환자에게 알리지 않기 위해 일부 접수 직원은 이름 대신 번호를 사용하여 대기실의 환자를 호명합니다. 하지만 뒷문은 활짝 열린 상태에서 앞문만 잠그는 것은 상당히 어리석은 짓입니다. 어느 정도 똑똑한 사람들은 병원 전체에서 전송되는 모든 네트워크 패킷을 가로챌 수 있습니다. 네트워크 패킷을 기록하기 위해 더 이상 PC가 필요하지 않으며, 중형 핸드헬드 PC를 사용하여 기록할 수 있습니다. 상당수의 사람들이 이와 같은 장치를 지니고 다닙니다. 따라서 이 장치를 찾기 위해 모든 환자의 몸을 수색하지 않으려는 병원들은 모든 데이터를 항상 암호화해야 합니다.

프로젝트에도 사용자가 깨닫지 못하는 동일한 문제가 존재합니다. 모든 데이터는 중요합니다. 누군가가 특정 비행기에 탑승했는지 항공사 직원에게 물어 보십시오. 이 데이터는 사적이기 때문에 직원은 대답하지 않을 것입니다. 외부인으로부터 데이터를 보호하는 하는 것은 이 뿐만이 아닙니다. 동료의 봉급 및 고과 평가는 어떻습니까? 화난 상태에서 작성했지만 아직 제출하지 못한 사직서는 어떻습니까? 다시 말하지만 모든 데이터는 중요합니다.

데이터를 보호할 수 있는 방법은 무엇입니까? COM+ 응용 프로그램을 사용하면 상당히 간단합니다. 각 COM+ 응용 프로그램은 인증 수준이라는 것을 설정합니다. 이 관리 설정은 사용자가 실제 사용자인지를 결정하고, 사용자가 보낸 데이터의 훼손 또는 도청 여부를 결정하기 위한 수준을 컴퓨터에 알려 줍니다. 그림 11에 나타난 것처럼, COM+ 탐색기에서 인증 수준을 설정합니다. 다른 수준의 인증이 그림?12?에 요약되어 있습니다.

Figure 11 Setting Authentication Level
그림 11 인증 수준 설정

또한 패킷 프라이버시가 필요합니다. 패킷 프라이버시는 응용 프로그램이 네트워크를 통해서 보내는 모든 것을 자동으로 암호화합니다. 단 한번의 마우스 클릭으로 패킷 프라이버시를 사용할 수 있는데도 실제 환경에서 사용하지 않으면 업무 과실에 해당합니다. 당신은 증인대에 앉아서 “말해 주십시오, Jones씨. 인증 수준을 패킷 프라이버시로 설정하지 않은 이유가 무엇입니까? 당신은 David Platt의 기사를 읽으셨죠? 당신이 마우스를 늦게 눌러서 고객의 재산을 날리도록 선택한 이유가 무엇입니까?”라고 말하는 원고측 변호사의 대질 심문을 받기를 원하십니까?

패킷 프라이버시의 주요 단점은 암호화를 수행하지 않은 다른 수준보다 속도가 느리다는 점입니다. 기본적으로 패킷 프라이버시는 회선으로 보내지는 데이터를 암호화하기 위해 소프트웨어를 사용합니다. 부동 소수점 연산 및 비디오 조작을 위해 전용 암호화 하드웨어를 사용하면 훨씬 속도가 빨라질 것입니다. 다행히도 이와 같은 하드웨어들은 저렴한 비용으로 즉시 구할 수 있습니다. 암호화 네트워크 카드에는 Windows 2000에서 동작하는 온보드 프로세서가 내장되어 있어서, 암호화 작업을 위한 주 CPU의 부하를 줄여 줍니다. 이 카드들은 약 미화 100달러로 저렴합니다. 또한 Windows 2000의 강력한 소프트웨어 암호화 버전을 구입할 수 없는 미국 이외의 회사들에게 이 방법은 우수한 솔루션입니다. 대개 이 회사들은 외국에서 생산된 암호화 네트워크 카드를 비교적 저렴한 비용으로 구입할 수 있습니다. 사용이 쉽고 가격이 저렴하므로, 구입하지 않으면 후회하실 것입니다.

9. 시간 및 순서의 종속 관계 피하기
COM+ 대기 구성 요소(QC)는 비동기식 통신용 Microsoft Message Queue Service(MSMQ)에서 간편하고 편리하게 COM을 사용할 수 있는 방법입니다.
QC가 여러 상황에서 편리하고 유용하기는 하지만, 이 제품의 설계 목적이나 용도에 적합하지 않는 곳에 사용하다가 문제를 겪는 클라이언트를 많이 보게 됩니다. 프로그래머의 입장에서 보면 이것은 기존의 COM과 거의 같아 보이기 때문에 기존의 동기식 COM처럼 설계합니다.
QC로 설계할 때 염두에 두어야 할 주요 사항은 서버가 언제 클라이언트측 레코더에서 전송된 일련의 호출을 처리하게 되는지 알지 못한다는 것입니다. 그것을 COM 호출용 전자 메일이라고 합시다. 수신자가 여러분이 보낸 메시지를 언제 읽을지, 또는 언제 메시지에 응답할지 모르기 때문에, 서버가 대기열에서 벗어나 기록된 COM 호출을 재생하는 시기도 알 수 없습니다. 여러분의 업무에 차질이 없도록 빨리 진행되기를 바라지만, 확실히 알 수 있는 방법은 없습니다. 그러므로 이러한 제한 사항을 염두에 두고 설계해야 합니다.
예를 들어, 한 클라이언트가 어떤 물건을 일정 가격에, 정해진 기한 내에 구입하겠다는 제안서를 담은 일련의 호출을 보낸다고 가정해 봅시다. 만기 시점이 문제가 되는 경우, 이를 개체의 비즈니스 로직에 작성하여 "GoodUntil" 속성을 만들어야 합니다. 이 속성을 점검하기 위해 서버 처리 로직을 작성한 후, 제안서가 시간상 아직 유효한 경우에만 구입 절차를 진행하십시오. 그렇지 않은 경우, 서버는 사실을 기록하고 시간의 경과에 따른 메시지 손상률을 추적할 수 있습니다. 클라이언트가 다음 작업으로 이동하기 전에 반드시 서버에서 응답을 받아야 할 경우, QC와 MSMQ는 적절한 접근 방법이 아닙니다. 이 경우에는 대신 동기식 DCOM을 사용해야 합니다.
마찬가지로, 기록된 QC 호출 패킷이 서버에서 어떤 순서로 처리될 것인지 알 수 없습니다. 우선, 이들은 MSMQ 네트워크의 여러 부분에 있는 여러 클라이언트에서 나올 수 있기 때문에 메시지가 서버에 도착하는 순서조차도 알 수 없습니다. 다시 전자 메일을 생각해 봅시다. 여러 메시지가 여러 경로를 택할 수 있고 실제 그런 경우가 많습니다. 먼저 보낸 메시지가 보류되어 있고 나중에 보낸 메시지가 다른 경로를 통해 더 빨리 도착하는 경우도 드물지 않습니다.
메시지가 서버쪽에 도착한 경우에도 처리에 일정한 순서를 부여하기란 매우 어렵습니다. 메시지는 대기열에 도착한 순서대로 MSMQ의 대기열에서 처리됩니다. 그러나 QC 재생 서비스는 멀티스레드 방식으로 이루어져 보통 사용자들의 관심사인 처리량을 늘릴 수 있게 되어 있습니다. 메시지가 대기열에서 빠져 나오면 각 스레드 실행에 영향을 줄 수 있습니다. 첫 번째로 대기열에서 나온 메시지 처리는 데이터베이스 검색 시간이 오래 걸려 늦어지고, 두 번째로 나온 메시지는 그렇지 않을 수도 있습니다. 이 때 두 번째 메시지는 아주 쉽게 처리가 시작되고, 첫 번째 메시지 처리가 완료되기 전에 끝날 수 있습니다. QC 개체를 설계할 때 이 점을 고려하지 않으면 안됩니다. 기본적으로, 각 구성 요소를 따로 설계하여 이 요소가 주어진 클라이언트 세션이 다른 QC 개체에 종속되지 않고 독립적으로 작용하도록 해야 합니다.
순서 종속 관계는 QC를 COM+가 느슨하게 연결된 이벤트 시스템과 결합할 때 특히 눈에 띄지 않게 됩니다. 이벤트의 발생은 순서와 관련이 있게 마련입니다. 즉, "자, 이번엔 이게 실행되고 그 다음엔 그 다음 것이 실행됩니다." 이런 식으로 말입니다. DCOM과 같은 동기식 전달 방식에서는 이러한 논리가 완벽하게 통합니다. 그러나 QC의 경우, 들어온 이벤트가 처리되는 순서와 이들이 실제 실행되는 순서가 일치한다고 확신할 수 없습니다. 제가 자주 사용하는 예는, 병원에서 사망한 환자를 검색하는 Handheld PC를 사용하는 간호사입니다. 간호사가 전송할 QC 이벤트를 생성하는 버튼을 누르고, 330호실 환자가 사망했다고 알립니다. 그 후 330호실에는 신규 환자가 배당되고, 병원 통계 조사 응용 프로그램은 QC 이벤트를 보내 이 사실을 알립니다. 만일 정보 전달 순서가 바뀌어 영안실 조수가 이 사건의 순서를 반대로 알게 된다면 좀 골치 아픈 상황이 발생하겠죠.

맨 위로


10. 속도 향상을 위한 개체 풀링 사용
승리한 팀의 라커룸은 항상 즐거운 분위기입니다. 제가 이 기사와 다음에 쓸 책의 자료를 구하기 위해 3월에 Microsoft를 방문했을 때, COM+ 팀은 여전히 최신 트랜잭션 처리량 벤치마크에서 나온 최고 기록을 자축하고 있는 분위기였습니다. 비영리 단체인 'Transaction Processing Performance Council'은 이러한 벤치마크를 개발하여 실행 결과를 정기적으로 게시합니다. 이 웹 사이트 주소는 http://www.tpc.org/?입니다.
2000년 2월, Microsoft는 Microsoft SQL Server™ 와 COM+로 아주 강력한 Compaq 서버에서 Windows 2000을 실행하여 분 당 227,000건의 트랜잭션을 처리했습니다. 이와 가장 근사한 경쟁은 IBM/Oracle이 거의 두 배의 비용을 들인 시스템에서 분 당 136,000건의 트랜잭션을 처리한 것이었습니다. 10월에 Microsoft와 Compaq은 초 당 50,000건 이상의 트랜잭션을 자랑하는 새로운 TPC-C 테스트 결과를 제출한 바 있습니다.

COM+ 팀원들은 그들이 어떻게 그런 속도를 낼 수 있었는지 설명해 주었습니다. 즉, 매번 연결을 열었다 닫았다 하는 대신, 개체 풀링을 사용하여 데이터베이스 연결을 재생했다는 것입니다. 여러분의 응용 프로그램도 이 기술을 사용하여 성능을 개선할수 있습니다. 그러나 특정 환경에서만 가능하므로, 이 기술을 활용하는 방법은 주의 깊게 생각해 보아야 할 것입니다.

Figure 13 Enabling JIT Activation
그림 13 JIT 활성화 사용

그림 13에 나타난 대로 Component Services Explorer의 상자에 확인 표시하여 구성 요소를 풀링된 것으로 표시합니다. 응용 프로그램이 시작되면, COM+는 최소치로 지정한 수만큼 개체를 생성하여 풀에 가져다 놓습니다. 클라이언트가 특정 클래스의 개체를 생성하면 COM+는 새 개체를 다시 만들지 않고, 풀에 저장된 개체를 가져옵니다. 클라이언트는 규정된 최소치보다 많은 개체를 만들기 때문에, COM+는 규정된 최대치까지 새 개체를 만듭니다. 클라이언트가 개체를 릴리스했거나 JIT 활성화되어 개체가 서버측에 릴리스되면 COM+는 개체를 파괴하지 않고 풀로 반환합니다. 그림 14는 개체 풀링 통계를 표시하는 Component Services Explorer를 보여줍니다.

Figure 14 Pooling Stats in Component Services Explorer
그림 14 Component Services Explorer의 풀링 통계

개체 풀링이 개체 생성 오버헤드를 줄일 수 있기 때문에 속도가 빠르다고 생각할 수도 있지만, 실제로는 그렇지 않습니다. 저는 풀링 구성과 비풀링 구성 모두에서 단순한 ATL 개체로 벤치마크를 실행해 보았지만, 생성 시간과 풀에서 가져오는 데 걸리는 시간은 차이가 없었습니다. 개체가 값비싼 방식으로 자체를 초기화하면 시간이 절약되며, 그 결과를 클라이언트에 다시 사용할 수 있습니다. 예를 들어, 한 개체는 지난 주에 체결된 외국환 거래에 대한 전체 목록을 읽고 의사 결정 기능을 지원해야 합니다. 또는 보안 목적으로 값비싼 인증을 필요로 하는 데이터베이스와 같은 외부 리소스에 연결해야 할 수도 있습니다(팁 3 참조). 그러나 재사용하는 정보에는 트랜잭션 격리를 끊을 수 있는 것이 없으므로 주의해야 합니다.
풀링할 구성 요소는 이 환경에서 성공적으로 실행되도록 개발되어야 합니다. 가장 중요한 규칙은 이것은 스레드와 관계가 없다는 점 즉, 어떤 스레드로 호출을 받는지에 대해 영향을 받지 않는다는 것입니다. 이것은 상관 없습니다. 왜냐하면 당신은 어쨌든 팁 4에 설명된 대로 하고 싶으실 테니까요. 풀링된 구성 요소는 풀 관리자가 사용하는 관리 정보를 담고 있는 인터페이스와 집계될 것이므로 집계를 지원해야 합니다. 풀링된 구성 요소는 또한 스레드가 없는 마샬러를 사용해서는 안됩니다.
풀링된 구성 요소는 보통 Activate, Deactivate, CanBePooled 메서드가 있는 IObjectControl 인터페이스를 지원하려고 합니다. COM+는 이 인터페이스를 쿼리하고 해당 메서드를 호출하여 풀링된 개체에게 수명 기간 동안 중요한 이벤트를 알려줍니다. COM+는 풀에서 개체를 가져와서 컨텍스트에 할당할 때 Activate 메서드를 호출합니다. 개체는 이 메서드를 사용하여 예를 들면, 자체 회원 변수를 기본값으로 설정하는 등, 개체가 지정한 모든 종류의 클라이언트 지정 초기화 작업을 수행할 수 있습니다. 이것은 또한 개체가 해당 컨텍스트를 획득해야 하는 첫 번째 기회로, 많은 개체들이 이 시점에서 컨텍스트를 가져와서 로컬로 저장합니다. COM+는 개체를 풀에 다시 놓으려 할 때 CanBePooled 메서드를 호출합니다. 개체가 재생되어 개체 풀로 되돌아갈 수 있으면 TRUE가 되고, 심하게 손상되어 버려야 하는 경우는 FALSE가 됩니다. COM+는 개체를 파괴하든지 풀로 돌려 보내든지 개체 세션이 종료될 때 Deactivate 메서드를 호출합니다. 이 때가 개체가 획득한 클라이언트 지정 리소스를 릴리스할 수 있는 기회입니다.

맨 위로


결론
COM+는 지금까지 PC 플랫폼에서 구축된 가장 강력한 런타임 환경입니다. 강력한 모든 도구가 그렇듯, COM+도 최고의 성능을 발휘하려면 세심한 주의가 필요합니다. 지금까지 실전 현장의 연구자들에게 배운 몇 가지 팁과 사용법에 대해 정리해 보았습니다. 도움이 될 수 있기를 바랍니다.
많은 정보를 제공해 주신 COM+ 팀의 Dick Dievendorff와 Joe Long에게 감사의 말을 전합니다.


배경 정보:
David Platt의 Understanding COM+(Microsoft Press, 1999)


David S. Platt은 Rolling Thunder Computing의 사장이자 창설자입니다. 그는 하버드 대학과 전세계 기업을 대상으로 COM과 COM+를 가르치고 있으며, http://www.rollthunder.com/?에 COM+에 관한 무료 전자 메일 뉴스레터를 게재하고 있습니다. 또한 Understanding COM+(Microsoft Press, 1999)의 저자이기도 합니다.

? 최종수정일: 2004년 6월 23일

Top of Page Top of Page


Microsoft