最佳化管道效能
本主題描述在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 和傳送埠上的 PassThruTransmit 管線,如果您需要傳送二進位訊息,則可以在接收位置上使用 PassThruReceive 管線。 如果訊息已格式化並準備好傳輸,您也可以在系結至協調流程的實體傳送埠上使用 PassThruTransmit 管線。 如果您需要完成下列其中一個動作,則必須使用不同的方法:
在輸入 XML 或一般檔案訊息的內容上升級屬性。
在接收位置內套用地圖。
在訂閱訊息的協調流程中套用對應。
在訂閱訊息的傳送埠上套用對應。
若要完成其中一個動作,您必須探查並探索接收管線內的檔案類型,並將 (namespace#root-name) 值指派給 MessageType 內容屬性。 此作業通常是由反組譯程式元件來完成,例如 Xml 解譯器元件 (XmlDasmComp) 或 FFDasmComp) (一般檔案反組譯程式元件。 在此情況下,您必須使用標準 (,例如 XmlReceive 管線) 或包含標準或自訂反組譯器元件的自訂管線。
儘快取得資源,並儘快釋出資源。 例如,如果您需要存取資料庫上的資料,請盡速開啟連線,並儘快關閉它。 使用 C# using 語句來隱含釋放可處置的物件或 try-catch-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;
}
搭配 XMLTranslatorStream 使用 XMLReader 和 XMLWriter 來處理來自管線元件的訊息
另一個實作使用串流方法之自訂管線元件的方法,是搭配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
管線元件應該在不再需要這些物件時,管理其建立的物件存留期,並立即執行垃圾收集。 如果管線元件想要將物件的存留期持續到管線執行結束為止,則必須將這類物件新增至管線內容中可能會從管線內容擷取的資源追蹤器。
資源追蹤器用於下列類型的物件:
Stream 物件
COM 物件
IDisposable 物件
訊息引擎可確保新增至資源追蹤器的所有原生資源都會在適當的時間釋放,也就是在管線完全執行之後,不論其成功或失敗。 Resource Tracker 實例的存留期及其正在追蹤的物件是由管線內容物件所管理。 管線內容可透過實作 IPipelineCoNtext 介面的物件提供給所有類型的管線元件。
例如,下列程式碼片段是說明如何在自訂管線元件中使用 ResourceTracker 屬性的範例。 若要使用 ResourceTracker 屬性,程式碼片段會使用下列參數
IPipelineContext.ResourceTracker.AddResource
。 在此參數中:IPipelineCoNtext 介面會定義用來存取所有檔處理特定介面的方法。
ResourceTracker 屬性會參考 IPipelineCoNtext,並用來追蹤將在管線處理結束時明確處置的物件。
ResourceTracker.AddResource 方法可用來追蹤 COM 物件、可處置物件和資料流程,而且一律應該在自訂管線元件內使用,以明確關閉 (資料流程) 、處置 (IDisposable 物件) 或釋放 (COM 物件,) 這些類型的資源發佈至 BizTalk MessageBox。
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 方法。 |
資料 | 在每一個包裝層重新建立,因為資料會經過讀取。 | 在呼叫下一個元件之前,先讀取、修改並寫出每個元件。 |