COM, ATL

분산객체 시스템(COM,COm+,DCOM,MTS) 에 대한 개념-1

디버그정 2008. 7. 28. 13:58
분산객체 시스템(COM,COm+,DCOM,MTS) 에 대한 개념-1 MTS

2004/12/14 12:36

복사 http://blog.naver.com/saga111/120008481340

윈도우의 분산객체 기술은 지난 92년 OLE 기술이 소개된 이후 끊임없이 발전해 COM, DCOM 환경이 개발됐으며 현재의 COM+ 환경에 다달았다. COM+는 3티어 모델 기반의 분산 환경에서 비즈니스 로직 처리 부분을 완전히 분리시켜 개발, 실행할 수 있는 미들웨어(MTS, MSMQ)를 공급함으로써 보다 쉽고 편리하게 윈도우 분산 환경을 구축할 수 있는 지름길을 제시하고 았다.

김경현 아이메카 분산객체 시스템 연구실
--------------------------------------------------------------------------------
지난 수년동안 소프트웨어 개발 방법은 크게 변화하지 않았다. 대다수 소프트웨어 개발 작업은 시간과 비용에 얽매여 있었으며,
개발된 소프트웨어는 종종 수많은 버그와 유지보수의 문제로 어려움을 겪곤 했다. 지금까지 플로우 차트에서 객체 지향까지
수많은 개발 방법론이 제시됐으며, 그 중 일부는 마치 만병통치약인 것처럼 받아들여지기도 했다. 아마 이러한 방법론이 정말
뛰어난 해결책이었다면 소프트웨어 개발만큼이나 쉬운 일이 없을지도 모른다. 하지만 오늘날 역시 예전과 별반 차이없이 동일한
고민에 시달리고 있다. 플로우 차트 혹은 객체 지향 방법론이 무용지물이라는 얘기는 아니다. 이러한 개념으로 인해 보다
견고한 소프트웨어를 보다 빠르게 개발할 수 있는 건 사실이지만, 날이 갈수록 복잡해지는 컴퓨팅 환경 전부를 지원하기에는
역부족이라는 얘기다. 하나의 해결책이 모든 컴퓨팅 환경을 완벽하게 해결할 수 있는 상황은 지났다는 것.
이젠 모든 다양한 해결책을 잘 융화시켜 복잡한 문제 해결에 어떻게 적용시켜야 하는지에 대해 고민할 시기다.

하나의 솔루션이 모든 것을 해결해 준다?

객체 지향 소프트웨어 개발의 기본 개념은 모든 문제를 객체와 객체가 수행할 수 있는 행동으로 표현한다는데 있다.
이러한 객체를 보다 구체적으로 표현하기 위한 방법으로 클래스를 정의했으며, 클래스에서는 객체의 상태를 프로퍼티로
표현하고, 객체의 행동은 메쏘드로 표현한다.
객체를 사용하는 클라이언트는 클래스의 각 메쏘드와 프로퍼티가 어떻게 구현되었는지는 전혀 관심이 없으며 클래스가
어떠한 역할을 수행하는지에 대해서만 관심을 가진다(Encapsulation).

클래스를 설계하다 보면 수많은 프로퍼티와 메쏘드가 존재하고, 이들을 정리할 목적으로 인터페이스라는 것이 고안됐다.
인터페이스는 의미상 유사한 메쏘드, 프로퍼티의 집합으로 실제 구현에는 관여하지 않는다.
인터페이스 역시 클래스를 통해 표현되며, 소프트웨어 재사용성을 높여준다.
한 예로 두 개의 전혀 다른 클래스 A와 B가 있다.
이들은 각각 동일한 인터페이스인 ICommon 인터페이스를 클라이언트에 제공한다.
클라이언트는 자신이 서비스 받고자 하는 통로로 ICommon 인터페이스를 사용할 뿐이지 클래스 A, B에 대해서는
전혀 알 필요가 없다.
이러한 것을 객체 지향 용어로 동질 다형(Poly morphism)이라고 한다.
재사용성을 높이는 또 다른 방법으로 상속(Inheritance)을 얘기할 수 있다.
하나의 클래스는 기존 다른 클래스의 프로퍼티와 메쏘드를 상속받아 변경, 확장 등으로 기존 클래스를 재사용할 수 있다.

C++와 자바와 같은 객체 지향 언어는 이와 같은 특성을 지닌 클래스와 인터페이스를 구현하는 데 많은 이점을
제공하지만 대규모 분산 애플리케이션을 개발하는 데는 다소 적절하지 못하다. 프로그래밍 언어는 일반적으로
하나의 프로세스, 하나의 동일 언어로 작성된 애플리케이션을 개발하는 데에 그 기능의 초점이 맞춰져 있으므로
다양한 환경이 복합적으로 결합돼 있는 분산 환경을 지원하는데는 한계가 따른다. 이러한 문제를 해결하기 위해
언어 수준이 아닌 시스템 수준의 새로운 모델 COM이 개발됐다. COM은 객체 그 자체와 객체들 간의 통신 메커니즘을
제공하는 바이너리 표준을 정의한다. 객체와 클라이언트간의 모든 통신은 인터페이스를 통해 이뤄지며,
그 통신이 같은 컴퓨터 내에서든지 원격 컴퓨터에서든지 프로그래밍 언어에서는 관계없이 객체의 메쏘드 호출로
동일하게 표현한다. 또한 바이너리 수준의 표준이어서 프로그래밍 언어에 중립적이므로 어떠한 언어를 사용해도
개발이 가능하며 다른 언어로 개발된 컴포넌트를 서로 참조할 수 있다.

오늘날 소프트웨어 애플리케이션은 나날이 덩치가 커지고 복잡해지고 있으며, 네트워크 환경과 융합돼 있고,
서로 이질적인 다양한 시스템과 연동되어 작동한다. 그렇다면 COM이 이런 복잡한 컴퓨팅 환경을 훌륭하게
지원하는 해결책일까? 하나의 아이디어만으로 이 모든 문제를 풀기에는 이미 너무나 복잡해져 있다.
그래서 마이크로소프트는 COM과 마이크로소프트 트랜잭션 서버(MTS)의 조합을 기반으로 한 COM+라는 환경을
새로운 해결책으로 제시하고 있다.

COM+의 두 가지 기능

현재의 COM+는 크게 두 가지 기능을 제공한다. 하나는 기존의 COM이 정의한 프로그래밍 환경이고, 다른 하나는
분산 애플리케이션 구축을 위해 다양한 실행 환경(run-time environment)을 제공하는 컴포넌트 서비스다.
대규모 중요한 시스템에서는 데이터베이스를 포함하는 복잡한 작업 수행시 클라이언트 오류를 감지해 적절히
대처할 수 있어야 한다. 트랜잭션에 대한 어떠한 보장도 없이 데이터를 처리하는 도중에 오류가 발생했다면
데이터의 일치성은 전혀 보장받을 수 없을 것이다. 데이터 일치성을 보장받기 위해 개발자가 직접 복잡한 단계마다
트랜잭션 처리를 위해 일일이 코딩 작업을 해야한다. 이렇듯 컴포넌트 소프트웨어 기본 모델의 가장 큰 문제점은
다양한 비즈니스 로직 처리와 같은 애플리케이션의 기본적인 기능 구현보다 안정성, 확장성 등의 부가적인 작업에
훨씬 많은 에너지를 소모한다는 것이다.

마이크로소프트는 이러한 사실을 직시하고 소프트웨어 컴포넌트를 위한 쓰레딩, 동시성 보장, 보안, 관리,
견고함 등을 지원하기 위해 윈도우 기반의 실행 환경으로 MTS를 개발했다. COM+에서 제공되는 실행 환경은 MTS 실행
환경을 그대로 이어 받고 있으며, 서버 시스템 개발자가 직면한 다양한 문제를 해결하며, 애플리케이션 본연의
업무에 충실할 수 있도록 만들어 준다.

마이크로소프트는 지난 수년간 분산 환경을 지원하고자 DCOM, MTS, MSMQ와 같은 기본 프로그래밍 환경을 제공해 왔으며,
현재 이 모든 것을 윈도우 2000에 통합시켜 COM+라는 통합된 분산 개발 환경을 제공한다. 이미 우리는 COM에 대해선
너무 많은 것을 들어 왔으므로 COM에 대한 설명은 가능한 줄이고, COM+ 환경을 구축하는 각각의 컴포넌트 서비스를
중심으로 설명을 진행할 것이다.

사회의 다른 모든 분야와 마찬가지로 시간이 흐를수록 컴퓨팅 환경 역시 점점 복잡해지고 있다. 개인용 데스크톱
환경만 돌아보더라도 이 사실을 쉽게 알 수 있다. 국내에 IBM PC가 처음 소개되던 80년대 후반과 펜티엄 컴퓨터가
세상을 주름잡고 있는 현재를 비교해보자. 과거에 PC는 퍼스널 컴퓨터라는 이름 그대로 개인용 애플리케이션 수행을
주목적으로 하였으나, 현재는 PC 서버라는 용어를 사용할 정도로 서비스 제공자의 기능을 충분히 제공할 만큼
고성능화 되었다.

마이크로소프트 컴포넌트 서비스

CPU 클럭 스피드의 향상 못지 않게 소프트웨어도 많은 변화가 있었다. 웹의 등장으로 인터넷이라는 네트워크와
웹 서버라는 용어가 심심지 않게 등장하고 있으며, 단순한 HTML 문서를 보여주던 시스템에서 이제는 복잡한 기업용
업무 처리 시스템까지 그 영역을 넓혔다. 사용자 입장에서는 화려해진 화면과 다양한 기능을 제공하는 웹 환경의
발전에 흐뭇해할지 모르겠지만, 개발자는 나날이 피곤해지고 있다. PC에서 한 명의 사용자를 위해 수행하는 간단한
소프트웨어를 개발하다가 이제는 동시에 수천, 수만명 접속자가 요구하는 사항을 빠르고 안정적으로 처리해야하는
복잡한 서버 소프트웨어를 개발해야 한다. 필자 역시 마찬가지로 현재는 네트워크에서 수행되는 복잡한 서버 군을
개발하고 있다.

그렇다면 서버를 개발하는 데 있어 가장 큰 문제점은 무엇일까? 필자의 경험에 비춰보면 효율적이고 안정적인
네트워크 서버를 개발하는 작업은 정말 힘든 작업이다. 수십 명의 동시 접속자에서부터 수천 명의 동시 접속자를
원할히 처리하기 위해 쓰레드 풀을 이용한 대칭형 멀티 프로세서 지원은 기본이며, 서버의 자원을 최대한 효율적으로
사용하기 위해 독립적인 리소스 관리자도 개발했고, 디스크 입출력 최적화를 위한 다양한 캐시도 구현했었다.

서버 애플리케이션을 개발할 때마다 이런 기본적인 항목을 모두 구현해야 한다면 정말 보통 일이 아닐 것이다.
클라이언트가 필요로 하는 서버 애플리케이션의 기본 기능보다 기타의 부가적인 시스템 기능을 위해 훨씬 더 많은
시간이 투입될지도 모른다. 배보다 배꼽이 크다라는 말이 꼭 들어맞는 상황이다.

다음에 소개하는 몇 가지 서비스를 읽어보면, 어쩌면 서버 애플리케이션 개발 작업이 간단한 데스크톱 애플리케이션을
개발하는 것만큼 쉽다는 생각이 들지도 모르겠다. 배꼽이 훨씬 작은 정상적인 상황이다.

COM과 DCOM

비주얼 베이직과 같은 RAD 툴이 처음으로 선보였을 때를 생각해보자. ‘어려운 윈도우 프로그래밍이 이렇게 간단하게
만들어질 수도 있구나’라고 감탄사를 연발했었다. 윈도우를 만들기 위해 복잡한 CreateWindow라는 API를 호출할
필요도 없고, 그저 마우스 드래그 앤 드롭으로 윈도우 디자인에만 신경쓰며 단지 버튼 클릭, 메뉴 선택과 같은
이벤트 발생시 수행할 일에 초점을 맞춰 개발할 수 있었다. 게다가 필요한 모든 기능을 일일이 개발자 스스로가
만들 필요도 없고, 대신 자료실에 그러한 기능을 하는 모듈이 있는지 찾는데 집중하는 것이 소프트웨어 생산성 향상
측면에서나 개발자의 스트레스를 줄이는 측면에서 훨씬 득이 됐다.

하지만 늘 그렇듯이 눈 높은 소비자들은 다수의 사용자를 동시에 지원할 수 있고, 복잡한 데이터베이스를 쉽게
액세스할 수 있으며, 또한 한 대도 아닌 여러 대의 컴퓨터를 동시에 사용할 수 있기를 바랐다. 수요가 있으면 공급이
따르는 법, 복잡한 요구 사항에 적절히 대응하기 위해 소프트웨어 컴포넌트라는 새로운 개념이 도입됐다. 컴포넌트는
특별한 기능을 수행하는 독립적인 소프트웨어 조각이라고 볼 수 있으며, 어떠한 다른 프로그램에서도 쉽게 이를 사용할
수 있고, 쉽게 수정 가능하며, 배포될 수 있어야 한다. 이를 위해서는 표준화된 어떠한 방법론이 필요했으며,
마이크로소프트는 컴포넌트 오브젝트 모델(COM)이라는 소프트웨어 컴포넌트 사용을 위한 표준을 만들었다.

COM은 윈도우 환경에서 수행되며 바이너리 코드 레벨에서 호환 가능한 소프트웨어 컴포넌트 생성에 대한 기술이다.
따라서 COM은 프로그래밍 언어가 아니며 소스 코드 레벨의 라이브러리 역시 아니며, 컴파일러는 더더욱 아니다.
대신 바이너리 코드의 호환 표준이므로 프로그래밍 언어, 각종 개발 툴에 완전히 독립적인 소프트웨어 조각이다.

초기의 COM은 하나의 컴퓨터에서 수행되는 애플리케이션의 부품으로 사용했으나, 분산 컴퓨팅 환경의 비약적인
발전과 더불어 COM 역시 DCOM(Distributed COM)이라는 이름을 달고 지난 96년에 시장에 출현했다. DCOM은 COM과 그
기능이 매우 흡사하나 애플리케이션이 수행되는 컴퓨터가 아닌 다른 컴퓨터(물론 둘 사이에는 네트워크라는 고리가
물려 있어야 한다)에서 독립적으로 수행 가능하다는 놀라운 기능을 제공한다. 또한 윈도우 환경을 넘어서 유닉스,
IBM 메인 프레임에서도 수행 가능해 ERP, 뱅킹, 의료정보 시스템과 같은 대규모 비즈니스 시스템에 널리 사용하고 있다.

마이크로소프트 트랙잭션 서버

마이크로소프트는 엔터프라이즈급 규모로 확장 가능한 서버 애플리케이션 개발 환경을 지원하기 위해 마이크로소프트
트랜잭션 서버(MTS)를 지난 96년에 내놓았다. MTS는 COM과 DCOM으로 개발된 기업용 애플리케이션 시스템을 위한 실행
환경으로 분산 컴퓨팅 환경 에서 안정적이고, 확장 가능하며 트랜잭션을 지원한다.

트랜잭션 서버라는 명칭 때문에 어렵게 받아들일 수도 있지만 한 걸음 물러나서 보면 아주 간단한 시스템으로 생각할
수도 있다. MTS 기반의 모든 애플리케이션은 COM 컴포넌트의 집합으로 이뤄져 있으며, 이를 사용하는 클라이언트는
DCOM을 사용해 원격지에서 MTS 애플리케이션을 사용한다. 즉 마이크로소프트의 기반 기술인 COM/DCOM을 보다
효율적이고 안정적으로 사용 가능하게 만들어 주는 통합 환경으로 생각하면 된다.

IIS와 ASP

인터넷 인포메이션 서버(IIS)가 왜 마이크로소프트 컴포넌트 서비스의 하나로 언급되는지 의아해 하는 독자가 있을지도
모르지만, 인터넷 인포메이션 서버는 엄연히 중요한 컴포넌트 서비스다. 인터넷 인포메이션 서버는 기본적인 웹
서버 기능, HTTP, SSL(Secure Sockets Layer), CGI(Common Gateway Interface)를 지원할 뿐 아니라
ASP(Active Server Page)라는 컴포넌트 기반의 스크립트 언어를 지원한다. ASP에서는 다양한 종류의 COM 컴포넌트를
액세스할 수 있으며, MTS 애플리케이션도 쉽게 사용할 수 있다.

마이크로소프트 메시지 큐

DCOM은 RPC(Remote Procedure Call)를 통해 원격지에서 COM을 사용한다. 하지만 클라이언트 서버간에 동기화된
통신을 사용하므로 다수의 분산 애플리케이션 환경에는 다소 부적절하다. 분산 환경에서는 메시지 큐를 사용한
넌-블럭킹 모드의 비동기 통신이 종종 필요하다. 이러한 기능을 제공하는 것이 MSMQ 서버다. 애플리케이션은
메시지를 다른 애플리케이션에 보내지만 그에 대한 응답을 기다리지 않는다. 보낸 메시지는 MSMQ 서버의 큐에
저장되며 메시지를 받을 애플리케이션이 메시지를 받은 후 삭제할 때까지 계속 유지한다. 만일 보낸 메시지에
대한 응답이 필요할 경우 메시지를 보낸 애플리케이션은 남는 시간에 MSMQ 서버의 큐를 검사해 응답 유무를
확인할 수 있다. 네트워킹 오류와 같은 여러 예상치 못한 상황이 빈번한 분산 환경 하에서 이와 같은 비동기 메시지
전송은 전체적인 시스템 안정성 및 효율성 향상을 위해 반드시 필요하다.

MSMQ 역시 컴포넌트 서비스이므로 COM과 분리시켜 설명하긴 어렵다. COM 인터페이스가 제공하는 다양한 메쏘드 및
프로퍼티 호출은 MSMQ의 메시지로 표현되므로 ASP 스크립트, MTS 애플리케이션과 연동해서 훌륭하게 작동된다.

간단한 예제

이상에서 소개한 마이크로소프트 컴포넌트 서비스를 한 눈에 알아볼 수 있는 분산 컴퓨팅 시스템 예제를 살펴보자.
다음 그림은 B2C 전자상거래 사이트 시스템 구성도이다. 여기에서 주문을 내는 경우 각각의 IIS, ASP, MTS, MSMQ,
DCOM이 어떻게 연동돼 사용되는지 알아보자.

이 시스템의 가장 핵심적인 부분은 주문서를 작성하고, 실제 주문을 처리하는 비즈니스 로직을 구현한 COM 컴포넌트로
내부적으로는 데이터베이스를 액세스해 재고를 검사하고 주문을 내고 발송하는 모든 실제적인 일을 수행한다.
또한 이들 컴포넌트는 동시에 수많은 주문을 처리할 수 있어야 하므로 MTS 환경에서 수행시킨다. MTS 환경은 동시에
여러 트랜잭션 처리를 가능케 하며, 확장성과 안정성을 제공한다.

주문이 완료되면 주문 처리 컴포넌트는 창고로 주문에 대한 포장과 발송을 위한 메시지를 보낸다. 주문 처리 컴포넌트는
포장과 발송에 대한 완료 여부를 알 필요가 없으므로 MSMQ를 이용해 비동기 통신을 수행한다. 창고에 있는 애플리케이션은
MSMQ 서버의 큐에 저장된 주문 메시지를 읽어 차례로 포장 및 발송 작업을 처리한다.

이번에는 물건을 구입하는 소비자의 주문을 처리하는 방법을 살펴보자. 이 시스템에서 소비자는 오퍼레이터와 전화를
통해 물건을 주문할 수 있고, 웹 사이트를 통해 직접 주문을 할 수도 있다. 첫 번째의 경우 실제 주문을 처리하는
사람은 전자상거래 회사에 근무하는 오퍼레이터로 윈도우 98 환경에서 주문 프로그램을 사용해 주문을 낸다.
이 경우 주문 프로그램은 DCOM을 통해 MTS에 있는 주문 컴포넌트를 액세스해 처리하게 된다. 두 번째 경우는
웹브라우저를 사용해 주문하는 경우로 소비자가 주문 웹 페이지를 액세스하면 IIS는 ASP 스크립트 프로그램을
수행하게 된다. 앞에서 언급한대로 ASP 스크립트는 다양한 COM을 액세스할 수 있으므로 MTS 컴포넌트를 사용해
주문을 처리할 수 있게 된다.

앞의 예제에서 보는 바와 같이 마이크로소프트 컴포넌트 서비스는 분산 컴퓨팅 환경을 위한 다양한 형태의 서비스
환경을 제공하고 있으며 이를 더욱 발전시켜 COM+ 라는 서비스 환경을 제공한다. 다음장부터 COM+가 나오기까지의
마이크로소프트 분산 컴퓨팅 기술의 발자취를 DCOM, MTS, MSMQ 순으로 살펴볼 것이다.

DCOM

수년간 컴퓨터 산업 분야에 많은 변화가 있었지만 그 중에서도 가장 비약적인 발전을 보인 부분은 다름 아닌 인터넷 관련
IT 산업일 것이다. 이러한 IT 산업의 발전은 소프트웨어의 대형화를 야기시켰으며, 그에 대한 해결책으로 소프트웨어의
컴포넌트화가 제시되었다. 컴포넌트화는 전체적인 개발 기간을 단축시켰으며, 이질적인 시스템간의 통합을 보다 쉽게
만들어 주며, 소프트웨어 유지 보수에 드는 비용을 최소화시켰다.

특히 분산 컴포넌트 기술은 다수의 사용자를 처리해야하는 이러한 대형 IT 시스템을 구성하는 기본이 되었으며
마이크로소프트는 DCOM이라는 분산 컴포넌트 기술을 발표해 이러한 환경을 지원하고 있다. DCOM은 분산 환경을 효율적으로
지원하기 위해 다음과 같은 세 가지 주요 특징을 가지고 있다.

DCOM은 컴포넌트 기반 기술이다.
DCOM은 가장 널리 사용되는 컴포넌트 기술인 COM 기반의 기술로 다양한 개발 툴의 지원을 받으며 이미 수많은 서드 파티를
보유하고 있다.
DCOM은 컴포넌트 애플리케이션을 인터넷 환경으로 확장시키는 네트워킹 기술이다.
DCOM은 인터넷 기본 기술인 TCP/IP, 자바, HTTP와 잘 융합해 작동되며 웹을 통해 쉽게 비즈니스 애플리케이션을 구현할
수 있는 환경을 제공한다.
DCOM은 여러 플랫폼에서 작동되는 오픈 기술이다.
윈도우 플랫폼 외에 유닉스, IBM 메인프레임에서도 잘 작동하므로 복잡한 IT 시스템 통합에 유용하게 사용할 수 있다.
이상과 같은 특징으로 DCOM은 분산 애플리케이션 개발에 중요한 위치를 차지하고 있으며, 기존의 IT 시스템에 큰 변화를
주지 않고, 적은 비용으로 분산 컴퓨팅의 이점을 살릴 수 있는 기회를 제공한다.

DCOM에 대한 기술적 접근

DCOM 기술에 대해 알아보기 전에 왜 분산 애플리케이션을 만들어야 하는지 생각해보자. 복잡한 비즈니스 로직이 구현된
소프트웨어가 하나 존재하고, 이를 하나의 서버에 설치해 가동시킨다고 가정하자. 클라이언트 수가 늘어남에 따라 서버의
부하는 증가하게 되고 점점 응답 시간이 늦어지는 문제가 발생한다. 이를 해결하기 위해 애플리케이션을 튜닝할 수
있겠지만 그 보다는 두 배 빠른 서버로 대체하는 것이 적은 비용을 들여 빠르게 해결할 수 있는 한 방법일 수 있다.

반면 서버에서 작동되는 소프트웨어가 분산객체로 작성돼 있다면 훨씬 더 적은 비용으로 시스템 효율을 극대화시킬
수 있다. 비즈니스 로직 중 부하가 많이 발생하는 부분을 분리해 새로운 다른 서버(성능이 비슷한)에 옮겨 운영할 경우,
단적인 비용을 비교해 보면 두 배 빠른 서버를 구입하는 것 보다 적은 비용이 든다(4 CPU 서버 가격이 2 CPU 서버
가격의 몇 배쯤인가 확인해 보면 쉽게 이해가 된다).

또한 애플리케이션 튜닝 측면에서도 많은 이점을 제공한다. 복잡하고 큰 하나의 비즈니스 애플리케이션을 튜닝하는
것보다 여러 개의 컴포넌트 모듈로 분리돼 있는 애플리케이션을 유지 보수하는 것이 쉽다는 건 당연하다.

DCOM 기본 구조

너무 많이 들어와서 다소 지겹게 들릴 수도 있지만 DCOM이 COM의 확장이라는 사실은 매우 중요하다.
COM은 컴포넌트와 컴포넌트를 사용하는 클라이언트간의 상호 관계를 정의한다. 다음 그림은 이 상호 관계를 나타낸
것으로 둘 사이에 어떠한 시스템 컴포넌트 없이 직접 대화하는 구조다. 우리가 흔히 알고 있는 인-프로세스 서버 구조다.

<그림 3>은 다른 프로세스에 존재하는 컴포넌트를 사용하는 경우로 직접 컴포넌트를 액세스하지 못하고 운영체제가
제공하는 IPC(Interprocess Communication)를 사용해 액세스해야 한다. 마이크로소프트 윈도우는 프로세스를 서로
완전히(?) 격리시키는 구조이므로 컴포넌트를 액세스할 수 있는 다른 방법이 존재하지 않는다. COM/DCOM 런타임
라이브러리는 IPC를 사용해 클라이언트와 컴포넌트 사이의 대화를 쉽게 해주는 중간 매체 역할을 담당한다.

<그림 4>는 클라이언트와 컴포넌트가 완전히 다른 컴퓨터에 존재하는 경우로 DCOM은 IPC를 네트워크 프로토콜로 대체한다.
이는 클라이언트 및 컴포넌트 모두가 네트워크를 사용해 통신한다는 사실을 숨김으로써 클라이언트와 컴포넌트 입장에서는
<그림 2>와 별다른 차이가 없다.

위치 독립

분산 컴퓨팅 환경에서 위치 독립(Location Indepen dence)은 매우 중요하다. 사용하는 컴포넌트의 위치가 동일 컴퓨터에서
인터넷으로 연결된 지구 반대편의 컴퓨터로 변경될 때마다 소스를 고쳐 새로 컴파일해야 한다면 보통 일이 아닐 수 없다.
그러나 DCOM은 이러한 문제를 간단한 레지스트리 편집만으로 아주 쉽게 해결해 준다.

프로그래밍 언어 중립

COM 및 DCOM 프로그래밍 언어와는 완전히 독립적이므로 분산 애플리케이션 개발시 다양한 언어를 사용해 진행할 수 있다.
사용자 인터페이스 부분은 비주얼베이직 같은 RAD 툴을 사용하고 다소 성능이 많이 고려돼야 하는 부분 혹은 하드웨어
제어 같은 저 수준 프로그래밍 같은 경우는 C++를 사용할 수 있다. 또한 전체적인 분산 애플리케이션 구조를 빠른 시간
내에 구성하기 위해 비주얼 베이직을 사용해 우선 설계한 후, 차례로 C++를 사용해 재 구현하는 것도 좋은 개발
방법이 될 수 있다.

네트워크 연결 관리

DCOM은 네트워크를 통해 컴포넌트를 사용하므로 컴포넌트가 동일 컴퓨터에 존재하는 경우보다 오류 가 발생할 가능성이
훨씬 높으며, 네트워크 오류 발생시 안전하게 오류를 인지하고 알려주는 기능을 제공한다. DCOM은 일종의 ping 프로토콜을
사용해 클라이언트의 생사 유무여부를 확인한다. 클라이언트 컴퓨터는 일정 시간마다 메시지를 전송한다. 만일 컴포넌트가
세 번 이상 지정된 시간동안 ping 메시지를 받지 못할 경우 DCOM은 연결 오류가 발생했다고 간주하고 컴포넌트의
참조수(Reference Count)를 감소시키고, 참조수가 0이 되면 컴포넌트를 메모리에서 릴리즈시키게 된다.

DCOM 확장성

사용자 수가 늘거나 데이터 양이 늘어날 경우에도 분산 애플리케이션은 적절히 잘 대처해야 한다. DCOM은 성능 및 안정성의
손실 없이 이러한 문제를 효율적으로 해결할 수 있는 특성을 제공한다.

대칭형 멀티프로세싱(SMP)

DCOM은 윈도우 NT가 지원하는 멀티 프로세싱 환경의 장점을 스스로 알아서 적절히 활용한다. 프리-쓰레딩 모델을 사용하는
애플리케이션의 경우 DCOM은 클라이언트의 요구를 처리하는 쓰레드 풀을 관리하며, CPU의 수에 따라 쓰레드 풀을 최적화
시킨다. 개발자는 이러한 쓰레드 풀을 사용한 최적화 프로그래밍에 관심을 가질 필요 없이 비즈니스 로직 구현에 힘쓰면 된다.

유연한 애플리케이션 재배치

고성능 다중 프로세서 서버라 할지라도 애플리케이션의 로드가 증가에 따른 부하를 감당하기가 쉽지 않다. 이러한 경우
DCOM의 위치 독립이라는 특성을 십분 활용해 컴포넌트를 다른 서버로 분산시킴으로 로드의 증가에 적절히 대응할 수 있다.

특히 다른 컴포넌트와 상태 정보를 공유하지 않는 컴포넌트의 경우 해당 컴포넌트 복사 본을 쉽게 여러 서버에 분산시켜
설치해 운영할 수 있다. 이렇게 시스템을 구성할 경우 자연스레 사용자의 로드를 여러 서버에 분산시키는 효과를 가져온다.

예를 들어 사용자가 100여명 되고, 40개의 컴포넌트가 수행되는 서버가 존재한다. 점점 사용자가 늘어 200명이 되어
전체적인 서버의 부하가 급증해 서비스하는 데 많은 지장을 초래하게 되었고, 이 문제를 해결하고자 새로운 서버를 하나
구입해 20개의 컴포넌트를 새 서버에 분산시켰다. <그림 5>는 이러한 시나리오를 표현한 것으로 손쉽게 서버의 성능을
향상시킬 수 있다.

이 방법 외에 보다 고차원적인 컴포넌트 분산 방법으로 40개 컴포넌트 중에 가장 병목 현상을 보이는 것을 찾아 완전히
새로운 독립 서버로 분산시킬 수 있다. DCOM을 사용한 분산 애플리케이션 설계는 이러한 재배치 작업을 쉽게 가능하게
만든다. 최초 애플리케이션 개발시는 하나의 서버에서 모든 컴포넌트를 가동시키지만, 실제 서비스에 들어가 부하가
증가하게 되면 애플리케이션의 재설계, 재컴파일 작업 없이 쉽게 분산시킬 수 있다.

보통 이러한 병목 현상은 각 프로세싱 단계, 예를 들면 물건 주문 작업은 주문서 작성, 전송, 재고 확인, 포장, 발송
등의 단계로 이루어지며 각각의 단계는 나름대로의 처리시간을 가지며 처리를 완료하지 못하면 다음 단계로 진행할 수
없다. 이러한 각각의 단계를 컴포넌트로 표현해 개별 특정 서버에 분산 또는 개별 프로세스로 작동시켜 <그림 7>과 같은
소프트웨어 파이프라인을 구성할 수 있다. 이러한 구성에서 각 컴포넌트는 자신의 작업을 마치고 완전히 나머지 단계가
끝날 때까지 기다리는 것이 아니라 새로운 사용자 요구에 바로 반응할 수 있으므로 전체적인 시스템 성능을 극대화할 수 있다.

DCOM 성능

DCOM은 네트워크 기반으로 움직이기 때문에 네트워킹의 제약에 따라 많은 성능의 차이를 보일 수밖에 없다. 컴포넌트가
제공하는 메쏘드를 호출할 때 전달되는 파라미터의 크기가 크다면 당연히 그만큼 응답시간이 느려질 것이며, 컴포넌트가
멀리 떨어져 있을수록(많은 라우터와 다양한 연결 라인이 존재) 응답 시간은 느려질 것이다. DCOM은 이러한 문제를
극복하기 위해 데이터 전송 프로토콜로 TCP 보다는 UDP를 선호한다. UDP를 사용해 실제 데이터 전송 및 ping 메시지
전송시 필요한 응답(low-level acknowledge)을 줄여 성능을 향상시킨다.

DCOM 공유연결 관리

앞에서 언급했듯이 컴포넌트 서버는 클라이언트의 생사 여부를 판별해야 한다. DCOM은 이를 위해 ping 테스트(주기적으로 메시지를 보내 확인)를 사용한다. A라는 클라이언트가 B 서버에 있는 컴포넌트 100개를 사용할 경우, 100개의 컴포넌트 각각이 A가 살아있는지 확인하기 위해 ping 테스트를 한다면 엄청난 네트워크 트래픽을 야기시킬 것이다. DCOM은 개별적인 100개의 ping을 발생시키는 대신 100개의 컴포넌트를 나타내는 ID를 생성한 후, 그 ID로 하나의 ping 테스트만을 실행해 네트워크 트래픽을 줄인다(delta ping).

네트워크 라운드 트립 최적화

네트워크 라운드 트립(Round-Trips)을 최적화하기 위해서는 데이터를 여러 번 주고받는 대신 한번에 덩치 큰 데이터로 묶어 주고받는 아이디어를 사용할 수 있다. DCOM에서 메쏘드 호출은 네트워킹을 통해 이루어지므로 잦은 메쏘드 호출은 당연히 많은 네트워크 라운드-트립을 발생시킨다. 그렇다고 라운드 트립을 줄이기 위해 전달할 데이터를 묶어서 표현한 후 한 번의 메쏘드 호출로 보낸면 서버 역시 그러한 메커니즘에 맞춰 개발해야 하는 부담이 있다. 다소 성능 향상은 있을지 모르지만 전체적인 애플리케이션 구조가 변질될 가능성이 커서 좋은 개발 방법은 될 수 없다.

DCOM은 개발자가 이러한 식으로 라운드-트립을 줄이기 위해 노력하지 않더라도 DCOM 마샬링(mar shaling)을 통해 여러 메쏘드 호출을 가로챈 후 하나로 묶어 하나의 원격 프로시저 호출로 처리한다.

DCOM 보안

네트워크 기반의 분산 애플리케이션에서 보안 메커니즘이 존재하지 않는다면 네트워크를 통해 연결 가능한 어떠한 클라이언트도 컴포넌트에 쉽게 접속할 수 있으므로 많은 문제가 일어날 수 있다. 만일 분산 환경이 별다른 보안 메커니즘을 지원하지 않는다면 클라이언트가 컴포넌트에 접속시 사용자 계정과 암호를 보내 인증을 받는 과정을 개발자가 일일이 프로그래밍해야 하는 부담을 안게 될 것이다.

DCOM은 윈도우 NT가 제공하는 확장성 있는 보안 프레임을 사용한다. 윈도우 NT는 예전의 트러스트 도메인 보안에서 공개키 보안 메커니즘까지 다양한 형태의 인증을 지원한다.

컨피규레이션에 의한 보안

DCOM은 클라이언트, 컴포넌트 양쪽 모두 프로그램 소스 수준의 특별한 보안관련 코딩 없이 분산 애플리케이션을 안전하게 보안할 수 있다. DCOM이 컴포넌트 위치를 숨기는 것과 유사하게 컴포넌트 보안 관련 사항도 숨기므로 별다른 작업 없이 쉽게 사용할 수 있다. NT 파일 시스템이 파일 또는 디렉토리에 대해 ACL(Access Control List)을 세팅해 다양한 사용 권한을 제한하는 것과 동일하게 DCOM은 개별 컴포넌트별로 ACL을 저장한다. 이러한 방법은 직관적으로 해당 컴포넌트를 사용할 수 있는 사용자 및 사용자 그룹을 지정하며, DCOM 관리 툴(DCOMCNFG)을 사용해 쉽게 조정 가능하다.

클라이언트가 컴포넌트를 생성하거나 컴포넌트의 메쏘드를 호출할 때, DCOM은 클라이언트 프로세스와 연관된 사용자 계정을 추출한 후 컴포넌트가 수행되는 컴퓨터 또는 프로세스로 전달한다. 컴포넌트가 설치된 쪽의 DCOM은 시스템의 인증 메커니즘에 따라 사용자 계정이 해당 컴포넌트의 ACL에 포함되는 지를 검사한 후 없으면 메쏘드 호출을 취소시킨다. 현재 COM+ 환경에서는 ACL을 이용한 보안 기법의 약점을 극복한 롤(role) 기반의 보안을 사용한다.

인터넷에서의 보안

인터넷에서의 보안 역시 윈도우 NT가 제공하는 보안 메커니즘을 그대로 활용할 수 있다. 윈도우 NT 보안 구성은 다음과 같은 다양한 종류의 보안 공급자를 지원한다.

Windows NT NTLM(NT Lan Manager) authentication pro tocol: 윈도우 NT 4.0 이전 버전에서 사용되던 기본적 인증 방법
Kerberos Version 5 authentication protocol: NTLM을 대체하는 기본 인증 프로토콜로 윈도우 NT 도메인 상에서 리소스 액세스를 제어한다.
Distributed password authentication(DPA): MSN이나 컴퓨터 서브와 같은 초대형 사이트에서 사용되는 인증 프로토콜
Secure channel security service: 윈도우 NT상에서 구현된 SSL/PCT 프로토콜
앞의 프로토콜 모두는 인터넷에서 사용할 수 있으며, 각각은 서로 다른 장단점을 가진다. NTLM과 Kerberos 기반의 인증 방법은 중앙 집중식 관리 환경 및 윈도우 NT 기반의 도메인 환경에서 매우 효율적이고 안정적이다. 윈도우 NT 4.0의 디렉토리 서비스는 거의 10만 사용자에 대한 인증을 거뜬히 처리할 수 있으며, 윈도우 2000의 확장된 디렉토리 서비스는 백만 사용자로 확대되었으며, 여러 도메인을 윈도우 2000의 디렉토리 트리에 통합시키면 실제적으로 하나의 도메인으로 거의 무한대의 사용자 인증을 처리할 수 있다.

DCOM은 본질적으로 다른 여러 인증 프로토콜에 독립적으로 작동되므로 컴포넌트와 클라이언트는 어떠한 변경도 없이 다양한 인증 프로토콜과 더불어 보다 안전한 분산 환경을 구축할 수 있다.

DCOM 로드 밸런싱

로드 밸런싱은 사용자 수의 증가로 인해 시스템의 부하는 점점 가중되고, 이 부하를 여러 서버에 골고루 분산시키는 일련의 방법을 지칭하며, 크게 정적 로드 밸런싱과 동적 로드 밸런싱으로 구분할 수 있다.

정적 로드 밸런싱

특정 사용자는 지정된 서버에만 접속해야 한다는 제한을 둔 방법으로 네트워크 상태 및 여러 다른 요소의 변경에 잘 적응하지 못한다. DCOM 기반의 애플리케이션은 간단히 레지스트리 변경만으로 특정 서버의 컴포넌트에만 접속해 작동하도록 명시할 수 있다. 간단한 구현 예로 연결할 서버 이름을 중앙 서버의 파일 또는 데이터베이스에 저장해 두고, 클라이언트 애플리케이션이 실행중인 서버와 연결해야 할 정보를 읽어 특정 서버로 연결하게끔 만들 수 있다. 추후 이 정보를 변경함으로써 클라이언트가 접속해야할 서버를 정적으로 변경해 로드를 분산시킬 수 있다.

이 방법보다 조금 더 진보된 방법으로 참조 컴포넌트(Referral Component)를 사용할 수 있다. 참조 컴포넌트는 모든 클라이언트에서 연결할 수 있는 중앙 서버에 위치한다. 개별 클라이언트 프로세스는 이 컴포넌트에 연결해 서비스를 받을 서버를 할당받는다. 이 때 참조 컴포넌트는 DCOM의 보안 메커니즘을 사용해 클라이언트 계정 및 그룹 정보를 파악해 로드를 여러 서버로 분산시킬 수 있으며, 단순한 연결 서버 이름을 반환하는 대신 해당 서버 컴포넌트의 인터페이스 포인터를 반환함으로써 실제 클라이언트와 서비스 서버를 직접 연결시켜줄 수도 있다

동적 로드 밸런싱

정적 로드 밸런싱은 사용자 증가에 따른 로드 증가를 효과적으로 처리할 수 있지만 시스템 관리자가 계속 전체 시스템 로드를 감시해야 하고, 시스템 로드 자체가 명확히 구분되는 경우에만 적용될 수 있는 단점이 있다.

위에서 설명한 참조 컴포넌트의 로드 밸런싱 작업은 사용자 계정을 기반으로한 정적인 밸런싱 작업이었다. 여기에 서버의 현재 부하, 클라이언트 서버간의 네트워크 구조, 여러 통계정보 등을 활용해 지능적으로 로드를 분산시킬 수 있다. 매번 클라이언트가 참조 컴포넌트에 접속할 때마다 가장 적절한 서버를 찾아 연결 지어주게 된다. 이러한 작업을 동적 로드 밸런싱이라 부른다.

하지만 이런 종류의 로드 밸런싱이 모든 상황에 잘 적용되는 것은 아니다. 참조 컴포넌트가 동적으로 클라이언트와 컴포넌트를 연결시킨 이후 둘 사이는 정적 연결이 이루어진 것이 되며, 해당 컴포넌트의 각 메쏘드는 새로운 서버로 연결 없이 기존에 연결된 서버에서만 실행된다는 제약이 있다. 컴포넌트가 상태를 유지해야 하는 경우라면 메쏘드 호출이 여러 서버에서 이루어지는 로드 밸런싱은 상태 정보를 망가뜨리는 심각한 문제를 야기시킨다.

이러한 문제를 깔끔하게 해결한 것이 마이크로소프트 트랜잭션 서버다. MTS는 DCOM 프로그래밍 모델을 확장해 상태 정보를 유지하는 표준화된 인터페이스를 제공해 보다 정교한 수준의 로드 밸런싱을 제공한다.

MTS 모델에서 클라이언트와 컴포넌트 사이의 상호 의사 소통은 트랜잭션이라는 이름으로 묶여서 이루어진다. 여기에서 트랜잭션은 둘 이상의 컴포넌트 메쏘드의 호출이며 각각의 호출 사이에는 어떠한 상태 정보도 유지되지 않는다. 따라서 하나의 트랜잭션을 구성하는 여러 컴포넌트 메쏘드 호출에 대해 동적 밸런싱이 가능하며 이전에 언급한 파이프라이닝도 가능하게 된다.

DCOM 폴트 톨러런스

오류 상황으로부터 시스템의 안정적인 회복 및 폴트 톨러런스(Fau lt Tolerant)는 비즈니스 애플리케이션에서는 두말할 필요 없이 가장 중요한 문제다. 이러한 안정성은 서버 하드웨어 이중화, 운영체제, 애플리케이션 자체의 견고한 설계에 바탕을 두어야 보장되며, 어느 한 부분이라도 문제가 있으면 심각한 상황을 맞게 된다.

DCOM은 안정적인 서비스를 위해 프로토콜 수준에서 기본적인 폴트 톨러런스를 지원한다. 견고하게 만들어진 ping 메커니즘을 통해 네트워크는 클라이언트의 오류를 감지한다. 네트워크 오류 발생시 타임아웃 시간 내에 네트워크가 회복되면 DCOM은 연결을 자동으로 재설정한다.

보다 상위 수준에서 폴트 톨러런스한 시스템을 구성하고자 한다면 참조 컴포넌트를 활용하는 방법을 사용할 수 있다. 클라이언트는 참조 컴포넌트를 통해 서비스 컴포넌트와 연결하게 된다. 서비스 중 컴포넌트에 오류가 발생한 것을 클라이언트가 감지하면 클라이언트는 참조 컴포넌트에게 새로운 연결을 요구하게 되며, 이때 참조 컴포넌트는 올바르게 작동중인 다른 서버에 있는 서비스 컴포넌트와 연결을 제공한다. 이러한 메커니즘 구현을 위한 기본 프레임워크를 DCOM은 제공하며 그 실례가 MTS다. MTS는 여러 컴포넌트의 여러 메쏘드 호출을 트랜잭션으로 묶어 처리하므로 애플리케이션 수준의 일치성(Consistency)을 제공한다.

마이크로소프트 트랜잭션 서버

MTS가 필요한 이유

MTS의 기본 목적은 신뢰성 높고, 쉽게 확장 가능한 기업용 분산 애플리케이션 개발을 보다 용이하도록 만들어 주는 프로그래밍 환경을 제공하는 데 있다. 다중 사용자 기업용 서버 컴포넌트를 작성할 때 발생하는 가장 큰 문제점으로는, 실제 업무 로직과는 무관한 트랜잭션 관리, 리소스 관리, 쓰레드 관리와 같은 작업을 처리하는 부분까지 고려해 작업을 해야 한다는 것이다.

단적인 예로 데이터베이스 연결 리소스를 살펴보자. 데이터베이스 연결이 거의 무한하다면 수많은 클라이언트 각자가 하나 또는 그 이상의 연결을 유지하며 작업하는 모델이 가장 이상적이다. 하지만 데이터베이스 연결은 많은 시스템 자원을 소모하는 유한한 리소스이므로 다수의 사용자가 연결할 경우 보다 정교한 방법이 요구된다. MTS는 이러한 시스템 리소스 관리 외에 트랜잭션 관리, 쓰레드 관리, 컴포넌트 관리 기능을 효율적으로 제공한다.

MTS는 컴포넌트 기반의 트랜잭션 처리 시스템이므로 개발자는 서버 컴포넌트 형태로 구현된 서버 애플리케이션을 생성해 MTS에 배치함으로써 MTS가 제공하는 다양한 서비스를 사용할 수 있다. 개발자는 동시에 다수의 사용자 지원을 위한 별다른 고려 없이 처리하고자 하는 비즈니스 로직 구현에만 힘쓰면 된다. 비즈니스 컴포넌트를 MTS에 설치하는 순간 해당 컴포넌트는 자동으로 동시 사용자 지원을 위해 확장되고, 자동적으로 최적화된 리소스 관리 시스템에 동참하게 된다.

또한 MTS는 단순한 트랜잭션 모니터로서의 기능을 넘어 컴포넌트가 트랜잭션을 처리하게끔 확장 설계되었으므로, 기존의 COM 개발자가 트랜잭션을 처리하는 분산 애플리케이션을 보다 쉽게 만들 수 있는 환경을 제공한다.

프로세스, 쓰레드, 데이터베이스 연결과 같은 시스템 리소스를 관리해 트랜잭션 서버가 다중 사용자를 지원할 수 있도록 확장시킨다.
트랜잭션 서버 컴포넌트의 생성과 실행, 그리고 소멸을 관리한다.
자동적으로 트랜잭션을 시작하고 제어함으로써 신뢰성 있는 트랜잭션 서버 컴포넌트가 되게 한다.
사용 권한이 없는 사용자가 트랜잭션 서버 컴포넌트에 접근할 수 없도록 보안 관리를 제공한다.
MTS 컴포넌트와 시스템을 관리하기 위한 그래픽 인터페이스를 제공한다.
상업적 측면에서 바라보면 기존의 액티브X 컨트롤로 대변되던 클라이언트 쪽 컴포넌트 시장을 서버 컴포넌트 시장으로 확장하는데 큰 의미가 있다. 현재 우리는 멋진 사용자 인터페이스 구현 및 화려한 리포팅 출력을 위해 다양한 종류의 액티브X 컨트롤을 사용하고 있지만 멀지 않은 미래에는 복잡한 비즈니스 로직을 구현한 서버 컴포넌트를 쉽게 접할 수 있으며 필요한 컴포넌트를 구입해 쉽게 기업용 분산 애플리케이션을 만들 수 있을 것이다.

MTS의 기반기술, COM과 DCOM

COM

MTS 역시 마이크로소프트의 많은 다른 소프트웨어와 마찬가지로 COM 기반 기술을 바탕으로 만들어졌다. COM은 COM 개체의 생성 및 사용, 소멸을 지원하는 시스템 소프트웨어와 규약을 포함한다. 객체지향 언어에서 객체와 마찬가지로 COM 개체는 자신의 데이터를 숨기고, 메쏘드로 객체의 기능을 구현하며, 인터페이스로 묶어 사용자에게 노출시킨다. 클라이언트는 사용하기를 원하는 인터페이스 포인터를 구한 후 해당 인터페이스가 제공하는 메쏘드를 호출하게 된다.

앞에서 설명했듯이 COM은 어떠한 언어로도 구현할 수 있다. 언어 독립적으로 설계된 데이터 타입 및 바이너리 표준은 여러 언어로 공동의 프로젝트를 수행할 수 있게 한다.

DCOM

DCOM은 COM 컴포넌트를 다른 컴퓨터에서 수행 가능하게 만드는 환경을 제공한다. 클라이언트의 메쏘드 호출은 네트워크를 통해 다른 시스템에서 수행되는 컴포넌트로 전달된다. 이러한 메커니즘을 구현하기 위해 DCO M은 DCE(Distributed Computing Environ ment)에서 사용되는 RPC를 사용한다.

분산 보안 서비스를 제공하기 위해 DCOM은 윈도우에서 지원되는 NTLM(NT Lan Manager) 프로토콜을 사용할 수 있으며, Kerberos와 SSL(Secure Socket Lay er) 프로토콜도 지원한다.

컨테이너

동일 컴퓨터 내에서 아니면 원격 컴퓨터에서 실행되는 것과 상관없이 COM 컴포넌트는 독립적 실행 파일(EXE) 또는 동적 연결 라이브러리(DLL)로 만들어진다. 이 중 DLL 형태의 컴포넌트를 인-프로세스 서버라고 부르며, 컨테이너 내에서만 실행된다(DLL이므로 독립 실행은 불가능하다). COM의 실행 가능한 형태를 보면 <그림 8>과 같으며 지역 인-프로세스, 지역 독립 프로세스, 원격 인-프로세스, 원격 독립 프로세스가 있다. 네 가지 중 어떠한 형태로 구현돼도 클라이언트가 바라보는 COM 컴포넌트는 모두 동일하다.

DCOM 클라이언트 작성은 일반적인 COM 클라이언트 작성과 거의 유사하므로 간단하지만, DCOM 서버 애플리케이션 작성은 쉽지만은 않다. 하나의 클라이언트가 사용하는 간단한 서버를 만드는 것은 쉽지만, 동시에 많은 클라이언트에게 서비스를 제공해야하는 서버를 만들 경우는 효율성을 충분히 재고해 설계해야 한다. 당장 고려해야 할 사항이 서버 컴포넌트가 멀티쓰레드 환경에서 수행돼야 한다는 것이며 이를 위해서는 많은 부가적인 프로그래밍을 해야하는 어려움이 생긴다. 또한 서버 환경에서는 종종 트랜잭션 개념이 발생한다. 주문서를 발송하는 예를 들면 주문서 생성, 주문서에 주문할 물건을 추가, 삭제, 주문서 발송과 같은 연속적인 작업은 트랜잭션으로 처리해 성공할 경우 일괄 커밋, 실패할 경우 롤백해야 한다. 이와 같은 경우를 모두 고려해 DCOM 서버를 작성한다고 하면 아마도 웬만한 개발자가 아니면 두 손들고 말든지, 성능은 고려하지 않고 한번에 하나의 요청만 처리하는 심플 서버로 만들 것이다.

그러나 더 이상 이러한 사항에 대해 고민할 필요가 없을 거 같다. MTS는 트랜잭션 처리, 효율적 쓰레드 관리 등을 제공해 확장 가능한 DCOM 서버 애플리케이션을 쉽게 만들 수 있는 환경을 제공한다.

MTS 애플리케이션의 구조

MTS 컴포넌트

MTS 애플리케이션은 인-프로세스 COM 컴포넌트 형태(DLL)로 개발된다. COM 기반으로 만들어지기 때문에 비주얼 베이직, C++, 델파이, 자바 등 어떠한 언어를 사용해 개발할 수 있다. MTS는 인-프로세스 컴포넌트로 제작된 모듈을 실행하는 컨테이너 구조를 가진다. 연관성을 가지는 다수의 컴포넌트를 패키지로 묶어 MTS 내에서 독립적으로 실행할 수 있으며, 하나의 컴퓨터 내에서 동시에 다수의 패키지를 실행할 수 있다. 패키지는 각자 MTS 실행 모듈(Executive)의 사본을 가지므로 독립적인 프로세스에서 실행된다.

하나의 패키지에 묶인 모든 컴포넌트들은 하나의 MTS 실행 모듈에 로딩돼 사용하며, 이는 윈도우 NT 서버의 동일 프로세스 내에서 작동한다는 것을 의미한다. 이러한 모델은 분산 애플리케이션의 확장성을 제한시키는 문제점을 갖는다. 현재 버전의 MTS는 이러한 문제를 해결하지 못하지만, 하나의 애플리케이션을 구성하는 컴포넌트들을 다수의 패키지에 나누어 여러 윈도우 NT 서버에서 가동시킬 수 있으므로 확장성의 문제를 어느 정도 보완할 수 있다.

<그림 9>에서 보듯이 클라이언트가 MTS 컴포넌트를 액세스할 수 있는 유일한 방법은 COM/DCOM을 통하는 것이다. MTS 컴포넌트가 클라이언트와 동일한 컴퓨터에 있을 경우 COM이 사용되며, 원격지에 있을 경우는 DCOM이 사용된다. 따라서 클라이언트가 바라보는 MTS 컴포넌트는 단순한 몇몇의 인터페이스를 제공하는 COM 컴포넌트일 뿐이다. 그러나 <그림 9>에 나타나 있듯 MTS 실행 모듈은 둘 사이의 모든 대화를 감시할 수 있다. 이러한 감시를 통해 MTS는 멀티스래딩 핸들링, 트랜잭션 처리, 객체 생성 최적화 등과 같은 부가 서비스를 제공할 수 있다.

늦은 활성화

일반적인 COM 객체 생성과 마찬가지로 MTS 컴포넌트 생성 역시 CoCreateInstance API를 사용해 이뤄진다. COM 객체의 경우 API가 호출되면 인-프로세스 서버든, 리모트 서버든지 바로 COM 객체가 생성되지만 MTS의 경우는 바로 객체가 생성되지 않는다. 실제 객체를 필요로 하는 시점, 즉 해당 컴포넌트에 대한 첫 메쏘드가 호출되는 시점이 되어야 객체가 만들어진다.

MTS는 또한 인스턴스 풀링이라는 기법을 제공한다. 매번 CoCreateInstance를 호출할 때마다 객체를 생성하는 대신 이미 생성된 객체를 풀에 유지하면서 필요시 생성 작업 없이 바로 클라이언트에 공급한다.

이 두 방법은 객체의 전체 유지 시간을 줄여 한정된 서버 리소스의 효율을 높여준다. 클라이언트 수가 적을 경우 별다른 이득이 없지만 수많은 클라이언트가 서비스를 요구하는 상황에서는 많은 이점을 제공한다.

컨텍스트 객체

패키지에 포함된 컴포넌트는 하나의 컨텍스트 객체를 각자 가진다. 컨텍스트 객체는 MTS에 의해 자동으로 생성되며 컴포넌트 사이의 트랜잭션을 조정하는데 사용한다. 클라이언트는 GetObjectContext API를 호출해 컨텍스트 객체 인터페이스인 IObjectContext를 얻을 수 있다.

데이터 액세스

대부분의 MTS 컴포넌트는 데이터 처리를 담당하며, 데이터를 관리하는 스토리지로 오라클, SQL 서버와 같은 데이터베이스를 사용한다. MTS 컴포넌트에서 데이터베이스를 액세스하는 방법으로는 데이터베이스 벤더별로 제공하는 저수준 API를 사용하거나, 데이터베이스에 독립적인 ODBC를 사용할 수 있다. 그러나 마이크로소프트에서는 소프트웨어의 컴포넌트화에 발맞추어 데이터베이스에 독립적인 COM 기반의 OLE DB와 ADO(ActiveX Data Objects)를 발표했다.

OLE DB는 모든 종류의 데이터를 액세스하는 일반적인 방법을 제공하는 COM 객체와 인터페이스 집합을 정의한다. 예를 들면 OLE DB는 관계형 데이터베이스를 액세스하기 위해 두 가지 객체를 사용한다. 클라이언트는 command 객체에 SQL 문장을 제공한 후 쿼리를 실행시키면 command 객체는 그 결과를 rowset 객체에 반환한다. 클라이언트는 rowset이 제공하는 다양한 인터페이스를 사용해 실제 데이터를 액세스할 수 있다.

ODBC와 달리 OLE DB는 접근할 데이터 소스를 관계형 데이터베이스에 국한시키지 않는다. 즉 command 개체는 SQL 문장 외에 임의의 명령을 처리할 수 있으며, 다양한 포맷의 데이터에 대한 다양한 접근 방법을 제공할 수 있다.

그러나 OLE DB의 복잡성으로 인해 클라이언트에서 사용하기가 만만치 않다. C++ 사용자는 OLE DB를 사용해 비교적 쉽게 개발할 수 있지만, 비주얼 베이직과 같은 언어에서는 거의 사용이 불가능(?)하다. 그래서 마이크로소프트는 OLE DB 상위 계층 개념의 사용하기 쉬운 ADO를 제작했다. ADO는 이중 인터페이스를 제공하므로 비주얼 베이직에서도 쉽게 사용 가능하며 기존의 DAO(Data Access Objects), RDO(Remote Data Objects)를 모두 포함하는 강력한 기능을 제공한다.

데이터베이스를 액세스하는 프로그램은 보통 데이터베이스와 연결을 성립시킨 후 SQL문을 수행하고 모든 작업이 완료되면 연결을 종료한다. MTS 컴포넌트 역시 이러한 일련의 작업에서 예외는 아니다. 그러나 데이터베이스와의 연결은 생각보다 많은 시간이 걸리는 작업으로 서버 애플리케이션에서는 이 시간을 줄이기 위해 연결 풀링 기법을 사용한다. 연결 종료시 실제 연결을 끊지 않고 연결을 풀에 넣어 유지한다. 다음에 연결을 요구할 경우 풀에 있는 사용되지 않는 연결을 제공한다. 일종의 캐시라고 생각하면 된다. MTS 역시 이러한 기능을 제공하고 있다.

트랜잭션 처리

데이터베이스 작업을 하다 보면 종종 일련의 작업을 차례로 수행해야 하는 경우가 발생한다. 일련의 작업 중 하나라도 실패하면 작업 이전의 원래 상태로 돌아갈 수 있어야 하고, 각각의 작업이 성공적으로 끝나야 전체 작업이 성공된 것으로 간주된다. 이러한 것이 트랜잭션으로 데이터베이스에서는 여러 개의 SQL 문장이 하나의 단위로 처리되는 것을 의미한다.

만일 컴포넌트가 하나의 데이터베이스 서버에서 트랜잭션을 실행해야 한다면 굳이 MTS를 사용하지 않아도 된다. 데이터베이스가 제공하는 트랜잭션 기능을 사용하면 쉽게 처리할 수 있기 때문이다. 그러나 데이터베이스가 분산되어 있거나 데이터베이스 이외의 다른 시스템과 함께 트랜잭션을 수행해야 한다면 MTS를 이용하는 것이 절대적으로 유리하다.

MTS라는 이름에서 볼 수 있듯이 MTS는 기본적으로 트랜잭션을 지원하기 위해 개발됐지만, 단지 트랜잭션 처리만을 위해 사용되기에는 다소 아까운 면이 많다. 해당 컴포넌트가 트랜잭션을 사용하지 않더라도 MTS를 이용해 애플리케이션을 개발한다면 보다 확장성이 높고, 안정적인 DCOM 서버 애플리케이션을 쉽게 개발할 수 있을 것이다.

전통적인 클라이언트/서버 트랜잭션 시스템에서는 클라이언트가 트랜잭션의 시작과 끝을 구체적으로 명시했었다. MTS 컴포넌트에서도 이와 유사하게 StartTran saction, EndTransaction과 같은 메쏘드를 가지는 인터페이스를 제공해 클라이언트가 직접 트랜잭션을 명시하게끔 만들 수 있지만 좋은 방법은 아니다. 대신 MTS는 클라이언트가 트랜잭션의 시작과 끝을 알 수 없도록 자동화한 트랜잭션을 지원한다. 클라이언트는 단지 MTS 컴포넌트가 제공하는 특정 메쏘드를 호출해 원하는 기능을 수행할 뿐이지, 그 메쏘드가 트랜잭션을 시작하는지 종료하는지에 대해선 전혀 알 필요가 없다. 단지 트랜잭션은 MTS 컴포넌트의 몫이다.

이렇게 자동화되고, 투명한 트랜잭션을 지원하기 위해 MTS는 컨텍스트를 사용한다. 서로 다른 컴포넌트에 대해 하나의 트랜잭션을 처리할 경우 MTS는 동일한 컨텍스트를 두 컴포넌트에 제공해 각각의 컴포넌트 기능을 트랜잭션으로 묶어서 실행시킨다.

트랜잭션 속성

데이터베이스에 레코드를 추가하는 Add 컴포넌트와 레코드를 삭제하는 Delete 컴포넌트가 존재한다고 가정하자. 이들 두 컴포넌트를 사용해 데이터를 전송하는 Transfer 컴포넌트를 개발할 수 있다. 그러나 문제는 이들 두 컴포넌트가 어떻게 트랜잭션에 참가할 수 있는가 하는 것이다. 만약 트랜잭션에 참여할 수 없다면 Transfer 컴포넌트에서 Add, Delete 작업시 한 작업이라도 실패할 경우 데이터의 일관성은 망가지게 되는 치명적인 결과가 발생할 수 있다.

MTS는 Transfer 컴포넌트 로직을 구현할 때 트랜잭션을 명시하는 방법 대신 이들 컴포넌트가 애플리케이션 패키지로 묶여 MTS에 설치될 때 선언적으로 명시하는 방법을 사용한다. MTS에 설치되는 모든 MTS 컴포넌트는 트랜잭션 속성을 갖고 있으며, 이 속성은 MTS 카탈로그에 기록된다. MTS 컴포넌트 객체가 생성될 때 MTS는 이 트랜잭션 속성 값을 참조해 해당 MTS 컴포넌트가 트랜잭션에 어떻게 참여할 지를 결정한다. 트랜잭션 속성은 MTS 탐색기에서 지정할 수 있으며 가능한 값은 다음 네 가지다.

Requires a transaction: 해당 MTS 컴포넌트가 반드시 트랜잭션에서 실행돼야 한다는 것을 나타낸다. 만약 클라이언트가 트랜잭션 컨텍스트를 갖고있지 않다면, MTS는 자동으로 새로운 컨텍스트를 생성한다.
Requires a new transaction: 해당 MTS 컴포넌트는 반드시 자신의 고유한 트랜잭션 컨텍스트에서 실행돼야 한다는 것을 나타낸다. MTS 컴포넌트의 인스턴스가 생성되면 클라이언트가 트랜잭션을 갖고 있는 지와 상관없이 MTS는 자동적으로 새로운 컨텍스트를 생성한다.
Supports transactions: 해당 컴포넌트가 클라이언트의 컨텍스트에서 실행될 수 있다는 것을 나타낸다. 클라이언트가 트랜잭션 컨텍스트를 갖고 있으면 이를 그대로 상속받아 사용한다. 트랜잭션 컨텍스트가 없을 경우 새로운 컨텍스트를 만들지 않고 트랜잭션 처리하지 않는 인스턴스를 생성한다.
Does not support transactions: 해당 MTS 컴포넌트가 트랜잭션 컨텍스트 하에서 실행되지 않는다는 것을 나타낸다. 즉 클라이언트의 트랜잭션 컨텍스트와 상관없이 트랜잭션이 없는 인스턴스를 만든다.
트랜잭션 종료

트랜잭션 컨텍스트가 성립되면 각각의 컴포넌트는 클라이언트가 요구한 일을 수행하며, 모든 작업을 종료할 때 MTS 수행부에게 자신의 작업이 성공적으로 이루어져 커밋이 가능한지 아니면 오류가 발생해 롤백을 해야 하는지를 알려야 한다.

실제 트랜잭션을 종료하기 위해 컴포넌트는 컨텍스트 오브젝트가 제공하는 IObjectContext 인터페이스가 제공하는 메쏘드를 호출한다. 트랜잭션이 커밋돼야 한다면 IObjectContext::SetComplete를 호출하고, 오류가 발생해 롤백해야 한다면 IObjectContext::Set Abort를 호출한다. MTS 컴포넌트 개발자 입장에서 보면 성공이냐 실패냐의 양자 택일이라는 매우 간단한 작업이다.

그러나 MTS의 입장에서 보면 SetComplete가 호출되었다고 해서 즉시 커밋을 해야 한다고 판단할 수 없다. 하나의 트랜잭션에 참여하는 컴포넌트는 하나 이상일 수 있고, 이들 모두가 SetComplete를 호출해야 비로소 커밋을 진행할 수가 있다. 만일 하나라도 SetAbort가 호출되면 전체를 롤백 해야 한다.

Two-Phase 커밋

SetComplete 또는 SetAbort 호출을 통해 MTS 애플리케이션은 트랜잭션 종료를 지정하게 된다. 이때 이 트랜잭션이 하나의 데이터베이스에서 처리된다면 데이터의 변경이 쉽게 커밋(Commit)될 수 있다. 그러나 트랜잭션이 하나의 데이터베이스가 아닌 복수개의 데이터베이스 또는 그 밖의 다른 리소스 매니저라면 문제가 훨씬 복잡해진다. 여기서 리소스 매니저는 데이터베이스와 같이 트랜잭션 데이터를 처리할 수 있는 시스템이라고 정의한다. Two-phase 커밋은 모든 리소스 매니저에서 완전히 성공적으로 커밋이 되어야 하나의 트랜잭션이 성공적으로 완료된다는 것을 보장해 준다.

Two-phase 커밋에서, 트랜잭션 조정자는 우선 트랜잭션에 참여하는 모든 리소스 매니저에게 커밋할 준비돼 있는지를 묻는다. 모든 리소스 매니저로부터 ‘예’라는 응답을 받으면 트랜잭션 조정자는 각 리소스 매니저에서 커밋을 요청한다. 만약 하나의 리소스 매니저라도 커밋할 준비돼 있지 않다는 메시지를 보내거나, 커밋에 실패했다고 알려오면 트랜잭션 조정자는 나머지 리소스 매니저에게 트랜잭션을 롤백하라고 명령한다.

분산 트랜잭션 조정자

MTS에서 사용하는 Two-phase 커밋은 트랜잭션 조정자(Distri buted Transaction Coordinator), 즉 DTC에 의해 지원된다. DTC는 MTS 제품의 구성 요소가 아닌 SQL 서버 6.5의 구성 요소로 배포됐으며 독립적인 윈도우 NT 서비스로 작동한다. 클라이언트가 SetComplete를 호출해 트랜잭션을 커밋하려 하면 MTS는 이러한 커밋 요청을 DTC에 전달한다. <그림 10>에서 보는 것과 같이 MTS가 아닌 DTC가 실제로 각 리소스 매니저에 대해 two-phase 커밋을 실행한다.

DTC와 리소스 매니저 사이의 통신을 위해 어떠한 표준화된 프로토콜이 필요하며 가장 널리 사용되는 DTP(Distributed Transac tion Processing) 표준을 사용한다. DTP는 XA 인터페이스라 불리는 트랜잭션 조정자와 리소스 매니저 사이의 표준 인터페이스를 정의한다. DTC는 XA를 지원하며, 추가로 OLE 트랜잭션이라는 객체지향 개념이 추가된 방법을 지원한다. OLE 트랜잭션은 트랜잭션 조정자와 리소스 매니저 사이의 대화 방법으로 COM을 사용한다. 따라서 개별 리소스 매니저가 DTC와 함께 트랜잭션을 수행하려면 OLE 트랜잭션을 지원하기 위한 COM 객체 및 인터페이스를 제공해야 한다.

MTS와 인터넷

액티브X 컨트롤

인터넷을 통해 MTS 애플리케이션에 접근하는 방법은 크게 두 가지가 있다. 하나는 액티브X 컨트롤을 이용한 직접 사용이고 다른 하나는 ASP를 이용한 간접 사용이다.

사용자는 웹 브라우저를 통해 액티브X 컨트롤을 다운 받을 수 있으며, 액티브X 컨트롤은 웹 브라우저라는 컨테이너 내에서 인-프로세스 COM 형태로 작동한다. 액티브X 컨트롤은 DCOM 프로토콜을 사용해 MTS와 직접 연결해 MTS 애플리케이션을 사용한다.

액티브 서버 페이지

두 번째 방법은 웹 브라우저에서 MTS로 직접 연결을 시도하는 대신 기존의 HTTP 프로토콜 기반에서 DCOM 연결 없이 수행된다. 대신 웹브라우저 사용자가 볼 수 있는 결과물은 웹 페이지로 제한한다. <그림 11>은 이러한 연결 방법을 구체적으로 보여준다. 웹 브라우저는 HTT P를 통해 IIS와 연결해 웹 페이지를 요구한다. IIS는 요구된 ASP 페이지를 실행한다. ASP는 보통 VBScript로 쓰여진 스크립트 프로그램으로 이 스크립트에서 MTS 컴포넌트를 호출하게 된다. MTS 애플리케이션이 완료되면 ASP는 그 결과를 웹 페이지로 꾸며 웹 브라우저에 전달한다.

마이크로소프트 메시지 큐 서버

분산 애플리케이션 개발시 각 부분간의 통신을 위해 어떠한 방법을 사용할지 종종 고민한다. 웹 브라우저를 사용해 클라이언트 서버간 HTTP로 통신하는 방법, 오래된 방법이지만 RPC를 통한 방법, 객체 지향적인 방법인 DCOM 등을 통한 방법이 있을 수 있다. 이에 추가로 마이크로소프트 메시지 큐 서버(MSMQ)를 이용해 분산 애플리케이션 환경에서 메시지를 주고받을 수 있다.

MSMQ가 필요한 경우

언제 웹이나 RPC 대신 메시지 큐를 사용하는게 용이할까? 메시지 전송자가 처리 전에 수령자로부터 결과를 기다려야 한다면 RPC를 사용하는 것이 좋다. 즉 동기화된 메시지 전송에는 RPC가 여러 가지 측면에서 유리하지만, 메시지 수령 전에 기타의 여러 작업을 할 수 있는 비동기식 메시지 전송에는 메시지 큐를 사용하는 것이 좋다.

메시지를 주는 측과 받는 측이 함께 동작할 필요가 없는 경우라면 메시지 큐를 사용하는 것이 낫다. RPC는 클라이언트, 서버 모두가 함께 작동 되야 하지만, 메시지 큐는 전송자가 메시지 큐에 메시지를 넣으면 수령자는 언제든지 메시지 큐로부터 메시지를 읽을 수 있다. 또한 큐에 있는 메시지는 하나의 수령자가 아닌 다수의 수령자가 참조할 수도 있다. RPC는 클라이언트와 서버가 연결된 상태에서 작동하기 때문에 수령자 그룹에 메시지를 보내기가 쉽지 않다.

예를 들어 A가 메시지를 B에 전송하고, B는 이 메시지를 C와 D에 전송한 후 두 결과를 A에 전송하도록 만들려면 RPC보다 메시지 큐가 훨씬 좋은 해결책을 제시해 준다.

MSMQ 개관

메시지 큐의 가장 큰 장점은 개념적으로 매우 간단하다는 것이다. <그림 12>를 보면 메시지 큐는 크게 세 가지 부분으로 나뉜다.

애플리케이션이 메시지를 주고받기 위해 사용하는 API
애플리케이션에 의해 만들어지고 송신, 수신되는 메시지
큐 관리자에 의해 관리되는 큐로 큐를 통해 메시지가 전송/수신된다.
세 가지 기본 구성 요소를 바탕으로 MSMQ는 세 가지 형태의 애플리케이션을 정의한다. 첫째는 MSMQ 서버 자체로 큐와 큐 관리자를 가지고 MSMQ API를 제공하며 큐간에 메시지를 라우팅한다. 나머지 둘은 클라이언트 형태로 독립형 클라이언트와 종속형 클라이언트가 존재한다.

독립형 클라이언트는 MSMQ API와 자신만의 큐를 가진 큐 관리자를 갖고 있으므로 항상 자유롭게 메시지를 전송할 수 있다. 컴퓨터가 네트워크에 연결 안돼도 메시지는 전송될 수 있다(사실은 메시지 큐에 차례로 저장된다). 이 후에 컴퓨터가 네트워크에 접속하게 되면 큐 관리자는 자동적으로 연결을 감지해 메시지를 MSMQ 서버에 전달한다.

종속형 클라이언트 역시 메시지를 송수신하는 애플리케이션을 지원하지만 독립형에 비해 다소 제약이 있다. 종속형은 자신만의 큐와 큐 관리자 없이 단지 MSMQ API만 지원하기 때문에 클라이언트로 실행되는 애플리케이션은 반드시 MSMQ 서버와 연결되어 있어야 한다.

MSMQ API

MSMQ는 서로 다른 두 가지 API를 제공한다. 하나는 C++ 개발자를 위한 것으로 다양한 함수 호출을 정의하고 있으며, 다른 하나는 COM 객체 형태로 제공해 다양한 환경을 지원한다. COM 객체보다는 C API가 보다 많은 서비스를 제공한다.

MSMQ 특성

메시지 특성

메시지의 가장 중요한 특성은 모체(Body)로 메시지에 전송될 데이터를 담고 있으며 데이터는 유형이 없는 바이트 배열 또는 전송되는 데이터 유형에 대한 식별자를 담을 수 있다. 또한 한 번에 담을 수 있는 최대 크기는 4MB이다.

메시지 전달

또 다른 특성으로 전달에 대한 특성이 있다. 이 특성 값은 속달(Express)과 복구(Recoverable) 중에 하나로 지정될 수 있다. 메시지가 속달로 지정되어 있으면 메시지를 처리하는 모든 큐는 이 메시지를 디스크에 저장하지 않고 메모리에만 저장한다. 메모리에 저장하므로 빠른 메시지 전송이 가능하지만, 메시지가 큐에 저장되어 있는 상태에서 MSMQ 서버가 크래시된다면 이 메시지는 사라져 버리는 심각한 상황이 발생한다. 반면 복구로 표시되어 있는 메시지는 큐에 의해 항상 디스크에 기록된다. 디스크에 기록되어 있으므로 오류 상황에서 쉽게 복구될 수 있다. 개발자는 메시지의 특성을 잘 고려해 둘 중에 적절한 방식을 선택해야 한다.

수령 시간(Time to be received) 특성은 메시지가 전송된 후 큐에서 유지되어야 하는 시간을 규정한다. 만약 애플리케이션이 이 시간 내에 메시지를 받을 수 없다면 MSMQ는 이 메시지를 삭제한다. 큐 도달 시간(Time to reach queue) 특성은 메시지가 목적지 큐까지 도착하는데 소요되는 전체 시간을 규정한다. 만약 제 시간 내에 도착하지 못하거나 목적지에 이르는 경로에 오류가 발생했다면 MSMQ는 해당 메시지를 버린다.

메시지 동의(Acknowledge)

메시지를 보낸 후 해당 메시지가 어떻게 되었는지에 대한 대답은 메시지 동의 특성을 살펴봄으로써 알 수 있다.

Full Reach Queue : 메시지가 목적지 큐에 도착했거나 도착하지 못할 것 같은 경우(메시지 큐 도달 시간이 초과한 경우), MSMQ가 자동으로 동의 메시지를 전송하도록 설정한다.
Full Receive : 메시지가 도착했거나 도착할 것 같지 않은 경우(메시지 수령 시간이 초과한 경우)를 알리기 위해 동의 메시지를 보내도록 설정한다.
Nack Reach Queue : 메시지가 목적지 큐에 도착할 수 없음을 알리기 위해 동의 메시지를 보내도록 MSMQ를 설정한다. 오직 부결(negative ack nowledge) 메시지만 전송되기 때문에 전송자의 입장에서 보면 이 메시지를 받지 않는 것이 잘 전송됐음을 나타낸다.
Nack Receive : 메시지 수령 시간 타이머가 경과되었을 때 부결 메시지를 보내도록 설정한다.
None : MSMQ는 전송자가 동의 특성에 아무 값도 설정하지 않으면 동의 메시지를 보내지 않는다.
메시지 기록

메시지 큐의 가장 뛰어난 장점 중의 하나로 이미 전송된 메시지를 쉽게 기록할 수 있다. 애플리케이션은 각 메시지의 저널 특성을 설정해 이 메시지가 전송될 때 전송하는 시스템에 기록을 남기도록 할 수 있다. 만약 특성 값이 저널로 설정되면 메시지 복사 본은 저널 큐라는 특수한 큐에 저장된다. 이 큐는 어떤 메시지가 전송되었는지를 알고 싶어하는 모든 애플리케이션에 의해 참조될 수 있는 큐다.

여러 가지 이유로 인해 메시지가 전달될 수 없는 경우 저널 특성이 부여된 메시지는 삭제 편지(Dead Letter)로 설정되어 MSMQ의 삭제 편지 큐(Dead Letter Queue)에 저장된다. 만약 저널 특성에 어떠한 값도 지정되지 않으면 전송 후 저널 큐에 저장되지 않으며 수령되지 않을 경우 삭제 편지 큐에도 저장되지 않는다.

메시지 우선 순위

애플리케이션에서 몇몇 메시지는 다른 메시지보다 우선권을 가져야 하는 경우가 종종 발생한다. 예를 들어, 증권 중개용 애플리케이션에서 거래를 성립시키는 메시지는 주가를 보여주는 메시지 보다 우선권을 가져야 한다. MSMQ는 이러한 애플리케이션을 지원하기 위해 메시지마다 우선 순위 특성(Priority Property)을 부여할 수 있다. 높은 우선 순위를 갖는 메시지는 큐에 도착되는 순서와 상관없이 큐의 가장 앞쪽에 놓여진다.

메시지 응답

MSMQ 메시지의 특성 중 응답 큐 특성(Response Queue Property)은 메시지 수령자로 하여금 이 메시지에 대한 응답을 어디로 해야하는 지를 통지한다. 미리 정의된 큐만을 사용해 통신하는 경우에는 이 특성을 사용할 필요가 없지만 다양한 분산 애플리케이션 환경에서 꼭 필요한 기능이다. 이 특성을 설정한다고 해서 수령자가 반드시 응답을 해야하는 것은 아니다. 응답 여부는 전체 애플리케이션의 로직에 따른 것이지 이 특성과는 관련이 없다.

그리고 메시지 응답시 어떤 메시지에 대한 응답인지를 구분하기 위해 MSMQ는 메시지마다 고유의 ID를 부여한다. 메시지 수신자는 이 ID를 읽어 응답시 상관관계 ID 특성(Correlation ID Property)에 복사해 응답하고 송신자는 보낼 때의 고유 ID를 기록하고 있다가 응답으로 전송된 상관관계 ID 특성과 비교해 전송된 메시지에 대한 응답을 구분할 수 있다.

큐 특성

큐에 관한 가장 중요한 특성으로 큐 생성시 반드시 필요한 것으로 경로 명이 있다. 경로 명은 ‘machineX/myq ueue’와 같은 단순한 문자열로 큐가 존재하는 컴퓨터와 큐 이름을 나타내는 식별자 역할을 한다. 일단 이 특성이 큐에 설정되면 절대 변경할 수 없다.

쿼터 특성은 큐가 담을 수 있는 최대 크기를 바이트 단위로 설정한다. 만약 큐에 있는 모든 메시지 크기의 합이 이 한계치를 넘으면 더 이상 큐에 대한 메시지 전송은 이루어질 수 없다. 거부된 메시지는 동의 특성 값에 따라 동의 메시지가 만들어져 전송자에게 보내질 수 있다.

저널(Journal) 특성은 메시지가 큐로부터 저널 큐로 복사될 건지를 결정한다. 앞서 설명한 저널링은 메시지 기반으로 애플리케이션에서 전송된 메시지를 전송하면서 기록을 남기는 반면, 큐 기반의 저널링은 큐로부터 삭제되는 모든 메시지에 대한 기록을 남기며 큐 전체에 대해 이 옵션을 지정 또는 삭제할 수 있다.

베이스 우선 순위(Base Priority)는 큐 간 메시지를 라우팅할 때 어떤 메시지를 먼저 보낼 지에 대한 기준으로0사용된다. 높은 우선 순위를 가진 큐에 전송된 메시지는 낮은 우선 ?위를 갖는 큐에 전송된 메시지에 비해 좀더 신속하게 라우팅 될 것이다.

MSMQ와 트랜잭션

하나의 데이터베이스에 대해 트랜잭션을 수행하는 것은 데이터베이스 자체가 트랜잭션의 성공과 실패를 보장해 준다. 그러나 이러한 트랜잭션이 두 개 이상의 데이터베이스에서 이루어진다면 모든 데이터베이스에서 올바르게 트랜잭션이 처리되는 것을 보장하기 위해 트랜잭션 조정자를 사용한다. 윈도우 NT에서는 분산 트랜잭션 조정자(DTC) 서비스를 이용해 이러한 트랜잭션을 처리할 수 있다.

그러나 DTC를 사용해 직접 트랜잭션 기반 애플리케이션을 만드는 것은 쉬운 일이 아니다. COM 기반의 MTS를 이용하면 좀더 편리하게 이러한 애플리케이션을 만들 수 있다. MTS 역시 내부적으로는 DTC를 사용하지만 좀더 사용하기 쉬운 프로그래밍 인터페이스를 제공한다.

MTS에서 상세히 설명했다시피 DTC는 데이터베이스뿐만 아니라 OLE 트랜잭션을 지원하는 어떠한 자원 관리자와도 트랜잭션을 수행할 수 있다. 만일 MSMQ 역시 OLE 트랜잭션을 지원하는 자원 관리자가 된다면 분산 트랜잭션의 한 구성원이 될 수 있다. 인터넷을 통해 고객의 주문을 처리하는 웹 애플리케이션에서 주문이 발생하면 주문되는 상품에 대한 데이터베이스 변경이 이루어지며 그와 더불어 그 주문은 MSMQ 메시지를 통해 다른 컴퓨터(창고에 있는)로 전송되어 저장된다<그림 14>. 이 두 작업은 하나의 트랜잭션으로 묶여질 수 있으며, MTS를 이용하면 쉽게 구현할 수 있다.

큐가 트랜잭션에 참가하기 위해서는 큐 생성시 트랜잭션 특성을 설정해야 한다. 트랜잭션 특성이 설정되면 큐는 자원 관리자로써 DTC의 관리하에 다양한 트랜잭션에 참여하게 된다. 큐가 트랜잭션으로 지정되면 큐에 전송되는 모든 메시지는 메시지가 속한 트랜잭션이 완료될 때까지 계속 유지된다. 만약 트랜잭션이 커밋되면 메시지가 실제로 전송되고, 롤백되면 메시지가 전송되지 않고 큐에서 삭제된다. 이런 방법으로 트랜잭션이 처리되면 MSMQ는 메시지가 반드시 ‘단 한번’만 전송되도록 하며 여러 메시지가 정확한 순서대로 전달되도록 한다. 또한 트랜잭션 큐로 전달되는 모든 메시지는 전달(Delivery) 특성이 자동적으로 복구(Recoverable)로 설정되어 중간에 서버가 에러가 발생해도 메시지가 분실되지 않도록 한다.

COM+

기본 개념

COM+라는 용어를 처음 접하는 개발자라면 또 ‘뭔가 새로운 것이 나왔구나 ‘라고 지레 겁을 먹을지도 모르겠지만 그렇게 큰 걱정을 할 필요는 없다. 플러스 기호가 붙은 걸로 봐서 예전의 C 언어와 C++ 언어와의 관계 정도가 아닐까 하는 생각이 언뜻 들지 모르겠지만, 전혀 둘 사이는 무관하다. C++ 언어는 C와 완전히 다르다고 볼 수 있다. 이유는 C 언어는 절차언어인 반면 C++는 객체지향언어, 개발 방법이 완전히 다르기 때문에 모양새는 유사하지만 완전히 다른 언어로 취급한다. 하지만 COM+는 COM과 전혀 무관한 새로운 것이 아니다. 단지 좀더 발전된, 혁명이 아닌 진보 정도로 여기면 된다(아마 이러한 연유로 마이크로소프트는 플러스 기호를 하나만 사용했을지도).

COM은 프로그래밍 모델인 반면 COM+는 프로그래밍 모델을 보다 향상시키는 서비스의 집합이며, 분산 애플리케이션 개발에 필요한 여러 서비스를 제공한다. COM+를 이해하기 위한 전제로 우선 윈도우 DNA(Distributed interNet Application Architecture)에 대한 이해가 선행되어야 한다. DNA는 일종의 개발 프레임웍으로 마이크로소프트 윈도우가 제공하는 다양한 기술 및 서비스를 이용해 분산 애플리케이션을 개발하는 일련의 방법론을 의미하며, 다음과 같은 3티어 애플리케이션 개발에 초점을 맞추고 있다.

사용자 인터페이스 계층 - Forms+
미들 계층 - COM+
데이터베이스 계층 - Storage+
사용자 인터페이스 계층

마이크로소프트는 클라이언트용 사용자 인터페이스 구현을 위한 방법으로 Forms+를 개발하고 있으며, 이는 클라이언트 타입이 무엇이든(rich or thin) 상관없이 개발할 수 있는 일관된 솔루션을 제공한다. 아마 차기 개발툴쯤에 이와 관련된 기술이 선보이리라고 생각된다.

미들 계층

COM+의 모든 것이 존재하는 계층으로 현재까지 수년간 마이크로소프트가 투자한 분야다. 윈도우 NT 4.0 이전까지 개발툴은 RAD에 그 초점이 맞추어져 있었지만, 소프트웨어 기술이 발전하면서 미들 계층에 대한 끊임없는 요구가 발생했고, 이에 대한 최초의 응답이 MTS였다. MTS의 기본 목적은 트랜잭션 처리였으며, 트랜잭션 처리를 위한 많은 어려운 점을 해결해 개발자로 하여금 보다 비즈니스 로직 구현에 집중할 수 있는 환경을 제공하였다. 이후 마이크로소프트는 메시지 기반의 애플리케이션 개발 및 비연결 사용자를 위한 MSMQ를 발표하였다. 이러한 미들 계층 솔루션이 성숙되면서 윈도우와 이들을 통합시키게 되었고 이를 COM+로 명명하였다.

데이터베이스 계층

아직 Storage+에 대한 별다른 언급은 없지만 향후 윈도우 DNA를 구성하는 핵심적인 계층이 될 것이다. 현재 데이터베이스 계층은 ADO(ActiveX Data Object)와 OLE DB로 대표되며 아마 Storage+도 이를 기반으로 확장되지 않을까 예상된다.

컴포넌트 서비스

일반적으로 개발자가 컴포넌트를 개발하는데 있어 거의 30% 가량의 시간을 컴포넌트가 수행할 기본적인 업무인 비즈니스 로직 처리가 아닌 다른 부분에 쏟아 붓고 있다. 이러한 불필요한 프로그래밍 작업을 줄이고자 마이크로소프트는 COM+ 컴포넌트 서비스를 지원 컴포넌트 개발자에게 필요한 다양한 서비스를 제공해 개발자가 비즈니스 로직 구현에 보다 집중할 수 있게끔 만든다. <그림 15>에서 보듯이 COM에서 출발한 COM+는 분산 애플리케이션 환경에서 필요한 다양한 서비스를 제공하고 있다.

JIT(Just-In-Time) 실행

COM+의 가장 중요한 특징 중 하나는 미들-티어 컴포넌트로 그 성능을 확장해 수많은 동시 접속 사용자를 지원하는 환경을 제공하는데 있다. COM+ 환경에서는 클라이언트가 COM+ 객체를 생성하면 객체의 인터페이스를 직접 참조하는 것이 아니라 COM+가 구현한 컨텍스트 객체를 참조하는 모양이 된다. 따라서 실제 객체는 클라이언트가 생성했다고 해서 바로 메모리에 생성되지 않고 메쏘드가 호출될 때 비로소 생성한다. 클라이언트는 객체에 대한 참조를 계속 유지하지만 실제 COM+ 환경에서는 필요한 때에만 컴포넌트가 만들어지므로 효율적인 서버 리소스 관리가 가능해진다. 이러한 것을 JIT 실행이라고 하며 기존의 MTS 환경에서 소개되었다. 보다 자세한 내용은 ‘MTS 프로그래밍의 다섯 가지 규칙’을 참조 바란다.

객체 풀링(Object Pooling)

분산 애플리케이션의 전체적인 성능을 향상시키기 위해 COM+는 객체 풀링을 제공한다. 클라이언트 애플리케이션이 객체 풀링을 제공하는 객체를 릴리즈시킬 경우 COM+는 해당 객체를 제거하는 것이 아니라 동일 클라이언트 또는 다른 클라이언트를 위해 재사용한다. 클라이언트가 동일한 종류의 객체를 요구할 경우 COM+는 객체 풀에 요구되는 객체가 존재하면 새로 객체를 생성하지 않고 풀에 있는 객체를 반환한다. 만일 풀에 객체가 존재하지 않는다면 COM+는 새로 객체를 생성해서 제공할 것이다. 당연히 객체 풀링을 지원하는 컴포넌트는 새로 생성된 객체에 자신의 이전 상태를 복원시키는 기능을 제공해야 한다.

개발자는 자신이 개발하는 컴포넌트가 객체 풀링을 지원할지 말지를 결정해야 한다. 지원 여부의 기준은 객체 생성시 드는 비용과 풀에 객체를 유지하는데 들어가는 비용을 잘 저울질해야 한다. 객체를 생성해서 초기화하는데 많은 컴퓨팅 타임이 소모되는 대신 객체가 deactivate되었을 대 유지해야 하는 정보량이 적다면 당연히 객체 풀링을 지원하는 것이 좋다. 반면 객체 초기화 작업은 간단하지만 객체의 상태를 유지하는 정보가 많을 경우는 오히려 풀링을 지원하는 것이 좋지 않다.

MTS에서 객체 풀링이라는 말이 이미 언급되었지만 실제 구현되어 지원되지는 않았었다. 그러나 마이크로소프트는 이전의 약속을 지켜 COM+ 환경은 이를 지원한다.

로드 밸런싱

분산 COM+ 애플리케이션은 보통 수천이 넘는 사용자에게 빠르고 안정적인 서비스를 제공하는 것을 주목적으로 한다. 앞서 언급한 JIT 실행 및 객체 풀링은 하나의 서버 내의 제한된 자원을 보다 효율적으로 사용하는데 초점이 맞추어져 있으므로 COM+를 진정한 분산 환경으로 확장시키는 방법으로는 다소 무리가 있다. COM+는 컴포넌트를 네트워크의 여러 서버에 분산시켜 수행 가능하므로 업무 로드를 효과적으로 분산시켜 다수의 사용자에게 좋은 서비스를 제공할 수 있다. 이렇게 업무를 여러 컴퓨터에 분산시키는 것을 로드 밸런싱이라 부르며, COM+ 환경에서는 컴포넌트 수준에서 이를 지원한다. 클라이언트는 자신이 필요한 컴포넌트에 직접 연결을 요청하는 대신 로드 밸런싱 라우터에 연결한다. 로드 밸런싱 라우터는 분산 애플리케이션에 참여하고 있는 서버 정보를 기반으로 여러 서버에 업무를 분산시킨다. 여러 서버 중 선택된 서버에서는 클라이언트가 필요로 하는 객체를 생성하고 객체에 대한 참조를 클라이언트에 돌려준다. 추후 해당 컴포넌트에 대한 클라이언트 요청은 로드 밸런싱 라우터를 거치지 않고 지정된 서버로 바로 전달돼 처리된다.

많은 로드 밸런싱 알고리즘이 존재하지만 현재의 COM+ 환경은 simple response-time analysis 알고리즘을 사용한다(추후 COM+는 다양한 로드 밸런싱 알고리즘을 지원할 것이다). 또한 로드 밸런싱은 시스템 오류 상황에 대한 처리에도 유용하다. 한 클라이언트와 연결된 서버가 여러 가지 이유로 인해 다운됐을 때, COM+는 자동으로 서버 오류를 감지해 클라이언트의 요청을 다른 서버로 라우팅한다. 이러한 복구 방식은 전체적인 시스템 안정성을 높이는데 기여한다.

인-메모리 데이터베이스(IMDB)

인-메모리 데이터베이스는 부산 애플리케이션의 성능을 향상시키는 중요한 COM+ 서비스 중의 하나로 메모리 상에 데이터베이스 형태의 캐시를 구현해 빠른 데이터 액세스를 가능하게 한다. IMDB는 OLE DB 프로바이더 형태로 구현되며 동일 컴퓨터 내에 존재하는 데이터에 대해 빠른 액세스를 가능하게 만든다. 클라이언트는 이전과 마찬가지로 테이블, 인덱스 등을 사용하는데 ADO와 같은 고수준 컴포넌트를 그대로 사용하며, COM+가 이들 데이터에 대한 캐시를 제공하는 구조를 가진다.

Queued Components(QC)

QC는 마이크로소프트 메시지 큐 서버(MSMQ) 기반의 COM+ 서비스로, 컴포넌트 서버가 오프라인 상태 또는 오류 상태 등으로 작동하지 않을 경우에도 COM+ 컴포넌트에 대한 메쏘드 호출을 쉽게 가능하게 해준다. MSMQ 시스템은 컴포넌트 메쏘드 호출을 기록하고 큐잉하며 컴포넌트가 작동 가능한 상태가 되면 큐에 저장된 메쏘드 호출을 자동으로 진행시킨다. <그림 16>은 MSMQ가 클라이언트와 컴포넌트 사이에 데이터가 전달(메쏘드 호출)되는 방식을 보여준다