优化业务流程性能

本主题介绍在BizTalk Server解决方案中使用业务流程的最佳做法。 这包括针对以下项的建议:

  • 降低使用业务流程的BizTalk Server解决方案的延迟

    • 消除仅消息传递模式的业务流程

    • 利用来自业务流程的内联发送

    • 最大程度地减少业务流程持久性点

  • 嵌套业务流程

  • 业务流程设计模式

  • 业务流程异常处理块

针对低延迟方案优化业务流程的建议

以下技术可用于降低使用业务流程BizTalk Server解决方案的延迟。

消除仅消息传送模式的业务流程

尽可能减少业务流程的使用,以增加整体吞吐量并减少业务流程的延迟。 如果不需要运行长时间运行的事务,并且无需为每个请求调用多个系统,请考虑消除业务流程并将业务逻辑移动到接收和发送端口,以减少与 BizTalkMsgBoxDb 的往返总数,并降低数据库访问导致的延迟。 在这种情况下,实现自定义管道并重用以前从业务流程调用的帮助程序类。 仅当严格需要将设计模式实现为“散点”和“聚集”或“Convoys”时才使用业务流程。 有关业务流程设计模式的详细信息,请参阅BizTalk Server文档中的主题在业务流程中实现设计模式 (https://go.microsoft.com/fwlink/?LinkId=140042) 。

使用来自业务流程的内联发送以适应低延迟方案

尽可能减少业务流程的使用,并优先使用仅消息传送模式,以增加整体吞吐量并减少业务流程的延迟。 如果不需要长时间运行的事务,并且不需要业务逻辑调用多个系统,请考虑移动业务逻辑来接收和发送端口,并消除业务流程的使用。 此方法可以使用自定义管道实现,并重复使用以前从业务流程调用的帮助程序类。 为了在低延迟方案中实现更好的性能,请采用以下方法之一:

  • 消除不必要的业务流程,并采用仅消息传递模式,以减少 BizTalk MessageBox 数据库的往返总数。 此方法适合低延迟,因为内联发送会绕过 BizTalk 消息引擎和关联的开销。 BizTalk Server 2006 及更高版本提供业务流程内联发送功能。

  • 在业务流程中,消除绑定到物理端口的逻辑端口,并在其位置使用内联发送。 例如,内联发送可用于创建 WCF 代理类的实例,以调用下游 Web 服务或 ADO.NET 组件来访问SQL Server数据库。 在下图中,当业务流程实例化业务组件时,将执行内联发送,该组件在内部使用 WCF 代理对象直接调用下游 Web 服务:

    BizTalk 业务流程内联发送 的描述

注意

尽管使用来自业务流程的内联发送将显著减少延迟,但此方法存在一些限制。 由于内联发送绕过 BizTalk 消息传送引擎,因此消息传送引擎提供的以下功能不可用:

  • 事务性管道
    • 可恢复管道
    • 调用 BAM 侦听器 API 的管道
    • BizTalk Server适配器支持
    • 批处理
    • 重试
    • 相关集初始化
    • 声明性配置
    • 辅助传输
    • 跟踪
    • BAM 的声明性使用

有关无法从业务流程中执行的管道类型的详细信息,请参阅 BizTalk Server 2010 文档中主题 How to Use Expressions to Execute Pipelines (https://go.microsoft.com/fwlink/?LinkId=158008) 的“限制”部分。

通过减少持久性点数(如果可能)优化业务流程延迟

如果想要使用补偿或作用域超时,只需将业务流程范围标记为“长时间运行的事务性”。 长时间运行的事务范围会导致作用域末尾出现额外的持久性点,因此,当你不需要使用补偿或作用域超时时,应避免这些点。 原子范围会导致范围末尾的持久性点,但也保证原子范围内不会出现任何持久性点。 作用域内没有持久性的这种副作用有时可用于批处理持久性点, (执行多个发送时,例如) 。 不过,一般情况下,我们建议尽可能避免使用原子范围。 业务流程引擎将正在运行的业务流程实例在不同点的整个状态保存到持久存储中,以便以后可以在内存中还原该实例并执行到完成。 业务流程中的持久性点数是影响流经业务流程的消息延迟的关键因素之一。 每次引擎命中持久性点时,正在运行的业务流程的内部状态都会序列化并保存到 MessageBox,此操作会产生延迟成本。 内部状态的序列化包括所有已实例化且尚未在业务流程中发布的消息和变量。 消息和变量越大,这些消息和变量的数量就越大,保持业务流程的内部状态所需的时间就越长。 过多的持久性点可能会导致性能大幅下降。 因此,建议通过减少事务范围和发送形状的数量,从业务流程中消除不必要的持久性点。 此方法可以减少由于业务流程解除冻结和解除冻结而导致的 MessageBox 上的争用,提高整体可伸缩性并降低业务流程延迟。 另一个建议是始终保持业务流程的内部状态尽可能小。 此方法可以显著减少 XLANG 引擎在持久性点的情况下序列化、持久化和还原业务流程的内部状态所花费的时间。 实现此目的的一种方法是尽可能晚地创建变量和消息,并尽早释放它们:例如,在业务流程中引入非事务性作用域,并在这些内部范围内声明变量和消息,而不是在最顶层声明它们。 有关最小化业务流程持久性点的详细信息,请参阅 BizTalk Server 2010 文档中的以下主题:

有关使用提升的属性访问业务流程中的消息标记或属性的准则

如果确实需要提升属性,请仅提升那些用于消息路由、筛选器和消息关联的属性。 每个属性的升级都需要反汇编程序组件 (XML、平面、自定义) 来识别文档类型,并使用 XPath 表达式从定义文档类型的 XSD 中包含的相对批注检索消息中的数据。 此外,当消息代理将消息发布到 MessageBox 数据库时,每个属性升级都会单独调用 bts_InsertProperty 存储过程。 如果业务流程需要访问 XML 文档包含的特定元素或属性,请使用以下方法之一:

  • 减少写入和提升的属性的数量,并消除那些不严格必要的属性。

  • 消除不必要的可分辨字段。 可分辨字段是写入的上下文属性,它们很容易占用大量空间,因为它们的名称等于用于检索数据的 XPath 表达式。 可分辨属性定义为 XSD 中定义文档类型的批注。 反汇编程序组件使用用于提升属性的相同方法,并使用 XPath 表达式,该表达式定义一个可分辨字段,以便在传入文档中查找该字段。 然后,反汇编程序组件在上下文中写入属性,其中:

    • 名称:批注中定义的 XPath 表达式。

    • :传入文档中由 XPath 表达式标识的元素的值。

      XPath 表达式可能很长,尤其是当有问题的元素在文档架构中非常深入时。 因此,区分字段越多,上下文大小就越大。 这反过来又会对整体性能产生负面影响。

  • 使用业务流程运行时提供的 XPath 内置函数。

  • 如果消息非常小 (几 KB) XML 格式,则可以将消息反序列化为 .NET 类实例,并使用公共字段和属性。 如果消息需要复杂的细化 (自定义代码、业务规则引擎策略等 ) 则使用 .NET 类的实例公开的属性访问数据的速度要快得多。 业务流程调用的业务逻辑完成后,实体对象可以序列化回 BizTalk 消息。 可以使用以下工具之一从 XML 架构创建 .NET 类:XSD 工具 (.NET Framework 2.0) 或 SVCUTIL (.NET Framework 3.0) 。

  • 从业务流程启用帮助程序组件。 此技术比使用可分辨字段具有优势。 事实上,业务流程可能会从配置存储 (配置文件、SSO 配置存储、自定义数据库等读取 XPath 表达式,) 因此,当必须更改 XPath 表达式时,不必更改和重新部署架构,因为应该对提升的属性和可分辨字段执行该操作。 下面的代码示例提供了帮助程序组件的示例。 组件使用 BizTalk 运行时提供的 XPathReader 类。 这样,代码就可以通读文档流,直到找到 XPath 表达式。

#region Copyright
//===
//Microsoft Windows Server AppFabric Customer Advisory Team (CAT)
//
// This sample is supplemental to the technical guidance published on the community
// blog.
//
// Author: Paolo Salvatori.
//===
// Copyright © 2010 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT.
//===
#endregion
#region Using Directives
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Linq;
using System.Text;
using System.Globalization;
using Microsoft.XLANGs.BaseTypes;
using Microsoft.BizTalk.Streaming;
using Microsoft.BizTalk.XPath;
#endregion
namespace Microsoft.AppFabric.CAT.Samples.DuplexMEP.Helpers
{
public class XPathHelper
{
#region Private Constants
private const string MessageCannotBeNull = "[XPathReader] The message cannot be null.";
#endregion
#region Public Static Methods
public static string GetValue(XLANGMessage message, int partIndex, string xpath)
{
try
{
if (message == null)
{
throw new ApplicationException(MessageCannotBeNull);
}
using (Stream stream = message[partIndex].RetrieveAs(typeof(Stream)) as Stream)
{
XmlTextReader xmlTextReader = new XmlTextReader(stream);
XPathCollection xPathCollection = new XPathCollection();
XPathReader xPathReader = new XPathReader(xmlTextReader, xPathCollection);
xPathCollection.Add(xpath);
while (xPathReader.Read())
{
if (xPathReader.HasAttributes)
{
for (int i = 0; i < xPathReader.AttributeCount; i++)
{
xPathReader.MoveToAttribute(i);
if (xPathReader.Match(xPathCollection[0]))
{
return xPathReader.GetAttribute(i);
}
}
}
if (xPathReader.Match(xPathCollection[0]))
{
return xPathReader.ReadString();
}
}
}
}
finally
{
message.Dispose();
}
return string.Empty;
}
#endregion
}
}

最大程度地降低业务流程复杂性以提高性能

业务流程的复杂性对性能有重大影响。 随着业务流程复杂性的增加,整体性能会降低。 业务流程可用于几乎无限类型的方案,每个方案都可能涉及不同复杂性的业务流程。 尽可能避免复杂的业务流程,转而采用模块化方法。 换句话说,将业务逻辑拆分为多个可重用的业务流程。

如果确实需要实现复杂的业务流程,请尽可能将消息和变量定义为内部范围,而不是在根级别定义。 此方法为每个业务流程保持较小的内存占用空间,因为当流离开定义变量和消息的范围时,会释放变量和消息。 在持久性点将业务流程保存到 MessageBox 时,此方法特别有用。

使用“调用业务流程”形状与“启动业务流程”形状来提高性能

避免 使用“启动业务流程” 形状,并使用 “调用业务流程” 形状执行嵌套业务流程。 事实上, “调用业务流程” 形状可用于同步调用在另一个项目中引用的业务流程。 此方法允许跨 BizTalk 项目重复使用常见的业务流程工作流模式。 使用调用业务流程形状同步调用另一个嵌套 业务流程 时,封闭业务流程会等待嵌套业务流程完成,然后再继续。 嵌套业务流程在运行调用业务流程的同一线程上执行。

启动业务流程” 形状类似于 “调用业务流程 ”形状,但在本例中,嵌套业务流程以异步方式调用:调用业务流程中的控制流在调用之后继续,无需等待调用的业务流程完成其工作。 为了在调用方和被调用的业务流程之间实现这种分离,启动 业务流程 是通过将消息发布到 BizTalk 消息框来实现的。 然后,此消息由执行嵌套业务流程的进程内 BizTalk 主机实例使用。 如果可能,请使用 调用业务流程,尤其是在调用业务流程需要等待嵌套业务流程的结果才能继续处理时。 有关使用“调用业务流程”形状的详细信息,请参阅 BizTalk Server 2010 文档中的以下主题:

将 XmlReader 与 XLANGMessage 配合使用,而不是将 XmlReader 与 XmlDocument 配合使用以提高业务流程性能

若要提高从业务流程调用的 .NET 方法的业务流程性能,请将 XmlReader 与 XLANGMessage 配合使用,而不是 XmlDocument。 下面的代码示例演示了此功能。

// As a general rule, use XmlReader with XLANGMessage, not XmlDocument.
// This is illustrated in the parameter passed into the following code.
// The XLANG/s compiler doesn't allow a return value of XmlReader
// so documents must be initially constructed as XmlDocument()
public static XmlDocument FromMsg(XLANGMessage old)
{
    //get at the data
    XmlDocument ret = new XmlDocument();

    try{
        XmlReader reader = (XmlReader)old[0].RetrieveAs(typeof(XmlReader));
        //construct new message from old
        //read property
        object msgid = old.GetPropertyValue(typeof(BTS.MessageID));
    }
    finally {
        // Call Dispose on the XLANGMessage object
        // because the message doesn't belong to the
        // .NET runtime - it belongs to the Messagebox database
        old.Dispose();
    }
    return ret;
}

另一种方法是基于架构创建 .NET 类。 这比将文档加载到 XmlDocument 对象中占用的内存更少,并且为 .NET 开发人员提供了对架构元素的轻松访问。 若要基于 BizTalk 架构生成类,可以使用 Visual Studio 随附的 xsd.exe 工具。 例如,对包含名为 ItemA、ItemB、ItemC 的字段的简单架构运行 xsd.exe <schema.xsd> /classes 将生成以下类。

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.1433
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.Xml.Serialization;

//
// This source code was auto-generated by xsd, Version=2.0.50727.42.
//

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://Schemas.MySchema")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://Schemas.MySchema", IsNullable=false)]
public partial class MySchemaRoot {

    private string itemAField;

    private string itemBField;

    private string itemCField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string ItemA {
        get {
            return this.itemAField;
        }
        set {
            this.itemAField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string ItemB {
        get {
            return this.itemBField;
        }
        set {
            this.itemBField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string ItemC {
        get {
            return this.itemCField;
        }
        set {
            this.itemCField = value;
        }
    }
}

然后,可以在 .NET 程序集中引用此类以访问消息元素,并且可以将返回的对象直接分配给消息。 下面是上面生成的 类的示例用法。

public static Root SetValues(Microsoft.XLANGs.BaseTypes.XLANGMessage msg)
{
   try
   {
   MySchemaRoot rootObj=(MySchemaRoot)msg[0].RetrieveAs(typeof(MySchemaRoot);
   rootObj.ItemA="value a";
   rootObj.ItemB="value b";
   rootObj.ItemC="value c";
   }
    finally {
        msg.Dispose();
            }

   return rootObj;
}

此方法允许在处理消息时使用面向对象的方法。 此方法应主要用于相对较小的消息。 这是因为,即使此技术使用的内存比将消息加载到 XmlDocument 对象时要少得多,整个消息仍会加载到内存中。 处理较大的消息时,使用 XmlReader 类读取消息,使用 XmlWriter 类写入消息。 使用 XmlReaderXmlWriter 时,消息包含在 VirtualStream 对象中。 如果消息大小超出 BizTalk 组属性配置页上公开) 大消息阈值 (字节 数指定的值,则会将消息写入文件系统。 这会降低整体性能,但会避免内存不足异常。

通过尽量减少使用绑定到物理端口的逻辑端口来提高性能

可以通过尽量减少绑定到使用以下适配器的物理端口的逻辑端口的使用来提高性能:

  • SQL Server、Oracle

  • WSE、HTTP、WCF

  • MSMQ、MQSeries

    在 BizTalk Server 2010 中,可以使用 Microsoft.XLANGs.Pipeline.dll 中包含的 XLANGPipelineManager 类直接从业务流程调用发送和接收管道。 因此,管道的处理可以从端口移动到业务流程;业务流程中的逻辑端口可以替换为表达式形状,该形状调用给定 .NET 类的实例 (例如使用 ADO.NET) 的数据访问组件。 在采用此技术之前,应注意,如果不使用适配器和物理端口,将无法利用其功能,例如批处理、重试、声明性配置和辅助传输。

业务流程设计模式

业务流程Designer允许开发人员实现各种企业集成模式。 一些常见模式包括聚合器、异常处理和补偿、消息代理、散点和收集以及顺序和并行护送。 这些模式可用于开发复杂的企业应用程序集成, (EAI) 、Service-Oriented 体系结构 (SOA) 和业务流程管理 (BPM) 解决方案与 BizTalk Server。 有关业务流程设计模式的详细信息,请参阅BizTalk Server文档中的主题在业务流程中实现设计模式 (https://go.microsoft.com/fwlink/?LinkId=140042) 以及企业集成 (https://go.microsoft.com/fwlink/?LinkId=140043) 模式和最佳做法。

在业务流程中适当使用 .NET 类以最大程度地提高性能

通常,业务流程中使用的 .NET 类可以分为两个不同的类别:

  • 帮助程序和服务 - 这些类为业务流程提供常见服务,例如跟踪、错误处理、缓存和序列化/反序列化。 这些类中的大多数都可以实现为没有内部状态和多个公共静态方法的静态类。 此方法可避免在同一时间运行的不同业务流程中创建同一类的多个对象,这有助于减少主机进程的工作空间并节省内存。 无状态类有助于减少内部状态的总体大小,当业务流程解除冻结时,必须序列化并保存到 BizTalk MessageBox 中。

  • 实体和业务对象 - 可以使用这些类来管理实体,例如订单、订单项和客户。 单个业务流程可以在内部创建和管理同一类型的多个实例。 这些类通常是有状态的,公开公共字段和/或属性以及修改对象内部状态的方法。 通过使用 XmlSerializerDataContractSerializer 类或使用 XLANGPart.RetrieveAs 方法将 XLANGMessage 部件反序列化为 .NET 对象,可以动态创建这些类的实例。 应使用非事务性作用域构建业务流程,以便尽可能晚地创建有状态类的实例,并在不再需要时立即释放这些实例。 此方法可减少主机进程的工作空间,并最大程度地减小业务流程解除冻结时序列化并保存到 MessageBox 数据库的内部状态的总体大小。 有关在 BizTalk Server 中使用业务流程的详细信息,请参阅BizTalk Server业务流程 (https://go.microsoft.com/fwlink/?LinkID=116886) 常见问题解答一文。

    注意

    虽然本文针对 2004 BizTalk Server 2004 和 2006 BizTalk Server编写,但介绍的概念也适用于BizTalk Server 2010 业务流程。

业务流程异常处理程序块

使用业务流程异常处理程序块时,请尽可能将一个或多个作用域中的所有业务流程形状 (非事务性范围) 并至少创建以下异常处理程序块:

在业务流程中使用映射时的注意事项

在业务流程中使用映射时,以下注意事项适用:

  • 如果使用映射来提取或设置业务流程中与业务逻辑一起使用的属性,请使用可分辨字段或提升的属性。 应遵循这种做法,因为在使用映射提取或设置值时,文档会加载到内存中,但在使用可分辨字段或提升的属性时,业务流程引擎会访问消息上下文,并且不会将文档加载到内存中。

  • 如果正在使用映射将多个字段聚合为一个字段,请将可分辨字段或升级属性与业务流程变量结合使用,以累计结果集。

另请参阅

优化性能