Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Sendeadapter übermitteln Nachrichten von der BizTalk Messaging-Engine, die über die Leitung gesendet werden. Diese Nachrichten können über ein unidirektionales oder bidirektionales Nachrichtenaustauschmuster gesendet werden. Ein Adapter, der dieses bidirektionale Nachrichtenaustauschmuster verarbeitet, wird als Solicit-Response Adapter bezeichnet.
Blockierte vs. nicht-blockierende Übertragungen
Das Nachrichtenmodul übermittelt Nachrichten an den Sendeadapter, indem entweder die IBTTransmitter.TransmitMessage-Methode oder die IBTTransmitterBatch.TransmitMessage-Methode verwendet wird, je nachdem, ob der Adapter batchfähig ist. Beide Versionen der Methode weisen einen booleschen Rückgabewert auf, der angibt, wie der Adapter die Nachricht übertragen hat. Wenn der Adapter true zurückgibt, wurde die Nachricht vollständig gesendet, bevor die Rückgabe erfolgt. In diesem Fall löscht das Messagingmodul die Nachricht aus der MessageBox-Datenbank im Namen des Adapters. Wenn der Adapter einen Wert von false zurückgibt, bedeutet dies, dass die Nachrichtenübertragung gestartet wurde und der Adapter noch vor Abschluss der Übertragung zurückgekehrt ist. In diesem Fall ist der Adapter nicht nur für das Löschen der Nachricht aus der Anwendungswarteschlange verantwortlich, sondern auch dafür, Übertragungsfehler zu behandeln, die erfordern, dass die Nachricht entweder erneut zur Übertragung versucht oder vorübergehend ausgesetzt wird.
Der Adapter, der false zurückgibt, ist ein nicht blockierender Aufruf, was bedeutet, dass der TransmitMessage-Implementierungscode den aufrufenden Thread der Messaging Engine nicht blockiert. Der Adapter fügt einfach die Nachricht zu einer speicherinternen Warteschlange hinzu, die zur Übertragung bereit ist, und kehrt dann zurück. Der Adapter sollte über einen eigenen Threadpool verfügen, der die In-Memory-Warteschlange verwaltet, die Nachricht überträgt und dann die Engine über das Ergebnis der Übertragung informiert.
Die Threads der Nachrichten-Engine sind in der Regel stärker an die CPU gebunden als die Threads, die zum Senden von Daten über das Netzwerk verwendet werden. Das gleichzeitige Verwenden dieser beiden Arten von Threads hat negative Auswirkungen auf die Leistung. Nicht blockierende Sendevorgänge ermöglichen die Entkoppelung dieser beiden Threadstypen und führen zu einer erheblichen Leistungsverbesserung gegenüber dem Blockieren von Aufrufen.
Das folgende Diagramm zeigt den Threadpool des Adapters, der tendenziell von E/A-Vorgängen gebunden werden kann. Der Threadpool des BizTalk Server Messaging Engine ist stärker an die CPU-Verarbeitung gebunden. Indem zwei verschiedene Threadpools beibehalten und nicht dieselbe Art von Threads gemischt werden, kann das System effizienter arbeiten.
Leistungstipp: Um eine optimale Leistung zu erzielen, sollten Sendeadapter nicht blockiert und batchfähig sein. Wenn der BizTalk-Dateiadapter von blockierend und nicht-Batch-fähig in nicht blockierend und batchfähig geändert wurde, konnte eine dreifache Leistungssteigerung erzielt werden.
Tipp zur Problembehandlung: Das Blockieren von Übertragungen kann zu einer Leistungsbeeinträchtigung einer gesamten Hostinstanz führen. Wenn der Adapter eine übermäßige Blockierung in TransmitMessage ausführt, wird verhindert, dass Motorthreads Nachrichten an andere Adapter übermitteln.
Nicht batchierte Sendesendungen
Adapter, die nicht batchfähig sind, sollten IBTTransmitter implementieren, wie in Schnittstellen für einen asynchronen Sendeadapter beschrieben. Für jede Nachricht, die der Adapter mit der Nachrichten-Engine übertragen muss, ruft er IBTTransmitter.TransmitMessage auf. Im folgenden Objektinteraktionsdiagramm wird der typische Ansatz für die Übertragung von Nachrichten beschrieben, der aus den folgenden Schritten besteht:
Der Motor übermittelt die Nachricht an den Adapter.
Der Adapter stellt die Nachricht in eine speicherinterne Warteschlange ein, die bereit zur Übertragung ist.
Ein Thread aus dem Threadpool des Adapters entfernt die Nachricht aus der Warteschlange, liest die Konfiguration für die Nachricht und überträgt die Nachricht über das Kabel.
Der Adapter erhält einen neuen Stapel vom Motor.
Der Adapter ruft DeleteMessage im Batch auf und übergibt die soeben übertragene Nachricht.
Der Adapter ruft "Done" im Batch auf.
Das Modul verarbeitet den Batch und löscht die Nachricht aus der Anwendungswarteschlange.
Das Modul ruft den Adapter zurück, um ihn über das Ergebnis des DeleteMessage-Vorgangs zu benachrichtigen.
Das vorherige Objektinteraktionsdiagramm zeigt den Adapter, der eine einzelne Nachricht aus der Anwendungswarteschlange löscht. Im Idealfall verarbeitet der Adapter mehrere Nachrichtenvorgänge gleichzeitig, anstatt eine einzelne Nachricht zu bearbeiten.
Batchsendungen
Adapter, die batchfähig sind, sollten IBTBatchTransmitter und IBTTransmitterBatch implementieren, wie in Schnittstellen für Sendeadapter beschrieben. Wenn das Modul Nachrichten für den zu übertragenden Adapter hat, ruft das Modul einen neuen Batch vom Adapter ab, indem IBTBatchTransmitter.GetBatch aufgerufen wird. Der Adapter gibt ein neues Batchobjekt zurück, das IBTTransmitterBatch implementiert. Das Modul startet dann den Batch durch Aufrufen von IBTTransmitterBatch.BeginBatch. Diese API verfügt über einen Out-Parameter, mit dem der Adapter die maximale Anzahl von Nachrichten angeben kann, die er für den Batch akzeptiert. Der Adapter kann optional eine DTC-Transaktion zurückgeben. Das Modul ruft dann IBTTransmitterBatch.TransmitMessage einmal auf, damit jede ausgehende Nachricht dem Batch hinzugefügt wird. Die Anzahl der Aufrufe ist größer als Null, aber kleiner oder gleich der maximalen Größe des Batches, wie vom Adapter angegeben. Wenn alle Nachrichten dem Batch hinzugefügt wurden, ruft der Adapter IBTTransmitterBatch.Done auf. An diesem Punkt stellt der Adapter typischerweise alle Nachrichten im Stapel in die Speicherwarteschlange ein. Der Adapter überträgt die Nachrichten von einem Thread oder Threads in einem eigenen Threadpool wie bei nicht batchfähigen Adaptern. Der Adapter benachrichtigt dann die Engine über das Ergebnis der Übertragung.
Das folgende Objektinteraktionsdiagramm veranschaulicht die Übertragung von zwei Nachrichten durch einen Batch-Sendeadapter.
Behandeln von Übertragungsfehlern
Die empfohlene Semantik für Übertragungsfehler wird in der folgenden Abbildung veranschaulicht. Dies sind nur Empfehlungen und werden nicht vom Messagingmodul erzwungen. Sie können einen Adapter entwickeln, der von diesen Richtlinien abweicht, wenn es gültige Gründe dafür gibt. In diesem Fall sollten Sie jedoch vorsichtig sein. Zum Beispiel sollte ein Adapter im Allgemeinen Nachrichten immer in den Sicherungstransport verschieben, nachdem alle Versuche erschöpft sind.
In der Regel muss ein Transport möglicherweise mehr Wiederholungen verwenden, als konfiguriert sind. Obwohl dies etwas anders ist, wird sie als akzeptabel angesehen, da die Resilienz der Transportschicht erhöht wird. Im Allgemeinen sind die APIs, die vom Messagingmodul verfügbar gemacht werden, so konzipiert, dass der Adapter möglichst viel Kontrolle erhält. Mit diesem Steuerelement kommt ein größeres Maß an Verantwortung.
Der Adapter bestimmt die Anzahl der in einer Nachricht verfügbaren Wiederholungen, indem die Systemkontexteigenschaft RetryCount überprüft wird. Der Adapter ruft die Resubmit-API einmal für jeden Wiederholungsversuch auf und übergibt die Nachricht, die erneut übermittelt werden soll. Zusammen mit der Nachricht wird der Zeitstempel übergeben, der angibt, wann die Engine die Nachricht zurück an den Adapter übermitteln soll. Dieser Wert sollte in der Regel die aktuelle Uhrzeit plus der Wert von "RetryInterval" sein. RetryInterval ist eine Systemkontexteigenschaft, deren Einheiten Minuten sind. Sowohl " RetryCount " als auch " RetryInterval " im Nachrichtenkontext sind die Werte, die für den Sendeport konfiguriert sind. Erwägen Sie eine skalierte Bereitstellung mit Instanzen desselben BizTalk-Hosts, die auf mehreren Computern bereitgestellt werden. Wenn die Nachricht übermittelt wird, nachdem das Wiederholungsintervall abgelaufen ist, kann die Nachricht an eine der Hostinstanzen auf einem der Computer übermittelt werden, auf denen sie für die Ausführung konfiguriert sind. Aus diesem Grund sollte der Adapter keinen Zustand enthalten, der einer Nachricht zugeordnet ist, die für den Wiederholungsversuch verwendet werden soll, da es keine Garantie gibt, dass dieselbe Instanz des Adapters zu einem späteren Zeitpunkt für die Übertragung verantwortlich ist.
Der Adapter sollte nur versuchen, die Nachricht in den Sicherungstransport zu verschieben, nachdem die Wiederholungsanzahl kleiner oder gleich Null ist. Ein Versuch, die Nachricht in den Sicherungstransport zu verschieben, schlägt fehl, wenn kein Sicherungstransport für den Port konfiguriert ist. In diesem Fall sollte die Nachricht angehalten werden.
Das folgende Codefragment veranschaulicht, wie Sie die Wiederholungsanzahl und das Intervall aus dem Nachrichtenkontext ermitteln und anschließend erneut übermitteln oder zum Backup-Transport verschieben können.
using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.TransportProxy.Interop;
…
// RetryCount and RetyInterval are system context properties...
private static readonly PropertyBase RetryCountProperty =
new BTS.RetryCount();
private static readonly PropertyBase RetryIntervalProperty =
new BTS.RetryInterval();
public void HandleRetry(IBaseMessage msg, IBTTransportBatch batch)
{
int retryCount = 0;
int retryInterval = 0;
// Get the RetryCount and RetryInterval off the msg ctx...
GetMessageRetryState(msg, out retryCount, out retryInterval);
// If we have retries available resubmit, else move to
// backup transport...
if ( retryCount > 0 )
batch.Resubmit(
msg, DateTime.Now.AddMinutes(retryInterval));
else
batch.MoveToNextTransport(msg);
}
public void GetMessageRetryState(
IBaseMessage msg,
out int retryCount,
out int retryInterval )
{
retryCount = 0;
retryInterval = 0;
object obj = msg.Context.Read(
RetryCountProperty.Name.Name,
RetryCountProperty.Name.Namespace);
if ( null != obj )
retryCount = (int)obj;
obj = msg.Context.Read(
RetryIntervalProperty.Name.Name,
RetryIntervalProperty.Name.Namespace);
if ( null != obj )
retryInterval = (int)obj;
}
Auslösen einer Ausnahme von TransmitMessage
Wenn der Adapter eine Ausnahme für eine der APIs IBTTransmitter.TransmitMessage, IBTTransmitterBatch.TransmitMessage, IBTTransmitterBatch.Done auslöst, behandelt das Modul die Übertragung der nachrichten als Übertragungsfehler und führt die entsprechende Aktion für die Nachricht aus, wie in der Behandlung von Adapterfehlern beschrieben.
Bei batchfähigen Sendeadaptern führt das Auslösen einer Ausnahme für die TransmitMessage-API dazu, dass der gesamte Batch gelöscht wird und die standardmäßigen Sendefehleraktionen für alle Nachrichten in diesem Batch ausgeführt werden.
Solicit-Response
Bidirektionale Sendeadapter unterstützen in der Regel sowohl unidirektionale als auch bidirektionale Übertragungen. Der Sendeadapter bestimmt, ob die Nachricht als unidirektionales oder bidirektionales Senden übertragen werden soll, indem die Systemkontexteigenschaft IsSolicitResponse im Nachrichtenkontext überprüft wird.
Das folgende Codefragment veranschaulicht folgendes:
private bool portIsTwoWay = false;
private static readonly PropertyBase IsSolicitResponseProperty= new BTS.IsSolicitResponse();
...
// Port is one way or two way...
object obj = this.message.Context.Read(
IsSolicitResponseProperty.Name.Name,
IsSolicitResponseProperty.Name.Namespace);
if ( null != obj )
this.portIsTwoWay = (bool)obj;
Während einer Solicit-Response-Übertragung überträgt der Adapter die Anforderungsnachricht. Nach Abschluss dieses Vorgangs sendet es die zugeordnete Antwort und weist die Messaging Engine an, die ursprüngliche Anforderungsnachricht aus der MessageBox-Datenbank zu löschen. Die Aktion zum Löschen der Nachricht aus der Anwendungswarteschlange sollte im gleichen Transportproxybatch wie die Übermittlung der Antwortnachricht ausgeführt werden. Dadurch wird die Atomität der Löschung und Übermittlung der Antwort sichergestellt. Zur vollständigen Atomizität sollte der Adapter eine DTC-Transaktion verwenden, bei der die Übermittlung der Aufforderungsnachricht an eine transaktionsfähige Ressource, die Übermittlung der Antwortnachricht und das Löschen der Aufforderungsnachricht im Kontext derselben DTC-Transaktion erfolgt. Wie immer empfehlen wir, dass die Aufforderungsnachricht mit einem nicht blockierenden Senden übertragen wird.
Das folgende Codefragment veranschaulicht die wichtigsten Aspekte eines bidirektionales Sendens. Wenn die Engine IBTTransmitter.TransmitMessage aufruft, stellt der Adapter die Nachricht in eine Speicherwarteschlange, um sie zu übertragen. Der Adapter gibt false zurück, um anzuzeigen, dass er einen nicht blockierenden Sendevorgang ausführt. Der Threadpool des Adapters (WorkerThreadThunk) bearbeitet die Speicherwarteschlange und entfernt eine Meldung, um sie an eine Hilfsmethode zu übergeben. Diese Methode ist für das Senden der Solicit-Nachricht und das Empfangen der Antwortnachricht verantwortlich. (Die Implementierung dieser Hilfsmethode liegt außerhalb des Umfangs dieses Themas.) Die Antwortnachricht wird in die Engine übermittelt, und die Anforderungsnachricht wird aus der Anwendungswarteschlange gelöscht.
using System.Collections;
using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.TransportProxy.Interop;
static private Queue _transmitQueue = new Queue();
static private IBTTransportProxy _transportProxy = null;
// IBTTransmitter...
public bool TransmitMessage(IBaseMessage msg)
{
// Add message to the transmit queue...
lock(_transmitQueue.SyncRoot)
{
_transmitQueue.Enqueue(msg);
}
return false;
}
// Threadpool worker thread...
private void WorkerThreadThunk()
{
try
{
IBaseMessage solicitMsg = null;
lock(_transmitQueue.SyncRoot)
{
solicitMsg =
(IBaseMessage)_transmitQueue.Dequeue();
}
IBaseMessage responseMsg = SendSolicitResponse(
solicitMsg );
Callback cb = new Callback();
IBTTransportBatch batch = _transportProxy.GetBatch(
cb, null);
batch.SubmitResponseMessage( solicitMsg, responseMsg );
batch.DeleteMessage( solicitMsg );
batch.Done(null);
}
catch(Exception)
{
// Handle failure....
}
}
static private IBaseMessage SendSolicitResponse(
IBaseMessage solicitMsg )
{
// Helper method to send solicit message and receive
// response message...
IBaseMessage responseMsg = null;
return responseMsg;
}
Dynamische Sende
Dynamische Sendeports weisen keine Adapterkonfiguration auf. Stattdessen verwenden sie die Handlerkonfiguration für alle Standardeigenschaften, die der Adapter zum Übertragen von Nachrichten an einem dynamischen Port benötigt. Beispielsweise muss ein HTTP-Adapter möglicherweise einen Proxy verwenden und Anmeldeinformationen angeben. Der Benutzername, das Kennwort und der Port können in der Handlerkonfiguration angegeben werden, die der Adapter zur Laufzeit zwischenspeichert.
Damit die Engine den Transport bestimmt, über den eine dynamische Nachricht gesendet werden soll, wird der OutboundTransportLocation dem Alias des Adapters vorangestellt. Ein Adapter kann während der Installation einen oder mehrere Aliase bei BizTalk Server registrieren. Das Modul analysiert die OutboundTransportLocation zur Laufzeit, um eine Übereinstimmung zu finden. Der Adapter ist dafür verantwortlich, die OutboundTransportLocation zu verarbeiten, unabhängig davon, ob das Alias davor gesetzt wurde oder nicht. In der folgenden Tabelle sind einige Beispiele für Aliase aufgeführt, die für sofort einsatzbereite BizTalk-Adapter registriert sind.
| Adapteralias | Adapter | Beispiel für "OutboundTransportLocation" |
|---|---|---|
| HTTP:// | HTTP | http://www. MyCompany.com/bar |
| HTTPS:// | HTTP | https://www. MyCompany.com/bar |
| mailto: | SMTP | mailto:A.User@MyCompany.com |
| DATEI:// | DATEI | FILE://C:\ MyCompany \%MessageID%.xml |