优化业务流程性能

本主题介绍在 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 文档中“ 如何使用表达式执行管道https://go.microsoft.com/fwlink/?LinkId=158008主题的“限制”部分。

通过尽可能减少持久化点来优化协调延迟

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

使用已提升的属性从编排中访问消息标签或属性的准则

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

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

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

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

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

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

  • 使用编排运行时提供的 XPath 内置的函数。

  • 如果消息非常小(几千字节)和 XML 格式,则可以将消息反序列化为 .NET 类实例,并使用公共字段和属性。 如果消息需要复杂的细化(如自定义代码、业务规则引擎策略等),那么使用通过 .NET 类实例公开的属性来访问数据时,采用 XPath 表达式会大大加快速度。 业务流程协调调用的业务逻辑完成后,可以将实体对象序列化为 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 Messagebox 来实现的。 然后,此消息由进程内 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> /classe 将生成以下类。

//------------------------------------------------------------------------------
// <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 的数据访问组件)。 在采用此方法之前,应注意,如果不使用适配器和物理端口,则无法利用其功能,例如批处理、重试、声明性配置和辅助传输。

编排设计模式

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

    注释

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

业务流程异常处理程序块

使用编排异常处理程序块时,请将所有编排形状包括在一个或多个范围内(尽可能使用非事务性范围),并至少创建以下异常处理程序块:

在编排中使用映射时的注意事项

在编排中使用映射时,需要考虑以下事项:

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

  • 如果使用映射将多个字段聚合到一个字段中,请使用区分字段或具有编排变量的提升属性来累积结果集。

另请参阅

优化性能