Partager via


Optimisation des performances du pipeline

Cette rubrique décrit les instructions relatives à l’optimisation des performances des pipelines dans une solution BizTalk Server.

Meilleures pratiques pour optimiser les performances des pipelines BizTalk Server

  1. Étant donné que les composants de pipeline ont un impact significatif sur les performances (par exemple, un composant de pipeline directe effectue jusqu’à 30 % de mieux qu’un composant de pipeline assembleur/désassembleur XML), assurez-vous que tous les composants de pipeline personnalisés s’exécutent de manière optimale avant de les implémenter dans votre déploiement. Réduisez le nombre de composants de pipeline dans vos pipelines personnalisés si vous souhaitez optimiser les performances globales de votre application BizTalk.

  2. Vous pouvez également améliorer les performances globales en réduisant la fréquence de persistance des messages dans votre composant de pipeline et en codeant votre composant pour réduire la redondance. Chaque assembly personnalisé et en particulier les artefacts susceptibles de perturber les performances, comme les composants de suivi personnalisés, doit être testé séparément en condition de charge importante pour observer leur comportement lorsque le système fonctionne à pleine capacité et pour trouver les goulots d’étranglement possibles.

  3. Si vous devez lire le message entrant à l’intérieur d’un composant de pipeline, évitez de charger l’intégralité du document en mémoire à l’aide d’un objet XmlDocument . La quantité d’espace nécessaire par une instance de la classe XmlDocument pour charger et créer une représentation en mémoire d’un document XML est jusqu’à 10 fois la taille réelle du message. Pour lire un message, vous devez utiliser un objet XmlTextReader avec une instance des classes suivantes :

    • VirtualStream (Microsoft.BizTalk.Streaming.dll) : le code source de cette classe se trouve à deux emplacements sous le Kit de développement logiciel (SDK) Pipelines : SDK\Samples\Pipelines\ArbitraireXPathPropertyHandler et SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.

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

    • SeekAbleReadOnlyStream : le code source de cette classe se trouve à deux emplacements sous le Kit de développement logiciel (SDK) Pipelines comme suit : SDK\Samples\Pipelines\ArbitraryXPathPropertyHandler et SDK\Samples\Pipelines\SchemaResolverComponent\SchemaResolverFlatFileDasm.

  4. Utilisez les pipelines standard PassThruReceive et PassThruTransmit dans la mesure du possible. Ils ne contiennent aucun composant de pipeline et n’effectuent aucun traitement du message. Pour cette raison, ils garantissent des performances maximales lors de la réception ou de l’envoi de messages. Vous pouvez utiliser un pipeline PassThruReceive sur un emplacement de réception si vous devez publier un document binaire dans BizTalk MessageBox et un pipeline PassThruTransmit sur un port d’envoi si vous devez envoyer un message binaire. Vous pouvez également utiliser le pipeline PassThruTransmit sur un port d’envoi physique lié à une orchestration si le message a été mis en forme et est prêt à être transmis. Vous devez utiliser une approche différente si vous devez effectuer l’une des actions suivantes :

    • Promouvoir les propriétés dans le contexte d’un message XML ou fichier plat entrant.

    • Appliquez une carte à l’intérieur d’un emplacement de réception.

    • Appliquez une carte dans une orchestration qui s’abonne à un message.

    • Appliquez une carte sur un port d’envoi qui s’abonne à un message.

      Pour effectuer l’une de ces actions, vous devez sonder et découvrir le type de document à l’intérieur du pipeline de réception et affecter la valeur (namespace#root-name) à la propriété de contexte MessageType. Cette opération est généralement effectuée par un composant désassembleur tel que le composant Désassembleur Xml (XmlDasmComp) ou le composant de désassembleur de fichier plat (FFDasmComp). Dans ce cas, vous devez utiliser un pipeline standard (par exemple, un pipeline XmlReceive) ou un pipeline personnalisé qui contient un composant désassembleur standard ou personnalisé.

  5. Acquérir des ressources aussi tard que possible et les libérer le plus tôt possible. Par exemple, si vous avez besoin d’accéder aux données sur une base de données, ouvrez la connexion le plus tard possible et fermez-la dès que possible. Utilisez l’instruction C# using pour libérer implicitement des objets jetables ou le bloc final d’une instruction try-catch-finally pour supprimer explicitement vos objets. Instrumentez votre code source pour simplifier le débogage de vos composants.

  6. Éliminez les composants de vos pipelines qui ne sont pas strictement requis pour accélérer le traitement des messages.

  7. Dans un pipeline de réception, vous devez promouvoir des éléments vers le contexte de message uniquement si vous en avez besoin pour le routage des messages (orchestrations, ports d'envoi) ou la réduction des propriétés de contexte de message (ports d'envoi).

  8. Si vous devez inclure des métadonnées avec un message et que vous n’utilisez pas les métadonnées à des fins de routage ou de rétrogradation, utilisez la méthode IBaseMessageContext.Write au lieu de la méthode IBaseMessageContext.Promote .

  9. Si vous devez extraire des informations d’un message à l’aide d’une expression XPath, évitez de charger l’intégralité du document en mémoire à l’aide d’un objet XmlDocument simplement pour utiliser les méthodes SelectNodes ou SelectSingleNode . Vous pouvez également utiliser les techniques décrites dans l’optimisation de l’utilisation de la mémoire avec la diffusion en continu.

Utiliser la diffusion en continu pour réduire l’empreinte mémoire requise lors du chargement des messages dans les pipelines

Les techniques suivantes décrivent comment réduire l’empreinte mémoire d’un message lors du chargement du message dans un pipeline.

Utiliser ReadOnlySeekableStream et VirtualStream pour traiter un message à partir d’un composant de pipeline

Il est considéré comme une bonne pratique pour éviter de charger l’intégralité du message dans la mémoire à l’intérieur des composants de pipeline. Une approche préférable consiste à encapsuler le flux entrant avec une implémentation de flux personnalisé, puis à mesure que les demandes de lecture sont effectuées, l’implémentation de flux personnalisé lit le flux sous-jacent, encapsulé et traite les données comme il est lu (de manière pure en streaming). Cela peut être très difficile à implémenter et peut ne pas être possible, en fonction de ce qui doit être fait avec le flux. Dans ce cas, utilisez les classes ReadOnlySeekableStream et VirtualStream exposées par le Microsoft.BizTalk.Streaming.dll. Une implémentation de celles-ci est également fournie dans le gestionnaire de propriétés XPath arbitraire (exemple BizTalk Server) (https://go.microsoft.com/fwlink/?LinkId=160069) dans le Kit de développement logiciel (SDK) BizTalk.ReadOnlySeekableStream garantit que le curseur peut être repositionné au début du flux. VirtualStream utilise un MemoryStream en interne, sauf si la taille est supérieure à un seuil spécifié, auquel cas elle écrit le flux dans le système de fichiers. L'utilisation de ces deux flux en combinaison (à l'aide de VirtualStream comme stockage persistant pour ReadOnlySeekableStream) fournit à la fois des fonctionnalités de « recherchabilité » et de « débordement vers le système de fichiers ». Cela permet de traiter les messages volumineux sans charger l’intégralité du message en mémoire. Le code suivant peut être utilisé dans un composant de pipeline pour implémenter cette fonctionnalité.

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

Ce code fournit un « seuil de dépassement de capacité » en exposant les variables bufferSize et thresholdSize sur chaque emplacement de réception ou configuration du port d’envoi. Ce seuil de dépassement peut ensuite être ajusté par les développeurs ou les administrateurs pour différents types de messages et différentes configurations (par exemple, 32 bits et 64 bits).

Utilisation de XPathReader et XPathCollection pour extraire un objet IBaseMessage donné à partir d’un composant de pipeline personnalisé.

Si des valeurs spécifiques doivent être extraites d’un document XML, au lieu d’utiliser les méthodes SelectNodes et SelectSingleNode exposées par la classe XmlDocument, utilisez une instance de la classe XPathReader fournie par l’assembly Microsoft.BizTalk.XPathReader.dll, comme illustré dans l’exemple de code suivant.

Remarque

Pour les messages plus petits en particulier, l’utilisation d’un XmlDocument avec SelectNodes ou SelectSingleNode peut fournir de meilleures performances que l’utilisation de XPathReader, mais XPathReader vous permet de conserver un profil de mémoire plat pour votre application.

Cet exemple montre comment utiliser XPathReader et XPathCollection pour extraire un objet IBaseMessage donné à partir d’un composant de pipeline personnalisé.

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

Utiliser XMLReader et XMLWriter avec XMLTranslatorStream pour traiter un message à partir d’un composant de pipeline

Une autre méthode pour implémenter un composant de pipeline personnalisé qui utilise une approche de streaming consiste à utiliser les classes .NET XmlReader et XmlWriter conjointement avec la classe XmlTranslatorStream fournie par BizTalk Server. Par exemple, la classe NamespaceTranslatorStream contenue dans l’assembly Microsoft.BizTalk.Pipeline.Components hérite de XmlTranslatorStream et peut être utilisée pour remplacer un ancien espace de noms par un nouvel espace de noms dans le document XML contenu dans le flux. Pour utiliser cette fonctionnalité à l’intérieur d’un composant de pipeline personnalisé, vous pouvez encapsuler le flux de données d’origine du composant corps du message avec une nouvelle instance de la classe NamespaceTranslatorStream et renvoyer ce dernier. De cette façon, le message entrant n’est pas lu ou traité à l’intérieur du composant de pipeline, mais uniquement lorsque le flux est lu par un composant suivant dans le même pipeline ou est finalement consommé par l’Agent de message avant de publier le document dans BizTalk Server MessageBox.

L’exemple suivant montre comment utiliser cette fonctionnalité.

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

Utilisation de ResourceTracker dans des composants de pipeline personnalisés

Un composant de pipeline doit gérer la durée de vie des objets qu’il crée et effectuer un garbage collection dès que ces objets ne sont plus nécessaires. Si le composant du pipeline souhaite que la durée de vie des objets se prolonge jusqu'à la fin de l'exécution, vous devez ajouter ces objets au traqueur de ressources que votre pipeline peut récupérer à partir du contexte.

Le suivi des ressources est utilisé pour les types d’objets suivants :

  • Diffuser des objets

  • Objets COM

  • Objets IDisposables

    Le moteur de message garantit que toutes les ressources natives ajoutées au suivi des ressources sont publiées en temps opportun, c’est-à-dire une fois le pipeline complètement exécuté, qu’il ait réussi ou échoué. La durée de vie de l’instance Resource Tracker et les objets qu’il suit est gérée par l’objet de contexte de pipeline. Le contexte de pipeline est mis à la disposition de tous les types de composants de pipeline via un objet qui implémente l’interface IPipelineContext.

    Par exemple, l’extrait de code suivant est un exemple qui montre comment utiliser la propriété ResourceTracker dans les composants de pipeline personnalisés. Pour utiliser la propriété ResourceTracker, l’extrait de code utilise le paramètre IPipelineContext.ResourceTracker.AddResourcesuivant. Dans ce paramètre :

  • L’interface IPipelineContext définit les méthodes utilisées pour accéder à toutes les interfaces spécifiques au traitement de documents.

  • La propriété ResourceTracker fait référence à IPipelineContext et est utilisée pour effectuer le suivi des objets qui seront supprimés explicitement à la fin du traitement du pipeline.

  • La méthode ResourceTracker.AddResource permet de suivre les objets COM, les objets jetables et les flux, et doit toujours être utilisée à l’intérieur d’un composant de pipeline personnalisé pour fermer explicitement (flux), supprimer (objets IDisposable) ou libérer (objets COM) ces types de ressources lorsqu’un message est publié dans 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;

}

Comparaison du chargement de messages dans des pipelines à l’aide d’une approche en mémoire et d’une approche de diffusion en continu

Les informations suivantes ont été extraites du blog de 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). Ce tableau fournit une comparaison résumée du chargement de messages dans des pipelines à l’aide d’une approche en mémoire et d’une approche de streaming.

Comparaison de... Diffusion en continu En mémoire
Utilisation de la mémoire par message Faible, quelle que soit la taille du message Élevé (varie en fonction de la taille du message)
Classes courantes utilisées pour traiter les données XML Dérivations intégrées et personnalisées des éléments suivants :

XmlTranslatorStream, XmlReader et XmlWriter
XmlDocument, XPathDocument, MemoryStream et VirtualStream
Documentation Médiocre : de nombreuses classes BizTalk non prises en charge et non documentées Très bon - Classes .NET Framework
Emplacement du code « Logique de traitement » - Reliez les lecteurs et les flux via la méthode Execute.
- L’exécution réelle se produit dans les lecteurs et les flux à mesure que les données sont lues.
Directement à partir de la méthode Execute du composant de pipeline.
Données Recréé à chaque couche d'enveloppement lorsque les données sont lues. Les données sont lues, modifiées et enregistrées à chaque composant avant d'appeler le composant suivant.

Voir aussi

Optimisation des applications BizTalk Server