使用规则引擎时的性能注意事项

本主题介绍规则引擎在各种情况下以及使用不同的配置/优化参数值时的性能表现。

事实类型

规则引擎访问 .NET 事实所用的时间比访问 XML 事实和数据库事实所用的时间要少。 如果面临在策略中使用 .NET 事实、XML 事实还是数据库事实的情况,应该考虑到,使用 .NET 事实会获得更好的性能。

数据表与数据连接绑定

当数据集的大小较小 (小于大约 10 行) 时, TypedDataTable 绑定的性能优于 DataConnection 绑定。 当数据集较大 (大于或等于大约 10 行) 时, DataConnection 绑定的性能优于 TypedDataTable 绑定。 因此,应根据数据集的估计大小来决定是使用 DataConnection 绑定还是 TypedDataTable 绑定。

事实检索器

可以编写事实检索器 - 一个实现标准方法的对象,通常使用它们在执行策略之前向规则引擎提供长期且缓慢更改的事实。 引擎将缓存这些事实,并在多个执行循环中使用它们。 您应该创建一个事实检索器,它只在第一次调用规则引擎时提交事实,然后在需要时才在内存中更新该事实,而不是每次调用规则引擎时都提交一个静态事实或相当静态的事实。

规则优先级

规则的优先级设置范围可以是 0 的任一端,较大的数字具有较高的优先级。 操作按照从最高优先级到最低优先级的顺序执行。 当策略使用 断言/更新 调用实现前向链接行为时,可以使用优先级设置优化链接。 例如,假设 Rule2 依赖于 Rule1 设置的值。 赋予 Rule1 更高的优先级意味着 Rule2 仅在 Rule1 触发并更新值后才会执行。 相反,如果 为 Rule2 提供更高的优先级,它可以触发一次,然后在 Rule1 触发后再次触发,并更新 Rule2 在条件中使用的事实。 这样可能会也可能不会生成正确的结果,但显然触发两次比只触发一次对性能的影响更大。

更新调用

Update 函数更新存在于规则引擎的工作内存中的事实,并导致重新计算在条件中使用更新事实的所有规则。 更新 函数调用的成本可能很高,尤其是在由于更新事实而需要重新评估许多规则时。 在有些情况下,可以避免重新计算规则。 例如,请考虑以下规则:

规则 1:

IF PurchaseOrder.Amount > 5   
THEN StatusObj.Flag = true; Update(StatusObj)  

规则 2:

IF PurchaseOrder.Amount <= 5   
THEN StatusObj.Flag = false; Update(StatusObj)  

策略的所有剩余规则在其条件下都使用 StatusObj.Flag 。 因此,当对 StatusObj 对象调用 Update 时,将重新评估所有规则。 无论 Amount 字段的值是什么,除 Rule1 和 Rule2 之外的所有规则都会评估两次,一次是在更新调用之前,一次是在更新调用之后。

相反,可以在调用策略之前将 标志 字段的值设置为 false ,然后在策略中仅使用 Rule1 来设置标志。 在这种情况下,仅当 Amount 字段的值大于 5 时,才会调用 Update;如果金额小于或等于 5,则不调用 Update。 因此,仅当“金额”字段的值大于 5 时,才计算除 Rule1Rule2 之外的所有规则两次。

使用“逻辑或”运算符

规则引擎针对执行逻辑 AND 运算符进行了优化,它以分离法线形式重新构造它分析的规则,以便 OR 运算符仅在顶层使用。 在条件中使用越来越多的逻辑 OR 运算符会产生额外的排列,从而扩展规则引擎的分析网络,并且规则引擎可能需要很长时间才能规范化规则。 以下列表包含此问题的可能解决方法。

  • 将规则修改为非常规形式,使 OR 运算符仅位于顶层。 请注意,在业务规则编辑器中以非常规形式开发规则可能比较棘手。 可以考虑以编程方式创建规则。

  • 开发一个帮助程序组件,该组件执行 OR 操作并返回布尔值,并在规则中使用 组件。

  • 请考虑将规则拆分为多个规则,并让规则检查之前执行的规则设置的标志,或使用以前执行的规则断言的对象,如以下示例所示:

    • 规则 1:如果 (a == 1 或 a == 3) THEN b = true

      规则 2:如果 (b == true) THEN ...

    • 规则 1:如果 (== 1 或 a == 3) THEN 断言 (new c () )

      规则 2:如果 (c.flag == true) THEN ...

缓存设置

规则引擎使用两个缓存。 第一个缓存在更新服务中,第二个缓存在每个 BizTalk 进程中。 初次使用某个策略时,BizTalk 进程从更新服务请求策略信息。 更新服务从规则引擎数据库检索策略信息,对其进行缓存,然后将信息返回 BizTalk 进程。 BizTalk 进程基于该信息创建策略对象,并在关联的规则引擎实例完成策略执行后,将策略对象存储在缓存中。 再次调用同一个策略时,BizTalk 进程重用缓存中的策略对象(如果缓存中有的话)。

同样,如果 BizTalk 进程从更新服务请求有关策略的信息,更新服务会首先在其缓存中查找策略信息。 更新服务还会每隔 60 秒(一分钟)进行检查,查看是否对数据库中的策略有任何更新。 如果有任何更新,更新服务将检索该信息,将更新的信息进行缓存。

规则引擎有三个与这些缓存相关的优化参数: CacheEntriesCacheTimeoutPollingInterval。 您可以在注册表或配置文件中为这些参数指定值。

CacheEntries 的值是缓存中的最大条目数。 CacheEntries 的默认值为 32。 在某些情况下,可能需要增加 CacheEntries 参数的值以提高性能。 例如,假设您要重复地使用 40 个策略。 在这种情况下,可能需要将 CacheEntries 的值增加到 40 以提高性能。 这样做可以使更新服务在内存中能缓存多达 40 个策略的详细信息。 还可以使 BizTalk 服务在内存中能缓存多达 40 个策略实例。 在 BizTalk 服务的缓存中可能有策略的多个实例。

CacheTimeout 的值是条目从更新服务缓存中过期) (的时间(以秒为单位)。 换句话说, CacheTimeout 值是指策略的缓存条目在缓存中保留多长时间(如果没有对策略的引用)。 CacheTimeout 的默认值为 3600 秒 (一小时) 。 这意味着,如果缓存条目没有在一小时之内被引用,就会被删除。 在某些情况下,可能需要增加 CacheTimeout 值以提高性能。 例如,假设策略每隔两小时调用一次。 可以通过将 CacheTimeout 参数的值增加到大于两小时的值来提高策略执行的性能。

规则引擎的 PollingInterval 参数定义更新服务检查规则引擎数据库是否有更新的时间间隔(以秒为单位)。 PollingInterval 参数的默认值为 60 秒 (一分钟) 。 如果您知道策略根本不更新或者很少更新,可以增加此值以提高性能。

SideEffects 属性

ClassMemberBindingDatabaseColumnBindingXmlDocumentFieldBinding 类具有名为 SideEffects 的属性。 此属性确定是否缓存绑定字段的值、成员或列。 DatabaseColumnBindingXmlDocumentFieldBinding 类中的 SideEffects 属性的默认值为 falseClassMemberBinding 类中 SideEffects 属性的默认值为 true。 因此,如果 XML 文档字段或数据库表的列是在策略中第二次访问或稍后访问的,则其值从缓存中检索。 不过,如果 .NET 对象的成员是第二次访问或稍后访问的,其值从 .NET 对象检索,而不是从缓存中检索。 将 .NET ClassMemberBindingSideEffects 属性设置为 false 将提高性能,因为从第二次开始从缓存中检索字段的值。 您只能通过编程方式来完成此步骤。 业务规则编辑器工具不公开 SideEffects 属性。

实例和选择性

XmlDocumentBindingClassBindingDatabaseBinding 类有两个属性:InstancesSelectivityInstances 的值是工作内存中类的预期实例数。 Selectivity 的值是成功通过规则条件的类实例的百分比。 规则引擎使用这些值来优化条件计算,这样在条件计算中最初尽可能使用最少的实例,以后再使用其余的实例。 如果事先了解对象的实例数,将 Instances 属性设置为该值可以提高性能。 同样,如果事先了解传递条件的这些对象的百分比,将 Selectivity 属性设置为该值可以提高性能。 只能通过编程方式来设置这些参数的值。 业务规则编辑器工具不公开这些属性。