如何設計更具效能的配接器
基於效能的目的,所有配接器在對於提交訊息批次、傳輸批次及在各批次的訊息上執行一般性作業等方面,都應該具備批次感知的能力。 配接器應該嘗試公開可設定的效能相關屬性,例如,批次的大小或批次中的位元組數目 (這些屬性可從配接器的設計階段使用者介面進行設定)。
如同之前所提過,傳送配接器一定要執行未封鎖的傳送,以免降低傳送主控件的效能。 不建議採用傳訊引擎 API 的進一步封鎖。
訊息內容的讀取和寫入都會影響執行階段效能。 一般來說,配接器應該避免讀取、寫入和升級過多數目的訊息內容屬性。 升級屬性會產生額外的效能耗損,因為在執行階段會針對每一個升級的屬性進行訂閱評估。 但是,配接器需要升級極大量的屬性,才會對效能造成顯著的影響。 因此,只升級那些需要升級的屬性是一個很好的作法。
節流傳送和接收
當 BizTalk 引擎上的負載超過了所設定的閾值時,引擎會節流配接器和協調流程,以確保能夠有最佳的效能。 在接收端,當引擎上的工作負載超過指定的閾值時,配接器的 IBTTransportBatch.Done 呼叫會遭到封鎖,直到負載已足夠減少為止。 這樣會強制配接器只在引擎可用時才將新的工作提交給引擎。 另一方面,當引擎正在節流配接器傳送的輸出訊息時,引擎在負載降低以前,不會傳遞要傳輸的新訊息。
基於這些理由,除非必要 (例如,為了限制後端系統的連接數目),否則配接器不需要考慮節流。 在這些類型的案例中,引擎和配接器架構都不提供任何支援。
您可以透過數種方式 (根據您是否控制配接器的原始程式碼而定) 來處理從自訂傳送配接器傳送之許多訊息的節流。
傳送端節流會提升效能
如果您控制配接器的原始程式碼,您可以從嘗試錯誤的方法來決定您希望佇列中隨時可傳送的最大訊息數目。 當傳訊引擎呼叫 TransmitMessage
方法並傳遞傳送配接器新的訊息時,您可以選擇封鎖執行緒,或檢查佇列中的訊息數目是否大於您先前決定的最大值。 如果已超過訊息數目上限,您可以使用 Resubmit
方法來將訊息重新提交至傳訊引擎。 請注意,如果配接器是同步的,就表示訊息已經封鎖。
如果您不控制配接器的原始程式碼,您可以變更 BizTalk 管理資料庫中Adm_serviceclass資料表中的 Highwatermark 值,以變更佇列訊息的數目。 Highwatermark屬性的最大值為 200。 您也可以將 Lowwatermark 屬性的值變更為較小的值。
請記住,非同步介面卡 的 Highwatermark 屬性值會針對傳訊引擎提供給介面卡的訊息數目考慮。 傳訊引擎會透過 TransmitMessage
方法將這些訊息傳遞至配接器,這些訊息仍可在傳輸中完成,例如,如果配接器尚未對 DeleteMessage
、 Resubmit
、 MoveToNextTransport
或 Microsoft.BizTalk.TransportProxy.Interop.BatchOperationType.MoveToSuspendQ 方法進行對應的呼叫。 對於同步介面卡, Highwatermark 屬性只會使用 TransmitMessage 方法將傳訊引擎傳遞至配接器的訊息數目,因為此呼叫會同步處理,因而封鎖呼叫傳訊引擎執行緒。
如果您要針對本質緩慢的通訊協定 (如 HTTP、FTP 或雙向 SOAP) 來撰寫傳送配接器,請考慮以下事項:
這類配接器從 BizTalk 傳訊引擎接收要傳輸之訊息的速度,可能會比可以傳輸訊息的速度還要快。 這項差異會造成各種層級的問題, 傳輸底下的訊息會留在記憶體中,並佔用虛擬記憶體,因而讓整個系統變得緩慢。
此配接器可能會佔用通訊協定特有的資源。 例如,它可能會開放太多的伺服器並行連接,這樣可能會中斷遠端伺服器。
此配接器可能會影響其他配接器。 例如,如果有太多的訊息排入特定配接器的佇列,傳訊引擎會在該處理序中停止發出要求給其他傳送配接器。
有一個解決方法是將緩慢和快速的配接器放在個別的 BizTalk 主控件中,並使用「配額上限」和「配額下限」設定來控制訊息數目。
接收端節流會提升效能
在許多情況下,接收配接器接收訊息的速度會快於系統其餘部分可以處理訊息的速度。 當這種情況發生時,MessageBox 資料庫會積存訊息。 當發生這種情況時,整個系統的效能會大幅降低。
如果您的配接器發生這種情況,您可以使用下列其中一種方法來降低接收配接器的速度:
減少傳訊引擎執行緒集區的大小。 您可以控制傳訊引擎用來將訊息發佈到 MessageBox 的執行緒數目。 藉由減少執行緒的數目,您就可以降低接收配接器接收訊息到 MessageBox 的速度。 只有對應到配接器之接收處理常式的主控件才需要進行這項設定。 如果是對應到配接器之傳送處理常式的主控件,則不應該進行這項設定,除非您也想要讓傳送配接器變慢。
減少配接器批次的大小。 大多數的快速接收配接器都會以批次方式發佈訊息至 MessageBox, 這些批次的大小通常可以在接收位置屬性頁中設定。 藉由降低批次大小,就可以減少流入系統中的整體訊息輸送量。
變更其他配接器特有的設定。 當您完成前兩個步驟之後,可以嘗試調整其他配接器參數,以進一步減少輸送量。 某些配接器會公開可用來降低輸送量的內部參數。 例如,MQSeries 配接器有一項「排序的傳遞」設定。 「排序的傳遞」會指定此配接器將會發佈訊息批次、等候此批次完成,然後再發佈下一個批次。 藉由啟用這項設定,基本上就可以從接收配接器移除所有平行處理原則。 相反地,可以透過相反的方向調整參數,以提高接收配接器的接收速度。
配接器可以盡量將所需的批次數提交給傳輸 Proxy。 當系統受到高度壓力時,IBTTransportBatch介面的Done方法呼叫將會封鎖訊息,直到必要的資源釋放至系統為止。
非同步接收和傳送的計劃
BizTalk Server 傳訊 API 對於非同步程式設計有相當多的支援。 如果您要撰寫可擴充的配接器,一開始請使用非同步模型來規劃,因為非同步模型提供較理想的並行處理。
在接收端,當配接器透過呼叫 IBTTransportBatch::D one) ,將訊息批次提交至 BizTalk 傳訊引擎 (時,傳訊引擎會使用其內部執行緒集區將工作排入佇列,並立即傳回。 引擎會處理個別執行緒上的訊息,讓配接器可從其來源自由讀取更多的訊息並提交訊息,而不需要等候上一個訊息處理完畢。
在傳送端,您的配接器可以是非同步,也可以是同步。 但是,如果您的通訊協定支援非同步作業,您就應該使用這項支援來撰寫可擴充的配接器。 例如,檔案和 HTTP 傳送配接器是完全非同步,而且它們會執行非常少的封鎖/同步作業。
非同步作業可確保傳訊引擎和您的配接器都將以平行方式繼續執行其各自的工作,而不會互相等候另一方來進行一般訊息處理。
使用批次處理來改善效能
批次處理是撰寫可擴充之配接器的一個最佳起點, 傳送端和接收端配接器都是如此。 每一個批次都會透過 BizTalk Server 內的資料庫交易,即使配接器為非交易式亦然。 因為每一個交易都有關聯的固定延遲,所以您應該嘗試將一個以上的作業結合成單一批次,讓交易的數目減至最少。
請勿讓 .NET 執行緒集區過於匱乏資源
撰寫 BizTalk 配接器是撰寫 .NET 執行階段程式碼的一項練習;撰寫 .NET 執行階段程式碼一定是非同步程式設計的一項練習。
讓 .NET 執行緒集區過於匱乏資源對於 .NET 中的所有非同步程式設計都是一項風險,BizTalk 配接器程式設計人員尤其要避免。
.NET 執行緒集區是一項受限但廣泛共用的資源, 撰寫程式碼來使用其中一個 .NET 執行緒集區執行緒並保留一段很長的時間,以阻止其他工作項目的執行,是一件很簡單的事情。
每當您使用 BeginInvoke 或使用計時器時,您就會使用 .NET 執行緒集區執行緒。 如果您有多個工作要執行 (例如將訊息從 MQSeries 複製到 BizTalk Server) ,您應該執行一個工作專案, (一批訊息到BizTalk Server) ,然後線上程集區中重新排入佇列。 絕對不要在 while
執行緒上的迴圈中。
具體來說,這表示以 while
對 BeginInvoke的重複呼叫取代迴圈。 這項簡單的變更可大幅改善回應能力,並可擴充整個實作的能力。
在限制批次大小時選擇正確的度量
如果您要以批次方式提交訊息給 BizTalk Server,請不要只依賴訊息計數來限制批次大小。 請考慮當介面卡僅根據訊息計數設定為批次時會發生什麼情況:如果批次大小是兩個,且配接器分別取得大小為 4 KB、8 KB、1 MB 和 5MB 的四個訊息,則第一個批次的大小為 12 KB,而第二個批次的大小為 6 MB。
由於 BizTalk 傳訊引擎會循序處理單一批次中的所有訊息,所以此範例中第二個批次的處理速度要比第一個批次緩慢許多, 這樣實際上會減少輸送量。 此問題有一個更好的處理方法,就是根據訊息計數和批次中的總位元組數 (也就是以位元組計算的批次大小) 來進行批次處理。 總位元組數並沒有識別常數, 但是在正常的處理案例中,如果批次大小超過 1 MB,您就會開始看到並行處理和輸送量變差。
一般來說,配接器無從得知訊息,所以無法知道實際執行環境中的訊息大小。 內送訊息的大小可能會有大幅的變動, 因此,務必要使用訊息計數和總位元組數來建置批次。