本主題描述在 BizTalk Server 解決方案中優化管線效能的指導方針。
優化 BizTalk Server 管線效能的最佳做法
因為管線元件會對效能產生重大影響(例如,傳遞管線元件的執行效能比 XML 組合器/反組譯工具管線元件好 30%),因此,請確定任何自定義管線元件在部署中實作之前,會以最佳方式執行。 如果您想要將 BizTalk 應用程式的整體效能最大化,請最小化自定義管線中的管線元件數目。
您也可以藉由減少管線元件中的訊息保存頻率,以及撰寫元件來將冗餘降到最低,以改善整體效能。 每個自定義元件,以及可能會中斷效能的特定成品,例如自定義追蹤元件,都應該在負載過重的情況下個別測試,以在系統以完整容量運作時觀察其行為,並找出任何可能的瓶頸。
如果您需要讀取管線元件內的輸入訊息,請避免使用 XmlDocument 物件將整個檔載入記憶體中。 XmlDocument 類別實例載入和建立 XML 檔記憶體內部表示所需的空間量,最多是實際訊息大小的 10 倍。 若要讀取訊息,您應該使用 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,您可以在接收位置使用 PassThruReceive 管線;如果您需要發送二進位訊息,您可以在傳送埠上使用 PassThruTransmit 管線。 如果訊息已格式化且已準備好傳輸,您也可以在系結至協調流程的實體傳送埠上使用PassThruTransmit管線。 如果您需要完成下列其中一個動作,則必須使用不同的方法:
於輸入 XML 或平面文件訊息的背景下提升屬性。
在接收位置內套用地圖。
在編排中訂閱訊息時套用映射。
在訂閱訊息的傳送埠上套用地圖。
若要完成其中一個動作,您必須探查並探索接收管線內的檔類型,並將 (namespace#root-name) 值指派給 MessageType 內容屬性。 此作業通常是由反彙編程式元件來完成,例如 Xml 反組譯程式元件 (XmlDasmComp) 或一般檔案反彙編程式元件 (FFDasmComp)。 在此情況下,您必須使用標準 (例如 XmlReceive 管線) 或包含標準或自定義反彙編程式元件的自定義管線。
盡可能晚取得資源,並儘早釋放資源。 例如,如果您需要存取資料庫上的數據,請儘快開啟連線,並儘快關閉它。 使用 C# 的 using 語句自動釋放可處理的物件,或在 try-catch-finally 語句中使用 finally 區塊以明確釋放您的物件。 檢測您的原始程式碼,讓您的元件更容易進行偵錯。
從管線中排除任何不需要的元件,以加速訊息處理。
在接收管線內,只有在需要訊息路由(協調流程、傳送埠)或降級訊息內容屬性時,才應該將專案升階至訊息內容內容。
如果您需要將元數據包含在訊息中,且未使用元數據進行路由或降級,請使用 IBaseMessageContext.Write 方法,而不是 IBaseMessageContext.Promote 方法。
如果您需要使用 XPath 表達式從訊息擷取資訊,請避免使用 XmlDocument 物件將整個檔載入記憶體中,只要使用 SelectNodes 或 SelectSingleNode 方法即可。 或者,使用優化 記憶體使用量與串流中所述的技術。
使用串流將管線中載入訊息時所需的記憶體使用量降到最低
下列技術說明如何在將訊息載入管線時將訊息的記憶體使用量降到最低。
使用 ReadOnlySeekableStream 和 VirtualStream 處理來自管線元件的訊息
最佳做法是避免將整個訊息載入管線元件內的記憶體。 較好的方法是使用自定義數據流實作來包裝輸入數據流,然後在進行讀取要求時,自定義數據流實作會讀取基礎、包裝的數據流,並在讀取時處理數據(以純串流方式)。 這可能很難實作,而且可能不可能,視需要使用數據流完成的工作而定。 在此情況下,請使用 Microsoft.BizTalk.Streaming.dll公開的 ReadOnlySeekableStream 和 VirtualStream 類別。 這些實作也會在 BizTalk SDK 中的任意 XPath 屬性處理程式 (BizTalk Server 範例) 中https://go.microsoft.com/fwlink/?LinkId=160069提供。ReadOnlySeekableStream 可確保游標可以重新置放至數據流的開頭。 VirtualStream 會在內部使用 MemoryStream ,除非大小超過指定的臨界值,在此情況下,它會將數據流寫入文件系統。 結合使用這兩個數據流(使用 VirtualStream 作為 ReadOnlySeekableStream 的持續性記憶體),可提供「可搜尋性」和「文件系統溢位」功能。 這可容納大型訊息的處理,而不需要將整個訊息載入記憶體中。 下列程式代碼可用於管線元件中,以實作這項功能。
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 物件。
如果需要從 XML 檔提取特定值,而不是使用 XmlDocument 類別所公開的 SelectNodes 和 SelectSingleNode 方法,請使用 Microsoft.BizTalk.XPathReader.dll 元件所提供的 XPathReader 類別實例,如下列程式代碼範例所示。
備註
特別是針對較小的訊息,搭配 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;
}
使用 XMLReader 和 XMLWriter 搭配 XMLTranslatorStream 來處理從管線元件傳來的訊息
另一個實作使用串流方法之自定義管線元件的方法,是搭配 BizTalk Server 提供的 XmlTranslatorStream 類別使用 .NET XmlReader 和 XmlWriter 類別。 例如,包含在 Microsoft.BizTalk.Pipeline.Components 元件元件中的 NamespaceTranslatorStream 類別會繼承自 XmlTranslatorStream ,而且可用來將舊命名空間取代為數據流中包含的 XML 檔中的新命名空間。 若要在自定義管線元件內使用這項功能,您可以使用 NamespaceTranslatorStream 類別的新實例包裝訊息本文元件的原始數據流,並傳回後者。 如此一來,輸入訊息就不會在管線元件內讀取或處理,但只有在數據流是由相同管線中的後續元件讀取,或最終由訊息代理程式取用,再將檔發佈至 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 物件
消息處理引擎確保在適當時機釋放新增至資源管理器的所有本地資源,也就是在完成管線執行之後,無論管線成功或失敗。 資源追蹤器實例的存留期及其正在追蹤的物件是由管線內容物件所管理。 管線內容可透過實作 IPipelineContext 介面的物件,提供給所有類型的管線元件使用。
例如,下列代碼段是範例,說明如何在自定義管線元件中使用 ResourceTracker 屬性。 若要使用 ResourceTracker 屬性,代碼段會使用下列參數
IPipelineContext.ResourceTracker.AddResource。 在此參數中:IPipelineContext 介面會定義用來存取所有文件處理特定介面的方法。
ResourceTracker 屬性會參考 IPipelineContext,並用來追蹤將在管線處理結束時明確處置的物件。
ResourceTracker.AddResource 方法可用來追蹤 COM 物件、可處置物件和 Streams,而且應該一律在自定義管線元件內使用,以在訊息發佈至 BizTalk MessageBox 時明確關閉 (streams)、處置 (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;
}
使用記憶體內部方法和串流方法將訊息載入管線的比較
下列資訊取自尼克·巴登的博客 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 方法直接執行。 |
| 資料 | 在每一個包裹層中重新建立,因為數據在透過此層讀取時會重新創建。 | 在呼叫下一個元件之前,先對每個元件進行讀取、修改和寫入。 |