Condividi tramite


Ottimizzazione delle prestazioni della pipeline

Questo argomento descrive le linee guida per ottimizzare le prestazioni delle pipeline in una soluzione BizTalk Server.

Procedure consigliate per ottimizzare le prestazioni delle pipeline di BizTalk Server

  1. Poiché i componenti della pipeline hanno un impatto significativo sulle prestazioni (ad esempio, un componente della pipeline pass-through offre prestazioni migliori del 30% rispetto a un componente della pipeline assembler/disassembler XML), assicurarsi che tutti i componenti della pipeline personalizzati eseguano in modo ottimale prima di implementarli nella distribuzione. Ridurre al minimo il numero di componenti della pipeline nelle pipeline personalizzate se si vuole ottimizzare le prestazioni complessive dell'applicazione BizTalk.

  2. È anche possibile migliorare le prestazioni complessive riducendo la frequenza di persistenza dei messaggi nel componente della pipeline e codificando il componente per ridurre al minimo la ridondanza. Ogni assembly personalizzato e in particolare gli artefatti che potrebbero compromettere le prestazioni, ad esempio i componenti di rilevamento personalizzati, devono essere testati separatamente in condizioni di carico elevato per osservarne il comportamento quando il sistema lavora a piena capacità e per trovare eventuali colli di bottiglia possibili.

  3. Se è necessario leggere il messaggio in ingresso all'interno di un componente della pipeline, evitare di caricare l'intero documento in memoria usando un oggetto XmlDocument . La quantità di spazio richiesta da un'istanza della classe XmlDocument per caricare e creare una rappresentazione in memoria di un documento XML è fino a 10 volte la dimensione effettiva del messaggio. Per leggere un messaggio, è necessario utilizzare un oggetto XmlTextReader insieme a un'istanza delle classi seguenti:

    • VirtualStream (Microsoft.BizTalk.Streaming.dll): il codice sorgente per questa classe si trova in due posizioni in Pipelines SDK come indicato di seguito: SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler e SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.

    • ReadOnlySeekableStream (Microsoft.BizTalk.Streaming.dll).

    • SeekAbleReadOnlyStream : il codice sorgente per questa classe si trova in due posizioni in Pipelines SDK come indicato di seguito: SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler e SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.

  4. Usare le pipeline standard PassThruReceive e PassThruTransmit quando possibile. Non contengono alcun componente della pipeline e non eseguono alcuna elaborazione del messaggio. Per questo motivo, garantiscono prestazioni massime nella ricezione o nell'invio di messaggi. È possibile usare una pipeline PassThruReceive in un percorso di ricezione se è necessario pubblicare un documento binario in BizTalk MessageBox e una pipeline PassThruTransmit su una porta di trasmissione se è necessario inviare un messaggio binario. È anche possibile usare la pipeline PassThruTransmit su una porta di trasmissione fisica associata a un'orchestrazione se il messaggio è stato formattato ed è pronto per la trasmissione. Se è necessario eseguire una delle azioni seguenti, è necessario usare un approccio diverso:

    • Alzare di livello le proprietà nel contesto di un messaggio XML in ingresso o file flat.

    • Applicare una mappa all'interno di una posizione di ricezione.

    • Applicare una mappa in un'orchestrazione che sottoscrive un messaggio.

    • Applicare una mappa su una porta di trasmissione che sottoscrive un messaggio.

      Per eseguire una di queste azioni, è necessario eseguire il probe e individuare il tipo di documento all'interno della pipeline di ricezione e assegnare il valore (namespace#root-name) alla proprietà context MessageType. Questa operazione viene in genere eseguita da un componente disassembler, ad esempio il componente Disassembler Xml (XmlDasmComp) o il componente disassembler file flat (FFDasmComp). In questo caso, è necessario usare uno standard (ad esempio, una pipeline XmlReceive) o una pipeline personalizzata che contiene un componente standard o un disassembler personalizzato.

  5. Acquisire le risorse il più tardi possibile e rilasciarle il prima possibile. Ad esempio, se è necessario accedere ai dati in un database, aprire la connessione il più tardi possibile e chiuderla il prima possibile. Usare l'istruzione using C# per rilasciare in modo implicito oggetti eliminabili o il blocco finally di un'istruzione try-catch-finally per eliminare in modo esplicito gli oggetti. Instrumentare il codice sorgente per semplificare il debug dei componenti.

  6. Eliminare tutti i componenti dalle pipeline che non sono strettamente necessari per velocizzare l'elaborazione dei messaggi.

  7. All'interno di una pipeline di ricezione, è consigliabile alzare di livello gli elementi al contesto del messaggio solo se sono necessari per il routing dei messaggi (orchestrazioni, porte di trasmissione) o l'abbassamento di livello delle proprietà del contesto del messaggio (porte di trasmissione).

  8. Se è necessario includere metadati con un messaggio e non si usano i metadati per scopi di routing o abbassamento di livello, usare il metodo IBaseMessageContext.Write anziché il metodo IBaseMessageContext.Promote .

  9. Se è necessario estrarre informazioni da un messaggio usando un'espressione XPath, evitare di caricare l'intero documento in memoria usando un oggetto XmlDocument solo per utilizzare i metodi SelectNodes o SelectSingleNode . In alternativa, usare le tecniche descritte in Ottimizzazione dell'utilizzo della memoria con streaming.

Usare lo streaming per ridurre al minimo il footprint di memoria necessario durante il caricamento dei messaggi nelle pipeline

Le tecniche seguenti descrivono come ridurre al minimo il footprint di memoria di un messaggio durante il caricamento del messaggio in una pipeline.

Usare ReadOnlySeekableStream e VirtualStream per elaborare un messaggio da un componente della pipeline

È consigliabile evitare di caricare l'intero messaggio in memoria all'interno dei componenti della pipeline. Un approccio preferibile consiste nel eseguire il wrapping del flusso in ingresso con un'implementazione del flusso personalizzato e quindi, man mano che vengono effettuate richieste di lettura, l'implementazione del flusso personalizzato legge il flusso sottostante, sottoposto a wrapping ed elabora i dati mentre vengono letti (in modo puro). Questa operazione può essere molto difficile da implementare e potrebbe non essere possibile, a seconda di ciò che deve essere fatto con il flusso. In questo caso, usare le classi ReadOnlySeekableStream e VirtualStream esposte dal Microsoft.BizTalk.Streaming.dll. Un'implementazione di queste funzionalità viene fornita anche in Arbitraria XPath Property Handler (BizTalk Server Sample) (https://go.microsoft.com/fwlink/?LinkId=160069) in BizTalk SDK.ReadOnlySeekableStream assicura che il cursore possa essere riposizionato all'inizio del flusso. VirtualStream userà internamente memoryStream, a meno che le dimensioni non superano una soglia specificata, nel qual caso scriverà il flusso nel file system. L'uso di questi due flussi in combinazione (usando VirtualStream come risorsa di archiviazione permanente per ReadOnlySeekableStream) offre funzionalità di "ricercabilità" e "overflow nel file system". Questo consente l'elaborazione di messaggi di grandi dimensioni senza caricare l'intero messaggio in memoria. Per implementare questa funzionalità, è possibile usare il codice seguente in un componente della pipeline.

int bufferSize = 0x280;
int thresholdSize = 0x100000;
Stream vStream = new VirtualStream(bufferSize, thresholdSize);
Stream seekStream = new ReadOnlySeekableStream(inboundStream, vStream, bufferSize);

Questo codice fornisce una "soglia di overflow" esponendo le variabili bufferSize e thresholdSize in ogni posizione di ricezione o configurazione della porta di trasmissione. Questa soglia di overflow può quindi essere modificata dagli sviluppatori o dagli amministratori per diversi tipi di messaggi e configurazioni diverse ,ad esempio a 32 bit rispetto a 64 bit.

Utilizzo di XPathReader e XPathCollection per estrarre un determinato oggetto IBaseMessage dall'interno di un componente della pipeline personalizzato.

Se è necessario eseguire il pull di valori specifici da un documento XML, anziché utilizzare i metodi SelectNodes e SelectSingleNode esposti dalla classe XmlDocument, utilizzare un'istanza della classe XPathReader fornita dall'assembly Microsoft.BizTalk.XPathReader.dll, come illustrato nell'esempio di codice seguente.

Nota

Per i messaggi più piccoli, l'uso di xmlDocument con SelectNodes o SelectSingleNode può offrire prestazioni migliori rispetto all'uso di XPathReader, ma XPathReader consente di mantenere un profilo di memoria flat per l'applicazione.

In questo esempio viene illustrato come utilizzare XPathReader e XPathCollection per estrarre un determinato oggetto IBaseMessage dall'interno di un componente della pipeline personalizzato.

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;
}

Usare XMLReader e XMLWriter con XMLTranslatorStream per elaborare un messaggio da un componente della pipeline

Un altro metodo per l'implementazione di un componente pipeline personalizzato che usa un approccio di streaming consiste nell'usare le classi XmlReader e XmlWriter .NET insieme alla classe XmlTranslatorStream fornita da BizTalk Server. Ad esempio, la classe NamespaceTranslatorStream contenuta nell'assembly Microsoft.BizTalk.Pipeline.Components eredita da XmlTranslatorStream e può essere usata per sostituire uno spazio dei nomi precedente con uno nuovo nel documento XML contenuto nel flusso. Per usare questa funzionalità all'interno di un componente della pipeline personalizzato, è possibile eseguire il wrapping del flusso di dati originale della parte del corpo del messaggio con una nuova istanza della classe NamespaceTranslatorStream e restituire quest'ultimo. In questo modo il messaggio in ingresso non viene letto o elaborato all'interno del componente della pipeline, ma solo quando il flusso viene letto da un componente successivo nella stessa pipeline o viene infine utilizzato dall'agente messaggi prima di pubblicare il documento nel BizTalk Server MessageBox.

Nell'esempio seguente viene illustrato come usare questa funzionalità.

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;
}

Uso di ResourceTracker nei componenti della pipeline personalizzati

Un componente della pipeline deve gestire la durata degli oggetti creati ed eseguire Garbage Collection non appena questi oggetti non sono più necessari. Se il componente della pipeline vuole che la durata degli oggetti dura fino alla fine dell'esecuzione della pipeline, è necessario aggiungere tali oggetti al rilevamento delle risorse che la pipeline può recuperare dal contesto della pipeline.

Lo strumento di rilevamento delle risorse viene usato per i tipi di oggetti seguenti:

  • Oggetti Stream

  • oggetti COM

  • Oggetti IDisposable

    Il motore di messaggi garantisce che tutte le risorse native aggiunte al tracker delle risorse vengano rilasciate in un momento appropriato, ovvero dopo che la pipeline viene eseguita completamente, indipendentemente dal fatto che abbia avuto esito positivo o negativo. La durata dell'istanza di Resource Tracker e degli oggetti da tenere traccia viene gestita dall'oggetto contesto della pipeline. Il contesto della pipeline viene reso disponibile per tutti i tipi di componenti della pipeline tramite un oggetto che implementa l'interfaccia IPipelineContext.

    Ad esempio, il frammento di codice seguente è un esempio che illustra come usare la proprietà ResourceTracker nei componenti della pipeline personalizzati. Per usare la proprietà ResourceTracker, il frammento di codice usa il parametro IPipelineContext.ResourceTracker.AddResourceseguente. In questo parametro:

  • L'interfaccia IPipelineContext definisce i metodi usati per accedere a tutte le interfacce specifiche dell'elaborazione dei documenti.

  • La proprietà ResourceTracker fa riferimento a IPipelineContext e viene usata per tenere traccia degli oggetti che verranno eliminati in modo esplicito alla fine dell'elaborazione della pipeline.

  • Il metodo ResourceTracker.AddResource viene usato per tenere traccia di oggetti COM, oggetti e flussi eliminabili e deve essere sempre usato all'interno di un componente della pipeline personalizzato per chiudere in modo esplicito (flussi), eliminare (oggetti IDisposable) o rilasciare (oggetti COM) questi tipi di risorse quando un messaggio viene pubblicato in 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;

}

Confronto tra il caricamento dei messaggi nelle pipeline tramite un approccio in memoria e l'uso di un approccio di streaming

Le informazioni seguenti sono state tratte dal blog di Nic Barden (http://blogs.objectsharp.com/cs/blogs/nbarden/archive/2008/04/14/developing-streaming-pipeline-components-part-1.aspxhttps://go.microsoft.com/fwlink/?LinkId=160228). Questa tabella fornisce un confronto riepilogato del caricamento dei messaggi nelle pipeline usando un approccio in memoria e un approccio di streaming.

Confronto tra... Streaming In memoria
Utilizzo della memoria per messaggio Bassa, indipendentemente dalle dimensioni dei messaggi Alta (varia a seconda delle dimensioni del messaggio)
Classi comuni usate per elaborare i dati XML Derivazioni predefinite e personalizzate di:

XmlTranslatorStream, XmlReader e XmlWriter
XmlDocument, XPathDocument, MemoryStream e VirtualStream
Documentazione Scarsa: molte classi BizTalk non supportate e non documentate Ottimo - Classi .NET Framework
Posizione del codice "Elaborazione logica" - Lettori e flussi "Wire up" tramite il metodo Execute.
- L'esecuzione effettiva avviene nei lettori e nei flussi durante la lettura dei dati.
Direttamente dal metodo Execute del componente della pipeline.
Dati Ricreato a ogni livello di wrapping man mano che i dati sono letti. Leggere, modificare e scrivere in ogni componente prima di chiamare il componente successivo.

Vedere anche

Ottimizzazione delle applicazioni BizTalk Server