.NET Enterprise Services 성능
Richard Turner, 프로그램 관리자, XML Enterprise Services Microsoft Corporation 2004년 3월 적용 대상: 요약: 다른 활성화 및 호출 패턴에 적용될 때의 원시 COM+ 및 .NET Enterprise Services 구성 요소 성능을 확인합니다. .NET Enterprise Services 구성 요소를 C++의 COM+ 구성 요소처럼 빨리 실행하기 위한 지침과 함께 고성능 .NET Enterprise Service 구성 요소를 만드는 데 도움이 되는 주요 권장 사항을 살펴봅니다(45페이지/인쇄 페이지 기준). 관련 EnterpriseServicesPerf.exe 코드 샘플을 다운로드하십시오. 목차소개 |
소개
COM+ 코드를 "원시" Visual C++ 또는 Visual Basic 6에서 관리되는 .NET Enterprise Services 구성 요소로 이동할 것을 고려 중인 개발자는 다음과 같은 고민 사항이 있을 수 있습니다.
- 왜 관리되는 코드로 전환해야 하는가?
- 코드를 얼마나 변경해야 하는가?
- Enterprise Services 구성 요소는 어떻게 수행되는가?
- COM+ 및 .NET Enterprise Services가 제시하는 미래는 어떠한가?
이 문서에서는 특히 성능에 대한 질문을 위주로 위 주제를 다룰 것입니다. 이러한 주제에 대한 자세한 내용은 부록 4: 참고 자료에 있는 리소스를 참조하십시오.
이 문서는 COM+ 구성 요소를 개발하고 코드를 .NET Enterprise Services로 마이그레이션할 것을 고려 중인 개발자와 설계자를 대상으로 합니다.
관리되는 코드로 마이그레이션해야 하는 이유
개발자가 .NET에서 코드를 개발해야 하는 이유는 여러 가지입니다. 다음은 코드 개발의 몇 가지 이점입니다.
- 향상된 개발자 생산성: 개발자들은 종종 .NET을 사용하여 개발할 때 작성해야 하는 "통로 코드"가 훨씬 적기 때문에 응용 프로그램 논리를 작성하는 데 더 많은 신경을 쓸 수 있습니다. 또한 대부분의 개발자는 .NET에서 제공하는 명확하고 일관되게 구성된 풍부한 리소스 라이브러리 덕분에 다른 기술과 비교하여 훨씬 빨리 배울 수 있습니다.
- 향상된 코드 안정성 및 보안: 개발자는 원시 코드보다는 .NET을 사용할 때 안정적이고 보안된 코드를 더욱 쉽게 작성할 수 있습니다. 그 이유는 코드 액세스 보안 및 CLR(공용 언어 런타임) 같은 기능 때문입니다. 이러한 기능은 NET 코드가 다른 실행 중인 코드에 의도하지 않은 영향을 미치는 것을 방지하고 해커가 .NET 코드를 사용하여 환경을 방해하거나 제어할 수 있는 기회를 줄이는 데 도움이 됩니다.
- 향상된 성능 및 확장성: 개발자는 .NET으로 마이그레이션할 때 코드의 성능과 확장성이 향상되는 것을 알 수 있습니다. 모든 .NET 언어가 다중 스레딩 같은 기능을 지원하고 활용하기 때문입니다.
- XCOPY 배포: 대부분의 .NET 응용 프로그램에서는 필요한 파일을 하드 드라이브의 폴더로 복사하고 공유 구성 요소를 운영 체제에 선택적으로 등록하기만 하면 배포가 이루어집니다. 이는 다른 응용 프로그램에서 일반적으로 사용하는 것보다 훨씬 명쾌한 배포 전략입니다.
개발자가 .NET으로 마이그레이션하기를 원하는 10가지 이유에 대해서는 Top 10 Reasons for Developers to Use the .NET Framework 1.1 을 참조하십시오.
.NET은 시스템 관리자에게도 이점을 제공합니다. 관리자가 .NET으로 이동하기를 원하는 10가지 이유가 기록된 목록을 보려면 Top 10 Reasons for Systems Administrators to Use the .NET Framework 1.1 을 참조하십시오.
일반 C++ 코드를 관리되는 C++로 마이그레이션하는 방법에 대한 소개는 Managed Extensions for C++ Migration Guide의 Introduction to Wrapping C++ Classes 를 참조하십시오.
코드 변경 정도 지정
대부분의 경우 COM+ 코드를 .NET Enterprise Services에 연결하려면 COM+ 구성 요소가 어떠한 언어로 개발되었는지를 비롯한 다수의 요인에 따라 몇 가지 수동 작업이 필요합니다. 예를 들어, Visual Basic 6 개발자는 앞으로 나올 Visual Studio 2005의 도구에서 서브루틴 및 함수의 본문을 수정하지 않고도 클래스 정의 및 메서드 서명을 변환할 수 있는 몇 가지 지원을 받게 됩니다(다른 변환된 메서드에 대한 호출은 제외).
C++ 개발자는 COM+ 코드에서 .NET 코드로 변환하는 작업을 대부분 수동으로 수행해야 하지만, 대부분의 통로가 ATL(Active Template Library) 같은 클래스 라이브러리 대신 CLR에 구현되기 때문에 변환된 코드가 좀 더 간결해지는 것을 확인할 수 있습니다. C++ 개발자는 응용 프로그램을 연결할 언어를 선택할 수도 있습니다. 예를 들어, 기존 코드 기반을 최대한 활용하기 위해 관리되는 C++를 선택하거나, 더욱 간결한 코드를 위해 C#을 선택할 수 있습니다.
.NET Enterprise Services에 COM+ 구성 요소 연결
기존 COM+ 코드를 Visual Basic 6 및 Visual C++ 같은 원시 프로그래밍 언어와 도구로부터 마이그레이션하는 개발자는 .NET 코드로 완벽하게 변환하기 위해 몇 가지 기존 코드를 수정해야 합니다. 여기에 동반되는 작업 양은 사용할 수 있는 기존 코드 기반 및 도구에 따라 다릅니다. 다음 표에는 코드를 .NET으로 마이그레이션할 때 고려할 옵션이 요약되어 있습니다.
변환하기 전의 언어 | 변환한 후의 언어 | 코드 변환 도구 사용 가능 여부 | 필요한 코드 변환 작업 |
---|---|---|---|
Visual Basic 6 | Visual Basic .NET | 예(Visual Studio 2005) | 대부분의 Visual Basic 6 코드는 Visual Basic .NET에 직접 연결됩니다. Visual Studio 2005의 Visual Basic 6 코드 마이그레이션 도구는 대부분의 클래스와 메서드 선언 및 형식을 Visual Basic .NET 구문으로 변환합니다. |
Visual C++ | Visual C++ .NET | 아니요 | C++ .NET은 특히 원시 코드와 .NET 사이에서 상호 작동하는 코드를 작성하는 데 유용합니다. |
Visual C++ | Visual C# | 아니요 | C# 구문은 많은 면에서 C++와 비슷합니다. 변환을 수행하려면 개발자의 특정 작업이 필요합니다. |
.NET 특성
COM+ 구성 요소를 설치한 후에는 구성 요소 서비스 스냅인 도구를 사용하여 수동으로 구성하거나 스크립트 또는 코드를 통해 구성해야 합니다.
예를 들어, 구성 요소에 트랜잭션 지원이 필요하다고 표시하고 각 구성 요소의 AddSale() 메서드가 오류 없이 완료될 경우 트랜잭션을 자동으로 커밋하도록 지정하는 상황을 가정합니다. 그러기 위해서는 구성 요소 및 필요한 메서드의 속성을 COM+ 구성 요소 서비스 관리 콘솔에서 수동으로 구성해야 합니다.
- 구성 요소 서비스 관리 콘솔을 열고 올바른 응용 프로그램 및 구성 요소를 탐색합니다.
- 이 구성 요소의 속성을 열고 트랜잭션 탭을 클릭한 다음 필수를 클릭합니다.
- 확인을 클릭하고 구성 요소 탐색기를 통해 ATLPerfTests 개체의 AddSale() 메서드를 찾습니다.
- AddSale() 메서드를 마우스 오른쪽 단추로 클릭하고 메서드의 속성을 연 다음 이 메서드가 반환하면 자동으로 이 개체 비활성화 확인란을 선택합니다.
관리자는 일반적으로 보안 및 ID 설정 같은 배포 지향 설정이나 역할 구성원 및 재활용 같은 런타임 지향 설정을 구성합니다. 개발자는 트랜잭션 지원과 같은 구성 요소의 개발 지향 기능을 구성합니다. 그러나 COM+에서는 개발자가 코드 내에서 구성 요소의 구성 방법을 지정하기가 어렵습니다. Visual Basic 개발자는 구성 요소에 필요한 트랜잭션 지원을 어느 정도 지정할 수 있지만 C++ 개발자는 그렇지 못합니다. COM+ 구성 요소를 안정적이면서 반복적으로 설치하기 위해서는 스크립트, 설치 관리자 응용 프로그램 또는 설치 지침을 작성해야 합니다.
.NET은 개발자가 구성 요소의 코드 내에서 구성 요소에 필요한 서비스와 해당 서비스의 구성 방법을 지정할 수 있도록 함으로써 구성 요소 구성을 단순화합니다. 구성 요소가 설치되면 플랫폼에서 구성 설정을 자동으로 구성하지만, 이러한 구성 설정은 설치 후에 변경할 수 있습니다.
COM+에서는 설치 후에 구성 설정을 변경할 수 있기 때문에 이러한 속성을 다수 변경할 때는 매우 주의를 기울여야 합니다. 예를 들어, 보안 설정을 변경하면 개체를 인스턴스화하고 개체의 메서드를 호출할 수 있는지의 권한 지정에 영향을 미칠 수 있습니다. 반면에 트랜잭션 지원을 제거하면 구성 요소가 안정적이지 못하고 예측 불가능해질 수 있으며 구성 요소의 데이터가 손실되거나 손상될 수도 있습니다.
개발자는 특성(C# 및 C++에서는 [attribute]와 같이 대괄호 안에 표시되고, Visual Basic .NET에서는 <attribute>와 같이 꺾쇠괄호 안에 표시됨)을 사용하여 어셈블리, 응용 프로그램, 구성 요소 또는 메서드의 요소를 구성합니다. 예를 들어, 아래 코드에서는 SimpleTest 구성 요소에 트랜잭션이 필요하며, AddSale() 메서드가 오류 없이 완료될 경우 트랜잭션이 자동으로 완료된다는 것을 보여줍니다.
C#
[Transaction(TransactionOption.RequiresNew)] public class SimpleTest: ServicedComponent { ... [AutoComplete]public void AddSale(int orderNumber, int storeID, int titleID, int qty) { ... } ... }
Visual Basic .NET
<Transaction(TransactionOption.RequiresNew)> _Public Class VBTestObject : Inherits ServicedComponent ...<AutoComplete> _Public Function Sum(ByVal number1 As Integer, ByVal number2 As Integer) As Integer ... End Function ... End Class
다음 표에는 Enterprise Services 구성 요소에 적용할 수 있는 주로 사용되는 특성이 들어 있고, 설치 후에 특성을 안전하게 변경할 수 있는지 여부가 표시되어 있습니다.
특성 | 범위 | 기본 소유자 | 실행 중에 안전하게 수정 가능한지의 여부 |
---|---|---|---|
ApplicationAccessControl | 어셈블리 | 개발자 | 아니요. 개발자가 응용 프로그램의 보안 방법에 대한 하드 종속성 또는 묵시적 종속성을 사용하여 코드를 작성했을 수 있습니다. 액세스 제어를 낮추면 시스템 보안이 손상될 수 있습니다. |
ApplicationActivation | 어셈블리 | 관리자 | 예. 그러나 주의해야 합니다. 라이브러리 또는 서비스로 변경하거나 이로부터 변경하면 성능에 영향을 미칠 수 있으며 대기 중인 구성 요소가 손상될 수 있습니다. |
ApplicationID | 어셈블리 | 개발자 | 예. 그러나 주의해야 합니다. 이 특성을 변경하면 하드 코딩된 구성 요소 등록 도구에 영향을 미칠 수 있습니다. |
ApplicationName | 어셈블리 | 개발자 | 예. 그러나 주의해야 합니다. 이 특성을 변경하면 하드 코딩된 구성 요소 등록 도구에 영향을 미칠 수 있습니다. |
ApplicationQueuing | 어셈블리 | 개발자 | 아니요. |
AutoComplete | 메서드 | 개발자 | 아니요. 아래의 "Transaction"을 참조하십시오. |
ComponentAccessControl | 클래스 | 개발자 | 아니요. 개발자는 구성 요소의 보안 방법에 대한 하드 종속성 또는 묵시적 종속성을 사용하여 코드를 작성했을 수 있습니다. 액세스 제어를 낮추면 시스템 보안이 손상될 수 있습니다. |
ConstructionEnabled | 클래스 | 관리자 | 예. 생성자 문자열을 변경할 수는 있지만, 설정/해제 상태를 전환하지는 마십시오. |
Description | 어셈블리 클래스 메서드 인터페이스 | 관리자 | 예. |
EventTrackingEnabled | 클래스 | 관리자 | 예. |
InterfaceQueuing | 클래스 인터페이스 | 개발자 | 아니요. |
JustInTimeActivation | 클래스 | 개발자 | 아니요. |
MustRunInClientContext | 클래스 | 개발자 | 아니요. 구성 요소가 클라이언트의 컨텍스트와 호환되지 않을 수도 있습니다. |
ObjectPooling | 클래스 | 개발자 | 예. 풀 설정은 변경할 수 있습니다. 구성 요소가 손상될 수 있기 때문에 개체 풀링 설정/해제 상태를 전환하지는 마십시오. |
PrivateComponent | 클래스 | 개발자 | 아니요. 이 구성 요소를 공개적으로 호출할 수 없도록 개발자가 특별히 지정한 것입니다. 구성 요소가 알 수 없는 사용 패턴을 지원하는지에 대한 테스트를 받지 않았을 수도 있습니다. 공개되는 경우 심각한 보안 위협을 초래할 수 있습니다. |
SecurityRole - 역할 이름 | 어셈블리 클래스 인터페이스 | 개발자 | 아니요. 역할을 제거하지 마십시오. 개발자가 지정된 역할에 대한 명시적 종속성 또는 역할 존재에 대한 묵시적 예외를 사용하여 코드를 작성했을 수 있습니다. |
SecurityRole - 역할 구성원 | 어셈블리 클래스 인터페이스 | 관리자 | 예. 그러나 주의해야 합니다. 액세스 제어를 너무 광범위하게 공개하면 시스템의 보안이 손상되고, 너무 제한되게 공개하면 액세스가 과도하게 제한될 수 있습니다. |
Synchronization | 클래스 | 개발자 | 아니요. |
Transaction | 클래스 | 개발자 | 아니요. 구성 요소의 트랜잭션 지원을 수정하면 시스템의 안정성과 무결성이 손상될 수 있습니다. |
위 표는 구성 요소 개발자가 기본적으로 소유하는 구성 요소와 관리자가 기본적으로 소유하는 구성 요소도 보여 줍니다. 코드에 미치는 영향을 자세히 알고 있는 경우가 아니라면 개발자의 설정을 변경하지 않는 것이 좋습니다. 개발자가 지정한 보안 관련 특성을 관리자가 변경할 수는 있지만, 이 경우에는 구성 요소 또는 응용 프로그램에 대한 액세스를 충분히 제한하되 너무 과도하게 제한하지는 않도록 주의를 기울여 보안을 구성해야 합니다.
특성을 통해 개발자는 자신의 구성 요소에 대한 구성 요구 사항을 간단하고 효율적으로 지정하면서 설치 후에 관리자가 구성 설정을 변경할 수 있도록 합니다. Enterprise Services가 제공하는 특성에 대한 자세한 내용은 .NET Framework Class Library 를 참조하십시오.
.NET Enterprise Services와 COM+ 성능 비교
Enterprise Services의 성능을 COM+와 비교하여 측정하기 위해 다음 언어로 구성 요소를 만들었습니다.
- Visual C++ .NET 및 ATL COM+
- Visual Basic 6 COM+
- C# 및 .NET Framework 1.1 Enterprise Services
- Visual Basic .NET 및 .NET Framework 1.1 Enterprise Services
각 구성 요소에는 두 개의 공용 메서드가 포함되어 있습니다.
- Sum(): 이 간단한 메서드는 두 숫자를 합해 디스크 또는 데이터베이스 액세스 작업을 수행하지 않는 간단한 작업을 시뮬레이트합니다.
- AddSale(): 이 일반적인 메서드는 트랜잭션되며, 테이블에 레코드를 삽입하고 반환 전에 트랜잭션을 완료하는 개인 메서드인 InsertSale()을 호출합니다. 이 메서드는 일반적인 비즈니스 응용 프로그램 작업을 수행하는 "실제" 메서드의 성능 특징을 보여 줍니다.
그 다음에는 각 구성 요소에 대해 다음 테스트를 수행한 테스트 프로그램을 만들었습니다.
- 반복적인 만들기/호출/릴리스: 이 테스트는 개체를 만들고 호출하고 릴리스하는 과정을 반복적으로 수행합니다.
- 만들기/반복 호출/릴리스: 이 테스트는 개체를 인스턴스화하여 수천 번 호출한 다음 마지막에 개체를 릴리스합니다.
테스트 프로그램에서는 각 구성 요소에 대해 두 가지 테스트를 모두 실행했으며 결과를 쉼표로 분리된 파일에 작성하는 고해상도 타이머를 사용하여 각 테스트를 수행하는 데 걸린 시간을 측정했습니다. 이 파일의 결과를 Microsoft Excel로 가져와서 분석했습니다. 각 구성 요소에 대한 코드 목록은 부록 5: 성능 테스트 소스 코드를 참조하십시오.
테스트는 다음 표에 표시된 구성으로 설정된 컴퓨터에서 실행되었습니다.
컴퓨터 1: 서버 컴퓨터 | 컴퓨터 2: 클라이언트 컴퓨터/단일 컴퓨터 | |
---|---|---|
CPU | Dual Pentium 4 Xeon 3.06GHz | Dual Pentium 4 Xeon 2.8GHz |
RAM | 1GB | 1GB |
디스크 | 로컬 SCSI | 로컬 SCSI |
네트워크 | 기가비트 이더넷 | 기가비트 이더넷 |
OS 및 .NET | Windows Server™ 2003 .NET Framework 1.1 | Windows Server 2003 .NET Framework 1.1 |
다른 하드웨어에서 테스트 응용 프로그램을 실행할 때 나타나는 특정 결과는 아래에 보고된 결과는 물론, 서로 간에도 다를 수 있습니다. 그러나 각 결과는 여기에 소개된 결과와 비례해야 합니다.
테스트 결과 및 분석
다음 절에서는 이전에 논의한 코드에 대해 실행한 성능 테스트의 결과를 분석합니다. 이 결과는 위에 나열된 하드웨어와 소프트웨어에서 테스트를 실행하여 얻은 것입니다. 모든 결과의 목록은 부록 6: 테스트 결과에 포함되어 있습니다.
결과를 보여 주는 다음 차트에서 차트 막대 길이가 길거나 숫자가 클수록 성능이 뛰어난 것입니다.
개체 활성화 및 삭제 성능
먼저 C++ 및 Visual Basic 6을 사용하여 개발한 원시 COM+ 구성 요소의 성능을 통해 COM+ 인프라가 어떻게 수행되는지를 살펴보겠습니다. 아래 차트는 개체 만들기, 간단한 메서드 호출 및 개체 릴리스를 반복적으로 수행함으로써 얻은 초당 호출 수를 보여 줍니다.
MTS(Microsoft Transaction Server) 1.0의 원래 디자이너는 이와 비슷한 데이터를 보고서 호출을 배달하는 데 필요한 인프라, 즉 프록시, DCOM(또는 프로세스간) 채널, 스텁 및 컨텍스트를 설정함으로써 프로세스 간 및 컴퓨터 간 활성화 시간에 큰 영향을 미칠 수 있다는 것을 깨달았습니다. 이 점이 다음을 수행하는 JIT(Just In Time) 활성화를 디자인하게 된 기본적인 동기였습니다.
- 서버 구성 요소가 반환 이전에 SetComplete() 또는 SetAbort()를 호출하여 자체 수명 주기를 제어할 수 있도록 합니다.
- 여러 메서드 호출을 사용하여 DCOM 통로를 설정하는 부담을 줄입니다.
다음 차트는 JIT 활성화를 활용하는 수정된 테스트를 단일 개체를 만들고 두 숫자를 합하는 간단한 메서드를 반복적으로 호출한 다음 마지막에 개체를 릴리스하는 방법으로 실행할 경우 발생하는 상황을 보여 줍니다.
이 결과는 JIT 활성화를 사용할 때 초당 호출 수 면에서 성능이 크게 향상되는 것을 보여 줍니다. JIT 활성화 및 Visual Basic 6을 사용하면 JIT 활성화를 사용하지 않는 C++보다 거의 33배 빠른 결과를 얻을 수 있습니다. JIT가 활성화된 Visual Basic 6에서는 초당 호출 수가 약 8600인 반면 JIT가 활성화되지 않은 Visual C++에서는 초당 호출 수가 약 261입니다.
작업을 수행하는 데 필요한 통로를 설정한 이후 컴퓨터 간 호출을 수행하면 네트워크가 성능에 큰 영향을 미치게 됩니다. 이 경우 Visual Basic 6 및 C++는 성능이 거의 비슷하지만, 그래도 Visual Basic 6가 C++보다 88% 빨리 수행됩니다.
Enterprise Services에서는 필요한 통로를 설정하는 추가 작업이 수행됩니다. 특히 개체를 생성하고 릴리스하기 위한 추가 호출이 필요합니다. 따라서 개체에서 아무런 작업을 수행하지 않고 단순히 개체를 만들었다 제거하는 경우를 비교할 때 이러한 추가 왕복 부담이 성능 비교에 큰 영향을 미치게 됩니다. Visual Studio 2005에서는 Enterprise Services가 향상되어 이러한 활성화 왕복 중 하나가 제거되었기 때문에 "활성화/단일 호출/릴리스" 패턴을 사용할 때 .NET Framework 1.1과 비교하여 성능이 20-30% 향상됩니다. 그러나 가능하면 이러한 패턴은 사용하지 않는 것이 좋습니다.
JIT 활성화를 사용할 때 C++ 및 Visual Basic 6의 성능이 비슷하다는 것을 고려하면 C# 및 Visual Basic .NET을 사용하는 Enterprise Services도 대략 같은 성능을 보일 것으로 예상할 수 있습니다. 아래 그림은 간단한 메서드를 호출하는 위 테스트를 실행한 결과를 보여 줍니다.
이 데이터는 단순히 두 정수를 합하고, 개체의 컨텍스트에 SetComplete()를 호출하고, 결과를 반환하는 간단한 메서드에 대해 수행한 초당 호출 수를 보여 줍니다. 개체를 활성화하고 릴리스하는 부담은 거의 사라졌지만 버퍼를 마샬링하고 호출 스택으로 변환하는 등의 작업으로 인해 호출을 수행하는 부담은 아직 남아 있습니다.
이처럼 매우 간단한 메서드에서도 프로세스 간 호출의 경우 Enterprise Services는 Visual Basic 6과 성능이 거의 비슷합니다. 컴퓨터간에 호출할 경우에는 모든 언어의 성능이 거의 비슷합니다.
그러나 일반적인 비즈니스 응용 프로그램은 메서드에서 이보다 더 복잡한 작업을 수행합니다. 다음 차트는 일반적인 메서드를 호출하여 분산 트랜잭션 내에서 데이터베이스 연결을 열고 간단한 SQL 문을 실행하는 동일한 응용 프로그램을 네 가지 언어로 작성했을 때 각각의 상대적인 성능을 보여 줍니다.
앞의 결과는 메서드 내에서 많은 작업을 수행할 경우 모든 언어의 결과가 실험 오차 범위 내에서 동등하다는 것을 보여 줍니다. ADO를 사용하는 C++ 및 Visual Basic 6을 통해 작성한 COM+ 원시 응용 프로그램은 Enterprise Services를 사용하는 C# 또는 Visual Basic .NET 응용 프로그램과 동일한 속도로 수행됩니다. 프로세스 간 작업을 실행하거나 컴퓨터 간 작업을 실행하는 경우 성능 면에서는 거의 차이가 없습니다.
결과 요약
위 결과는 구성 요소를 최대한 효율적으로 수행하는 데 있어서 JIT 활성화 및 "만들기/반복 호출/릴리스" 패턴이 매우 중요하다는 것을 보여 줍니다.
결론
코드를 .NET으로 마이그레이션하는 것이 유리한 몇 가지 주요 이유를 설명했습니다. 다른 활성화 및 호출 패턴에 적용될 때의 원시 COM+ 및 .NET Enterprise Services 구성 요소 성능에 대해서도 논의했습니다. 또한 지침을 따라가면서 .NET Enterprise Services 구성 요소가 C++ COM+ 구성 요소만큼 빨리 실행된다는 것을 보여 주었습니다. 부록 1: 성능 권장 사항에는 고성능 .NET Enterprise Service 구성 요소를 만드는 데 도움이 되는 주요 권장 사항이 나와 있습니다.
여기에 설명된 기술을 일관되게 적용하면 기존 COM+ 코드를 .NET Enterprise Service 구성 요소로 바로 변환하고 아무런 성능 저하 없이 .NET Framework의 사용성, 보안 및 개발자 생산성 등의 이점을 누릴 수 있습니다.
지금 COM+ 구성 요소를 Enterprise Services 구성 요소로 변환해 놓으면 나중에 코드를 "Indigo"로 더욱 쉽게 마이그레이션할 수 있다는 점도 중요합니다. 부록 2: "Indigo" 및 .NET의 동향에서는 이 주제에 대해 간략히 논의합니다.
부록 1: 성능 권장 사항
다음 절에서는 높은 수준의 성능을 제공하는 빠른 COM+ 및 Enterprise Services 구성 요소를 만드는 방법에 대한 팁과 안내를 제공합니다. 대부분의 제안은 .NET Enterprise Services 구성 요소와 원시 COM+ 구성 요소에 동일하게 적용됩니다.
해당하는 경우 개체 풀링 및 JIT 활성화 사용
위의 테스트 결과가 보여주듯이 메서드 호출이 구성 요소 활성화보다 빠르며 관리되지 않는 구성 요소의 활성화가 Enterprise Services 구성 요소의 활성화보다 빠릅니다. 따라서 구성 요소 기반 응용 프로그램의 속도를 최대한 높이려면 코드에서 구성 요소 활성화 및 삭제의 수를 최소화하는 것이 중요합니다.
COM+에서는 개체 활성화를 최소화할 수 있는 두 가지 서비스를 제공합니다.
- 첫 번째는 앞에서 설명했듯이 호출자가 개체에 대한 활성 참조를 보관하고 있는 동안 해당 개체를 원활하게 비활성화할 수 있는 COM+ 서비스인 JIT(Just-in-time) 활성화입니다. 클라이언트가 개체에 메서드를 호출하기만 하면 COM+가 개체의 할당을 동적으로 관리하여 요청을 처리합니다.
- 두 번째는 해당 형식의 구성 요소 인스턴스를 요청하는 클라이언트가 바로 사용할 수 있도록 개체를 풀에서 활성 상태로 유지하는 개체 풀링입니다. COM+는 풀을 자동으로 관리하며, 개체 활성화 정보를 처리하고 사용자가 지정한 기준(예: 풀 크기)에 따라 다시 사용합니다.
풀링된 구성 요소 및 JIT 활성화된 구성 요소에 대한 참조를 보관하고 다시 사용함으로써 구성 요소 활성화 및 삭제를 최소화하고 높은 수준의 성능을 얻을 수 있습니다.
COM+ JIT 활성화 및 개체 풀링에 대한 자세한 내용은 Platform SDK: COM+ (Component Services) 설명서 를 참조하십시오.
왕복 회피
COM+ 구성 요소의 성능을 최적화하려면 호출자와 구성 요소 사이에 수행되는 프로세스 간 또는 컴퓨터 간 호출의 수를 최소화하는 것이 중요합니다. COM+ 구성 요소에서 만들어진 모든 메서드는 프로세스 간 호출 전환은 물론 컴퓨터 간 호출 전환도 초래하며, 매번 전환할 때마다 시간이 걸립니다. 따라서 COM+ 개체에서 만들어지는 메서드 호출을 최소한으로 유지하는 것이 필수적입니다. 그러기 위해 단일 호출에서 최대한 많은 작업을 수행하는 메서드를 사용하여 COM+ 구성 요소를 디자인하는 것도 좋은 방법입니다. 단, 이 경우에는 순수 아키텍처에서 변형된 구성 요소도 디자인해야 합니다.
COM+ 서비스 사용 최적화
COM+가 중요한 서비스를 다수 제공하기는 하지만 이러한 서비스를 현명하게 사용하는 것이 중요합니다. COM+가 구성 요소에 필요한 서비스를 제공하는 경우에는 대개 이 서비스가 가장 높은 성능을 제공하므로 반드시 사용하도록 하십시오. 그러나 서비스가 필요하지 않은 경우에는 구성 요소가 불필요한 작업을 수행하여 실행 속도도 느려질 수 있으므로 해당 서비스를 사용할 필요가 없습니다.
COM 마샬링 가능 매개 변수 사용
호출자가 데이터를 전달할 때 사용하는 매개 변수를 Enterprise Services 구성 요소의 메서드가 받아들이는 경우 다음과 같이 COM과 .NET 사이에 쉽게 마샬링할 수 있는 형식을 사용할 것을 매우 강력히 제안합니다.
- Boolean
- Byte, SByte
- Char
- DateTime
- Decimal
- Single, Double
- Guid
- Int16, UInt16, Int32, UInt32, Int64, UInt64
- IntPtr, UIntPtr
- String
이러한 형식만 사용하고 다른 복잡한 형식(예: 구조 또는 배열)은 전달하지 않으면 .NET serializer가 호출 처리 스택을 최적화하고 호출을 유선(RPC의 경우) 또는 가상 유선(LRPC의 경우)에 일렬로 직렬화할 수 있습니다. 그러면 호출이 더욱 빨리 실행됩니다. 그러나 메서드에 복잡한 형식이 필요한 경우에는 코드가 일반 DCOM 호출 스택을 통해 호출되므로 추가 처리 과정이 발생합니다.
파이널라이저 사용하지 않기
Enterprise Services 구성 요소에서 파이널라이저(C# 및 C++의 ~Classname() 소멸자)를 구현하지 마십시오. 파이널라이제이션은 가비지 수집기의 단일 스레드 작업입니다. Enterprise 구성 요소를 파이널라이제이션할 경우 완료되는 데 상당한 시간이 걸리므로 가비지 수집기 성능이 저하됩니다. 가비지 수집기 엔진이 실행 중인 동안에는 응용 프로그램에서 다른 작업을 수행할 수 없으므로 가비지 수집기가 완료되는 데 오랜 시간이 걸리면 전체 응용 프로그램의 성능이 저하됩니다.
대신 개체에서 Dispose(bool)을 재정의하고 Dispose(true)가 호출될 때 파이널라이제이션 형식 작업을 수행하는 것을 고려해 보십시오. 또한 이러한 종료 코드를 최대한 정돈되고, 안전하고, 간단하게 유지하도록 하십시오.
단일 스레드 COM+ 구성 요소 만들지 않기
여러 스레드의 동시 액세스를 지원하지 않는 개체는 STA(단일 스레드 아파트) 기능을 지원하는 것으로 표시되어 있습니다. 여러 스레드가 같은 인스턴스에 동시 액세스할 수 있도록 지원하는 구성 요소는 MTA(다중 스레드 아파트) 인식으로 표시되어 있습니다.
.NET Enterprise Services 구성 요소는 항상 STA 및 MTA를 모두 지원하는 것으로 표시되어 있기 때문에 더 이상 이 논의에 포함시키지 않겠습니다.
모든 Visual Basic 6 COM+ 구성 요소는 STA입니다. C++ COM+ 개발자는 구성 요소를 STA, MTA 또는 둘 다로 표시할 수 있습니다.
STA COM+ 구성 요소의 잠재적인 문제는 개체가 단일 스레드에서만 실행될 수 있으므로 해당 스레드가 개체의 메서드를 실행하는 유일한 스레드라는 것입니다. 이 직렬화를 통해 개발자는 STA 구성 요소를 더욱 쉽게 작성할 수 있지만, 도메인 간 마샬링이 종종 필요해서 성능이 저하되고 STA에서 한 스레드만 계속 실행됨으로 인해 확장성이 떨어지는 것은 피할 수 없습니다.
가능하면 STA 구성 요소를 만들거나 사용하지 않을 것을 제안합니다. 특히 확장성이 중요한 곳에서는 더욱 그렇습니다. 구성 요소가 다른 COM+ 구성 요소를 호출하는 경우 특히 STA 스레딩을 피해야 합니다. 이러한 호출에는 종종 스레드 전환이 필요한데, 스레드 전환은 해당 아파트에 있는 다른 모든 COM+ 구성 요소를 차단합니다.
설상가상으로 가비지 수집기의 파이널라이저도 개체를 소유한 STA 스레드를 호출할 때 차단됩니다. 그러면 파이널라이제이션 프로세스가 단일 스레드에 직렬화되며, 이는 이전 주제에서 설명했듯이 시스템 성능을 크게 저하시킬 수 있습니다.
부록 2: "Indigo" 및 .NET의 동향
Microsoft에서 현재 개발 중인 연결된 응용 프로그램을 위한 새로운 플랫폼, 코드 이름 "Indigo"에 대해 들어 보셨을 것입니다. 그렇다면 "Indigo"란 과연 어떤 제품일까요?
"Indigo"는 서비스 지향 연결 응용 프로그램을 위한 Microsoft의 전략적 기술 플랫폼으로서, 로스앤젤레스에서 개최된 2003 PDC(Professional Developers Conference)에서 소개되었습니다.
"Indigo"는 다음 기술의 개념, 특징 및 기능을 하나의 기술 스택으로 통합합니다.
- COM
- DCOM
- COM+/Enterprise Services
- ASMX/Web Services
- .NET Remoting
- 향상된 웹 서비스
- MSMQ의 요소
"Indigo"는 서비스를 호출자에게 노출하는 데 필요한 프로토콜 및 전송으로부터 서비스의 개념을 추상화하는 다계층 플랫폼입니다. 최대한 많은 시스템과 상호 작동하기 위해 "Indigo"는 HTTP, TCP 및 IPC를 통한 고급 웹 서비스(WS-*)를 완벽하게 지원합니다. 현재 Microsoft는 코드 이름이 "Longhorn"인 Microsoft Windows의 출시 시기에 맞춰 "Indigo"를 배포할 예정입니다. Windows XP 및 Windows Server 2003에 대한 "Indigo" 지원도 함께 배포될 것입니다.
향후 "Indigo"가 발표된다고 하니 .NET Enterprise Services(또는 이 경우 ASMX 및 Remoting) 같은 기존 기술이 오늘날의 연결된 응용 프로그램을 개발하는 데 아직 유효한 것인지 걱정할 수도 있습니다. ASMX & WSE, Enterprise Services, Remoting 및 MSMQ는 오늘날의 엔터프라이즈 수준 솔루션에 가장 적합한 기술입니다. 적절하게 사용하면 "Indigo"가 릴리스되고 널리 사용될 때까지 훌륭한 응용 프로그램 개발 플랫폼을 제공해 줄 것입니다.
.NET을 사용하여 새 응용 프로그램을 작성하고 기존 응용 프로그램을 .NET으로 마이그레이션하면 향상된 보안, 안정성, 관리 및 확장성의 혜택을 누릴 수 있습니다. 또한 "Indigo"로 업그레이드하는 것이 원시 코드보다 훨씬 쉬워질 것입니다. 응용 프로그램의 "Indigo" 업그레이드를 준비하는 방법과 기존 기술을 사용하여 "Indigo"와 상호 작동하는 방법에 대한 자세한 내용은 나중에 MSDN을 참조하십시오.
"Indigo"에 대한 자세한 소개는 MSDN Magazine 기사, Code Name Indigo: A Guide to Developing and Running Connected Systems with Indigo 를 참조하십시오. 이 기사에 제공된 아키텍처 개요를 통해 이후의 Microsoft 응용 프로그램 플랫폼을 미리 살펴볼 수 있습니다.
"Indigo"에 대한 일반적인 내용은 Microsoft "Indigo" Frequently Asked Questions 를 참조하십시오.
부록 3: 분산 트랜잭션이 성능에 미치는 영향
위 테스트를 진행하면서 "COM+ 분산 트랜잭션이 이러한 구성 요소에 얼마나 많은 영향을 미칠까?"라는 질문이 생길 수도 있습니다. 이 질문의 답을 찾기 위해 각 구성 요소에 대해 COM+에서 "트랜잭션 필요" 설정을 끄고 테스트를 다시 실행해 보았습니다. 그 결과는 다음 차트에 표시되어 있습니다.
위 차트에서 볼 수 있듯이 COM+ 트랜잭션 지원이 없는 구성 요소의 성능과 트랜잭션이 켜져 있는 구성 요소의 성능은 거의 동일합니다. 이 결과는 테스트에서 COM+ 트랜잭션의 영향을 무시해도 상관없다는 것을 분명하게 보여 줍니다.
부록 4: 참고 자료
Upgrading Microsoft Visual Basic 6.0 to Microsoft Visual Basic .NET
Visual Basic 6.0 응용 프로그램을 Visual Basic .NET으로 업그레이드하는 내용을 다루며 프로그래밍 팁, 요령 및 단계별 코드 비교 내용을 함께 제공합니다.
Programming with Managed Extensions for Microsoft Visual C++ .NET
Visual C++ .NET 2003에 맞춰 업데이트된 이 책은 개발자를 위해 컴파일러의 새 기능과 언어에 대한 링커 확장을 심층적이고 전문적으로 다룹니다.
.NET Enterprise Services and COM+ 1.5 Architecture
Microsoft .NET 및 Enterprise Services가 어떻게 조화를 이루는지 보여 주고 COM+/Enterprise Services 구성 요소를 빌드, 제어, 관리 및 보안하는 방법을 설명합니다.
.NET Framework Developer Center의 Performance 페이지
고성능 코드를 작성하는 방법과 발생하는 문제를 진단하는 방법에 대해 심도있게 다루는 여러 링크와 리소스가 제공됩니다.
Performance Tips and Tricks in .NET Applications
.NET 응용 프로그램이 제대로 수행되도록 하기 위한 팁과 힌트를 모아 놓았습니다.
Writing Faster Managed Code: Know What Things Cost
.NET 코드에서 다양한 작업이 시스템에 어떤 부담을 주는지 자세히 분석한 내용입니다.
Garbage Collector Basics and Performance Hints
가비지 수집기의 작동 방법, 가비지 수집기가 코드에 미치는 영향, 가비지 수집의 영향을 최소화하도록 코드를 작성하는 방법 등에 대해 설명합니다.
Performance Considerations for Run-Time Technologies in the .NET Framework
가비지 수집 및 메모리 사용, JIT, 스레딩, .NET Remoting, 보안 등의 주제를 다룹니다.