파이프라인 성능 최적화
이 항목에서는 BizTalk Server 솔루션에서 파이프라인 성능을 최적화하기 위한 지침을 설명합니다.
BizTalk Server 파이프라인의 성능을 최적화하기 위한 모범 사례
파이프라인 구성 요소는 성능에 상당한 영향을 주므로(예: 통과 파이프라인 구성 요소가 XML 어셈블러/디스어셈블러 파이프라인 구성 요소보다 최대 30% 더 나은 성능을 발휘함) 배포에서 구현하기 전에 사용자 지정 파이프라인 구성 요소가 최적으로 수행되도록 합니다. BizTalk 애플리케이션의 전반적인 성능을 최대화하려면 사용자 지정 파이프라인의 파이프라인 구성 요소 수를 최소화합니다.
또한 파이프라인 구성 요소에서 메시지 지속성 빈도를 줄이고 구성 요소를 코딩하여 중복성을 최소화하여 전반적인 성능을 향상시킬 수 있습니다. 모든 사용자 지정 어셈블리 및 사용자 지정 추적 구성 요소와 같이 성능을 방해할 수 있는 특정 아티팩트를 부하가 많은 상태에서 별도로 테스트하여 시스템이 전체 용량에서 작동할 때 동작을 관찰하고 가능한 병목 상태를 찾아야 합니다.
파이프라인 구성 요소 내에서 인바운드 메시지를 읽어야 하는 경우 XmlDocument 개체를 사용하여 전체 문서를 메모리에 로드하지 마십시오. XmlDocument 클래스의 instance XML 문서의 메모리 내 표현을 로드하고 만드는 데 필요한 공간의 양은 실제 메시지 크기의 최대 10배입니다. 메시지를 읽으려면 다음 클래스의 instance 함께 XmlTextReader 개체를 사용해야 합니다.
VirtualStream(Microsoft.BizTalk.Streaming.dll) - 이 클래스의 소스 코드는 다음과 같이 Pipelines SDK 아래의 두 위치에 있습니다. SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler 및 SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.
ReadOnlySeekableStream(Microsoft.BizTalk.Streaming.dll).
SeekAbleReadOnlyStream - 이 클래스의 소스 코드는 다음과 같이 Pipelines SDK 아래의 두 위치에 있습니다. SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler 및 SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.
가능하면 PassThruReceive 및 PassThruTransmit 표준 파이프라인을 사용합니다. 파이프라인 구성 요소는 포함하지 않으며 메시지 처리를 수행하지 않습니다. 이러한 이유로 메시지를 받거나 보내는 데 최대 성능을 보장합니다. 이진 메시지를 보내야 하는 경우 이진 문서를 BizTalk MessageBox에 게시하고 송신 포트의 PassThruTransmit 파이프라인에 게시해야 하는 경우 수신 위치에서 PassThruReceive 파이프라인을 사용할 수 있습니다. 메시지 형식이 지정되고 전송할 준비가 된 경우 오케스트레이션에 바인딩된 실제 송신 포트에서 PassThruTransmit 파이프라인을 사용할 수도 있습니다. 다음 작업 중 하나를 수행해야 하는 경우 다른 방법을 사용해야 합니다.
인바운드 XML 또는 플랫 파일 메시지의 컨텍스트에서 속성을 승격합니다.
수신 위치 내에 지도를 적용합니다.
메시지를 구독하는 오케스트레이션에 맵을 적용합니다.
메시지를 구독하는 송신 포트에 맵을 적용합니다.
이러한 작업 중 하나를 수행하려면 수신 파이프라인 내에서 문서 형식을 검색하고 MessageType 컨텍스트 속성에 (네임스페이스#루트 이름) 값을 할당해야 합니다. 이 작업은 일반적으로 Xml Disassembler 구성 요소(XmlDasmComp) 또는 플랫 파일 디스어셈블러 구성 요소(FFDasmComp)와 같은 디스어셈블러 구성 요소에서 수행됩니다. 이 경우 표준(instance, XmlReceive 파이프라인의 경우) 또는 표준 또는 사용자 지정 디스어셈블러 구성 요소가 포함된 사용자 지정 파이프라인을 사용해야 합니다.
가능한 한 늦게 리소스를 획득하고 가능한 한 빨리 해제합니다. 예를 들어 데이터베이스의 데이터에 액세스해야 하는 경우 가능한 한 늦게 연결을 열고 가능한 한 빨리 닫습니다. C# using 문을 사용하여 삭제 가능한 개체 또는 try-catch-finally 문의 마지막 블록을 암시적으로 해제하여 개체를 명시적으로 삭제합니다. 소스 코드를 계측하여 구성 요소를 쉽게 디버그할 수 있도록 합니다.
메시지 처리 속도를 높이기 위해 반드시 필요하지 않은 모든 구성 요소를 파이프라인에서 제거합니다.
수신 파이프라인 내에서 메시지 라우팅(오케스트레이션, 송신 포트) 또는 메시지 컨텍스트 속성 강등(송신 포트)에 필요한 경우에만 항목을 메시지 컨텍스트로 승격해야 합니다.
메시지와 함께 메타데이터를 포함해야 하는 경우 라우팅 또는 강등 목적으로 메타데이터를 사용하지 않는 경우 IBaseMessageContext.Promote 메서드 대신 IBaseMessageContext.Write 메서드를 사용합니다.
XPath 식을 사용하여 메시지에서 정보를 추출해야 하는 경우 SelectNodes 또는 SelectSingleNode 메서드를 사용하기 위해 XmlDocument 개체를 사용하여 전체 문서를 메모리에 로드하지 마십시오. 또는 스트리밍을 사용하여 메모리 사용량 최적화에 설명된 기술을 사용합니다.
스트리밍을 사용하여 파이프라인에서 메시지를 로드할 때 필요한 메모리 공간을 최소화합니다.
다음 기술은 메시지를 파이프라인에 로드할 때 메시지의 메모리 공간을 최소화하는 방법을 설명합니다.
ReadOnlySeekableStream 및 VirtualStream을 사용하여 파이프라인 구성 요소에서 메시지 처리
파이프라인 구성 요소 내의 메모리에 전체 메시지를 로드하지 않는 것이 좋습니다. 바람직한 방법은 사용자 지정 스트림 구현을 사용하여 인바운드 스트림을 래핑한 다음 읽기 요청이 이루어지면 사용자 지정 스트림 구현이 기본 래핑된 스트림을 읽고 데이터를 읽을 때(순수 스트리밍 방식으로) 처리합니다. 이는 구현하기가 매우 어려울 수 있으며 스트림으로 수행해야 하는 사항에 따라 불가능할 수 있습니다. 이 경우 Microsoft.BizTalk.Streaming.dll 노출되는 ReadOnlySeekableStream 및 VirtualStream 클래스를 사용합니다. 이러한 구현은 BizTalk SDK의 임의 XPath 속성 처리기(BizTalk Server 샘플)(https://go.microsoft.com/fwlink/?LinkId=160069)에도 제공됩니다.ReadOnlySeekableStream은 커서의 위치를 스트림의 시작 부분으로 변경할 수 있도록 합니다. VirtualStream은 크기가 지정된 임계값을 초과하지 않는 한 내부적으로 MemoryStream을 사용합니다. 이 경우 스트림을 파일 시스템에 씁니다. 이러한 두 스트림을 조합하여 사용(ReadOnlySeekableStream에 대한 영구 스토리지로 VirtualStream 사용)은 "검색 가능성" 및 "파일 시스템에 오버플로" 기능을 모두 제공합니다. 이렇게 하면 전체 메시지를 메모리에 로드하지 않고 대용량 메시지를 처리할 수 있습니다. 파이프라인 구성 요소에서 다음 코드를 사용하여 이 기능을 구현할 수 있습니다.
int bufferSize = 0x280;
int thresholdSize = 0x100000;
Stream vStream = new VirtualStream(bufferSize, thresholdSize);
Stream seekStream = new ReadOnlySeekableStream(inboundStream, vStream, bufferSize);
이 코드는 각 수신 위치 또는 송신 포트 구성에 bufferSize 및 thresholdSize 변수를 노출하여 "오버플로 임계값"을 제공합니다. 이 오버플로 임계값은 개발자 또는 관리자가 다양한 메시지 유형 및 다양한 구성(예: 32비트 및 64비트)에 대해 조정할 수 있습니다.
XPathReader 및 XPathCollection을 사용하여 사용자 지정 파이프라인 구성 요소 내에서 지정된 IBaseMessage 개체를 추출합니다.
XmlDocument 클래스에서 노출되는 SelectNodes 및 SelectSingleNode 메서드를 사용하는 대신 XML 문서에서 특정 값을 가져와야 하는 경우 다음 코드 예제와 같이 Microsoft.BizTalk.XPathReader.dll 어셈블리에서 제공하는 XPathReader 클래스의 instance 사용합니다.
참고
특히 작은 메시지의 경우 SelectNodes 또는 SelectSingleNode와 함께 XmlDocument를 사용하면 XPathReader를 사용하는 것보다 더 나은 성능을 제공할 수 있지만 XPathReader를 사용하면 애플리케이션에 대한 플랫 메모리 프로필을 유지할 수 있습니다.
이 예제에서는 XPathReader 및 XPathCollection을 사용하여 사용자 지정 파이프라인 구성 요소 내에서 지정된 IBaseMessage 개체를 추출하는 방법을 보여 줍니다.
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message)
{
try
{
...
IBaseMessageContext messageContext = message.Context;
if (string.IsNullOrEmpty(xPath) && string.IsNullOrEmpty(propertyValue))
{
throw new ArgumentException(...);
}
IBaseMessagePart bodyPart = message.BodyPart;
Stream inboundStream = bodyPart.GetOriginalDataStream();
VirtualStream virtualStream = new VirtualStream(bufferSize, thresholdSize);
ReadOnlySeekableStream readOnlySeekableStream = new ReadOnlySeekableStream(inboundStream, virtualStream, bufferSize);
XmlTextReader xmlTextReader = new XmlTextReader(readOnlySeekableStream);
XPathCollection xPathCollection = new XPathCollection();
XPathReader xPathReader = new XPathReader(xmlTextReader, xPathCollection);
xPathCollection.Add(xPath);
bool ok = false;
while (xPathReader.ReadUntilMatch())
{
if (xPathReader.Match(0) && !ok)
{
propertyValue = xPathReader.ReadString();
messageContext.Promote(propertyName, propertyNamespace, propertyValue);
ok = true;
}
}
readOnlySeekableStream.Position = 0;
bodyPart.Data = readOnlySeekableStream;
}
catch (Exception ex)
{
if (message != null)
{
message.SetErrorInfo(ex);
}
...
throw ex;
}
return message;
}
XMLTranslatorStream과 함께 XMLReader 및 XMLWriter를 사용하여 파이프라인 구성 요소에서 메시지 처리
스트리밍 방법을 사용하는 사용자 지정 파이프라인 구성 요소를 구현하는 또 다른 방법은 .NET XmlReader 및 XmlWriter 클래스를 BizTalk Server 제공하는 XmlTranslatorStream 클래스와 함께 사용하는 것입니다. 예를 들어 Microsoft.BizTalk.Pipeline.Components 어셈블리에 포함된 NamespaceTranslatorStream 클래스는 XmlTranslatorStream 에서 상속되며 이전 네임스페이스를 스트림에 포함된 XML 문서의 새 네임스페이스로 바꾸는 데 사용할 수 있습니다. 사용자 지정 파이프라인 구성 요소 내에서 이 기능을 사용하려면 메시지 본문 부분의 원래 데이터 스트림을 NamespaceTranslatorStream 클래스의 새 instance 래핑하고 후자를 반환할 수 있습니다. 이러한 방식으로 인바운드 메시지는 파이프라인 구성 요소 내에서 읽거나 처리되지 않지만, 스트림이 동일한 파이프라인의 후속 구성 요소에서 읽거나 최종적으로 메시지 에이전트에서 사용하는 경우에만 BizTalk Server MessageBox에 문서를 게시합니다.
다음 예제에서는 이 기능을 사용하는 방법을 보여 줍니다.
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message)
{
IBaseMessage outboundMessage = message;
try
{
if (context == null)
{
throw new ArgumentException(Resources.ContextIsNullMessage);
}
if (message == null)
{
throw new ArgumentException(Resources.InboundMessageIsNullMessage);
}
IBaseMessagePart bodyPart = message.BodyPart;
Stream stream = new NamespaceTranslatorStream(context,
bodyPart.GetOriginalDataStream(),
oldNamespace,
newNamespace);
context.ResourceTracker.AddResource(stream);
bodyPart.Data = stream;
}
catch (Exception ex)
{
if (message != null)
{
message.SetErrorInfo(ex);
}
throw ex;
}
return outboundMessage;
}
사용자 지정 파이프라인 구성 요소에서 ResourceTracker 사용
파이프라인 구성 요소는 만드는 개체의 수명을 관리하고 이러한 개체가 더 이상 필요하지 않은 즉시 가비지 수집을 수행해야 합니다. 파이프라인 구성 요소에서 파이프라인 실행이 끝날 때까지 개체의 수명을 지속하려면 파이프라인 컨텍스트에서 파이프라인이 가져올 수 있는 리소스 추적기에서 이러한 개체를 추가해야 합니다.
리소스 추적기는 다음 유형의 개체에 사용됩니다.
스트림 개체
COM 개체
IDisposable 개체
메시지 엔진은 리소스 추적기에서 추가된 모든 네이티브 리소스가 적절한 시간에 릴리스되도록 합니다. 즉, 파이프라인이 성공적으로 실행되었는지 또는 실패했는지에 관계없이 파이프라인이 완전히 실행된 후입니다. Resource Tracker instance 수명 및 추적 중인 개체는 파이프라인 컨텍스트 개체에 의해 관리됩니다. 파이프라인 컨텍스트는 IPipelineContext 인터페이스를 구현하는 개체를 통해 모든 유형의 파이프라인 구성 요소에서 사용할 수 있습니다.
예를 들어 다음 코드 조각은 사용자 지정 파이프라인 구성 요소에서 ResourceTracker 속성을 사용하는 방법을 보여 주는 샘플입니다. ResourceTracker 속성을 사용하려면 코드 조각에서 다음 매개 변수
IPipelineContext.ResourceTracker.AddResource
를 사용합니다. 이 매개 변수에서:IPipelineContext 인터페이스는 모든 문서 처리 관련 인터페이스에 액세스하는 데 사용되는 메서드를 정의합니다.
ResourceTracker 속성은 IPipelineContext를 참조하며 파이프라인 처리가 끝날 때 명시적으로 삭제될 개체를 추적하는 데 사용됩니다.
ResourceTracker.AddResource 메서드는 COM 개체, Disposable 개체 및 Streams를 추적하는 데 사용되며, 메시지가 BizTalk MessageBox에 게시될 때 이러한 유형의 리소스를 명시적으로 닫거나(스트림), 삭제(IDisposable 개체) 또는 릴리스(COM 개체)하기 위해 항상 사용자 지정 파이프라인 구성 요소 내에서 사용해야 합니다.
public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg)
{
IBaseMessage outMessage = pContext.GetMessageFactory().CreateMessage();
IBaseMessagePart outMsgBodyPart = pContext.GetMessageFactory().CreateMessagePart();
outMsgBodyPart.Charset = Encoding.UTF8.WebName;
outMsgBodyPart.ContentType = "text/xml";
//Code to load message content in the MemoryStream object//
MemoryStream messageData = new MemoryStream();
//The MemoryStream needs to be closed after the whole pipeline has executed, thus adding it into ResourceTracker//
pContext.ResourceTracker.AddResource(messageData);
//Custom pipeline code to load message data into xmlPayload//
XmlDocument xmlPayLoad = new XmlDocument();
xmlPayLoad.Save(messageData);
messageData.Seek(0, SeekOrigin.Begin);
//The new stream is assigned to the message part’s data//
outMsgBodyPart.Data = messageData;
// Pipeline component logic here//
return outMessage;
}
메모리 내 접근 방식을 사용하고 스트리밍 방법을 사용하여 파이프라인에 메시지 로드 비교
다음 정보는 Nic Barden의 블로그 http://blogs.objectsharp.com/cs/blogs/nbarden/archive/2008/04/14/developing-streaming-pipeline-components-part-1.aspx (https://go.microsoft.com/fwlink/?LinkId=160228)에서 가져온 것입니다. 이 표에서는 메모리 내 접근 방식을 사용하고 스트리밍 방법을 사용하여 파이프라인에 메시지를 로드하는 방법에 대한 요약된 비교를 제공합니다.
비교... | 스트리밍 | 메모리 |
---|---|---|
메시지당 메모리 사용량 | 메시지 크기에 관계없이 낮음 | 높음(메시지 크기에 따라 다름) |
XML 데이터를 처리하는 데 사용되는 공통 클래스 | 기본 제공 및 사용자 지정 파생: XmlTranslatorStream, XmlReader 및 XmlWriter |
XmlDocument, XPathDocument, MemoryStream 및 VirtualStream |
설명서 | 불량 – 지원되지 않는 많은 BizTalk 클래스 | 매우 좋음 - .NET Framework 클래스 |
"처리 논리" 코드의 위치 | - Execute 메서드를 통해 판독기 및 스트림을 "연결"합니다. - 데이터를 읽을 때 판독기 및 스트림에서 실제 실행이 발생합니다. |
파이프라인 구성 요소의 Execute 메서드에서 직접. |
데이터 | 데이터를 읽을 때 각 래핑 계층에서 다시 생성됩니다. | 다음 구성 요소가 호출되기 전에 각 구성 요소에서 읽고 수정하고 기록합니다. |