스트리밍을 통한 메모리 사용 최적화
이 항목에서는 WCF 전송을 사용하여 큰 메시지를 보내거나 받을 때 또는 오케스트레이션에서 메시지를 로드할 때 스트리밍 패턴을 사용하여 메시지 메모리 공간을 최소화하기 위한 권장 사항을 제공합니다.
오케스트레이션의 코드를 사용하여 메시지 내용을 읽을 때는 XmlDocument 변수를 사용하지 마세요. XmlDocument 변수에 메시지를 로드하면 특히 큰 메시지의 경우 상당한 오버헤드가 발생합니다. 이 오버헤드는 메모리 사용량 및 처리 측면에서 메모리 내 구조를 빌드합니다. XmlDocument instance 사용하면 DOM(문서 개체 모듈)에 대한 개체 그래프를 작성하기 위해 전체 메시지 내용이 메모리에 로드됩니다. 이 클래스의 instance 사용하는 총 메모리 양은 실제 메시지 크기의 약 10배일 수 있습니다. XmlDocument 변수에 메시지를 로드할 때 필요한 메모리 공간에 대한 자세한 내용은 9장 – XML 성능 향상을 참조하세요.
이 항목의 나머지 부분에서는 메시지를 XmlDocument 변수로 로드할 필요가 없는 메시지 내용을 읽기 위한 대체 방법을 제공합니다.
WCF 전송을 사용하여 큰 메시지를 보내거나 받을 때 스트리밍 사용
WCF 전송을 사용하여 큰 메시지를 보내거나 받는 경우 WCF-Custom 또는 WCF-CustomIsolated 어댑터를 사용하고 다음 바인딩과 같이 transferMode = Streamed 옵션을 지원하는 바인딩 형식으로 구성합니다.
basicHttpBinding + BasicHttpBindingElement, transferMode = Streamed
netTcpBinding + NetTcpBindingElement, transferMode = Streamed
customBinding + HttpTransportElement, transferMode = Streamed
customBinding +ConnectionOrientedTransportElement, transferMode = Streamed
transferMode = Streamed 옵션을 지원하는 바인딩과 함께 WCF-Custom 또는 WCF-CustomIsolated 어댑터를 선택하면 필요에 따라 파일 시스템에 대한 큰 메시지 스트리밍을 구현하고 메모리 부족 문제를 완화할 수 있습니다.
스트리밍을 사용하여 오케스트레이션에서 메시지를 로드할 때 필요한 메모리 공간을 최소화합니다.
다음 기술은 메시지를 오케스트레이션에 로드할 때 메시지의 메모리 공간을 최소화하는 방법을 설명합니다.
XLANGMessage 변수를 사용하여 메시지 또는 메시지 파트의 내용 처리
오케스트레이션에서 .NET 클래스 라이브러리로 메시지를 전달할 때 이 항목의 앞부분에서 언급한 이유로 XmlDocument 변수로 전달하지 마세요. 대신 XLANGMessage 변수를 사용합니다. 다음 기술은 XLANGMessage 변수를 사용하여 메시지 또는 메시지 부분을 읽는 방법을 보여 줍니다.
XMLReader를 사용하여 메시지 처리 - XmlReader instance 메시지를 처리하려면 메시지를 .NET 코드에 XLANGMessage로 전달하고 XmlReader를 사용하여 Part 콘텐츠를 검색합니다.
public void ProcessMessage(XLANGMessage message) { try { using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader) if (reader != null) { ... } } finally { message.Dispose(); } }
StreamReader를 사용하여 메시지 내용을 문자열로 검색 - 오케스트레이션에서 XmlDocument의 일반적인 사용 중 하나는 XmlDocument.OuterXml()을 사용하여 메시지를 XML 문자열로 검색하는 것입니다. 다음 코드 예제에서는 XLANGMessage 변수를 사용하여 메시지를 문자열로 검색하는 대체 메서드를 보여 줍니다.
public static string MessageToString(XLANGMessage message) { string strResults; try { using (Stream stream = message[0].RetrieveAs(typeof(Stream)) as Stream) { using (StreamReader reader = new StreamReader(stream)) { strResults = reader.ReadToEnd(); } } } finally { message.Dispose(); } return strResults; }
간단한 .NET 메시지의 내용을 문자열로 검색 합니다. 메시지 형식이 간단한 .NET 형식인 경우 해당 형식으로 메시지를 검색할 수 있습니다. 예를 들어 메시지를 문자열로 얻으려면 메시지를 .NET 코드에 XLANGMessage로 전달하고 Part 콘텐츠를 문자열로 검색합니다.
public void ProcessMessage(XLANGMessage message) { try { string content = message[0].RetrieveAs(typeof(string)) as string; if (!string.IsNullOrEmpty(content)) { ... } } finally { message.Dispose(); } }
메시지의 내용을 스트림으로 검색 - 메시지를 스트림으로 가져오기 위해 메시지를 .NET 코드에 XLANGMessage로 전달하고 Part 콘텐츠를 스트림으로 검색합니다.
public Stream ProcessRequestReturnStream(XLANGMessage message, int bufferSize, int thresholdSize) { ... try { using (VirtualStream virtualStream = new VirtualStream(bufferSize, thresholdSize)) { using (Stream partStream = (Stream)message[0].RetrieveAs(typeof(Stream))) //Note that when calling this code, if the XmlDocument is quite large, keeping it in a memory with a MemoryStream may have an adverse effect on performance. //In this case, it may be worthwhile to consider an approach that uses a VirtualStream + ReadonlySeekableStream to buffer it to the file system, if its size is bigger than the thresholdSize parameter. //Keep in mind that: // - If the message size is smaller than the threshold size, the VirtualStream class buffers the stream to a MemoryStream. // - If the message size is bigger than the threshold size, the VirtualStream class buffers the stream to a temporary file. using (ReadOnlySeekableStream readOnlySeekableStream = new ReadOnlySeekableStream(partStream, virtualStream, bufferSize)) { using (XmlReader reader = XmlReader.Create(readOnlySeekableStream)) { } } } } } catch (Exception ex) { } finally { message.Dispose(); } return stream; }
메시지 내용을 .NET 개체로 검색 - 메시지를 .NET 개체로 가져오기 위해 메시지를 .NET 코드에 XLANGMessage로 전달하고 Part 콘텐츠를 .NET 클래스의 instance 검색합니다. Visual Studio 2010에서 제공하는 XML 스키마 정의 도구(Xsd.exe) 도구를 사용하여 메시지의 Xml 스키마에서 이 후자를 만듭니다.
참고
이 기술은 메시지가 작은 경우에만 유효합니다. 그렇지 않으면 실제 메시지를 .NET 개체로 직렬화 해제하는 데 상당한 오버헤드가 발생할 수 있습니다.
public void ProcessMessage(XLANGMessage message) { try { Request request = message[0].RetrieveAs(typeof(Request)) as Request; if (request != null) { ... } } finally { message.Dispose(); } }
참고
.NET 코드에서 반환하기 전에 XLANGMessage 매개 변수에 의해 노출되는 Dispose() 메서드를 사용하는 것은 시간이 지남에 따라 해제하지 않고 XLANGMessage 개체의 인스턴스를 누적할 수 있는 반복 시나리오 및 장기 실행 오케스트레이션에서 특히 중요합니다. 메시지 호출에 대한 자세한 내용을 참조하세요. 이러한 방식으로 Dispose()는 BizTalk Server 설명서에서 XLANGMessage로 표시되는 메시지를 참조하세요. 또한 이 항목에서는 스트림 기반 접근 방식을 사용하여 사용자 코드에서 XLANGMessage 변수를 생성하기 위해 IStreamFactory를 사용하는 모범 사례를 제공합니다.
오케스트레이션에서 호출하는 도우미 구성 요소 내에서 XLANGMessage를 처리하는 다양한 방법에 대한 자세한 내용은 다음 topics 참조하세요.
4 오케스트레이션 1부에서 호출한 도우미 구성 요소 내에서 XLANGMessage를 처리하는 다양한 방법 (타사 블로그 열기)
4 오케스트레이션 2부에서 호출한 도우미 구성 요소 내에서 XLANGMessage를 처리하는 다양한 방법 (타사 블로그 열기)
XPathReader 및 XPathCollection을 사용하여 오케스트레이션에서 호출된 메서드에서 XLANGMessage 개체에서 값을 추출합니다.
XMLDocument 클래스를 사용하여 사용자 지정 파이프라인 구성 요소 또는 오케스트레이션에서 호출된 도우미 클래스와 같은 사용자 지정 코드에서 XML 메시지의 내용을 읽지 마세요. XMLDocument instance 사용하여 XML 메시지를 로드하는 경우 전체 메시지가 메모리에 로드됩니다. 이는 비효율적이며 메시지의 실제 크기의 최대 10배에 달하는 메모리가 필요할 수 있습니다. XML 메시지의 내용을 읽는 보다 효율적인 방법은 스트리밍 기술을 사용하여 원래 스트림을 Microsoft.BizTalk.Streaming.dll 어셈블리에서 제공하는 스트림 클래스 중 하나로 래핑하는 것입니다. 이 기술은 큰 메시지를 로드할 때 특히 유용합니다.
XmlDocument 클래스에서 노출되는 SelectNodes 및 SelectSingleNode 메서드를 사용하는 대신 XML 문서에서 특정 값을 가져와야 하는 경우 다음 코드 예제와 같이 Microsoft.BizTalk.XPathReader.dll 어셈블리에서 제공하는 XPathReader 클래스의 instance 사용합니다.
이 예제에서는 XPathReader 및 XPathCollection을 사용하여 오케스트레이션에서 호출된 메서드 내의 XLANGMessage 개체에서 지정된 값을 추출하는 방법을 보여 줍니다.
public static string SelectSingleNode(XLANGMessage message, string xPath) { try { if (message == null || string.IsNullOrEmpty(xPath)) { return string.Empty; } using (XmlReader reader = (XmlReader)message[0].RetrieveAs(typeof(XmlReader))) { XPathCollection xPathCollection = new XPathCollection(); XPathReader xPathReader = new XPathReader(reader, xPathCollection); xPathCollection.Add(xPath); while (xPathReader.ReadUntilMatch()) { if (xPathReader.Match(0)) { return xPathReader.ReadString(); } } } } catch (Exception ex) { ... } finally { message.Dispose(); } return string.Empty; }