次の方法で共有

Durable Functions (Azure Functions) 中的数据保留和序列化

Durable Functions 运行时会自动将函数参数、返回值和其他状态保留到任务中心,以便提供可靠的执行。 但是,保留到持久存储的数据量和频率可能会影响应用程序性能和存储事务成本。 可能还需要考虑数据保留和隐私策略,具体取决于应用程序存储的数据的类型。

任务中心内容

任务集线器存储实例的当前状态以及所有待处理的消息。

  • 实例状态存储实例的当前状态和历史记录。 对于业务流程实例,此状态包括运行时状态、业务流程历史记录、输入、输出和自定义状态。 对于实体实例,它包括实体状态。
  • 消息存储函数输入或输出、事件负载以及出于内部目的(如路由和端到端关联)使用的元数据。

处理后会删除消息,但实例状态会保留,除非应用程序或操作员将其显式删除。 具体而言,即使编排完成,编排历史记录仍会保留在存储中。

有关状态和消息如何表示业务流程进度的示例,请参阅任务中心执行示例

存储中表示状态和消息的位置和方式取决于存储提供程序。 Durable Functions 的默认提供程序是 Azure 存储,它将数据持久化到队列、表和 blob,并存储在您指定的 Azure 存储帐户中。

序列化并保留的数据的类型

下表显示的是使用 Durable Functions 的功能时将序列化并保存的不同类型的数据:

  • 协调器、活动函数和实体函数的所有输入和输出,包括任何 ID 和未处理的异常
  • 编排器、活动和实体函数的名称
  • 外部事件名称和有效负载
  • 自定义编排状态有效负载
  • 业务流程终止消息
  • 持久计时器负载
  • 耐用的 HTTP 请求和响应 URL、头信息和有效负载
  • 实体呼叫和信号负载
  • 实体状态信息载荷

使输入和输出保持较小

如果向 Durable Functions API 提供大型输入和输出,则可能会遇到内存问题。 输入和输出被序列化到编排历史中,这意味着大型有效负载可能会随着时间的推移显著促进无限制的历史增长。 此增长风险会导致 重播期间出现内存异常。

若要缓解大型输入和输出的影响,可以:

  • 将工作委托给子业务流程协调程序,以跨多个业务流程协调程序对历史记录内存负担进行负载均衡,使单个历史记录的内存占用量保持较小。
  • 将大型数据存储在外部存储(如Azure Blob Storage)中,并传递轻量标识符,以便在需要时在活动函数内检索该数据。

小窍门

处理大数据的最佳做法是将其保留在外部存储中,并在需要时仅在活动内具体化该数据。

处理敏感数据

输入和输出(包括异常)被持久地保存在您选择的 Durable Functions 存储服务提供商中。 如果这些输入、输出或异常包含敏感数据(例如机密、连接字符串或个人身份信息),则对存储提供程序的资源具有读取访问权限的任何人都可以获取它们。

若要安全地处理敏感数据,请从Azure Key Vault或环境变量中提取活动函数中的数据,并且永远不会将数据直接与业务流程协调程序或实体通信。 此方法有助于防止敏感数据泄漏到存储资源中。

小窍门

本指南也适用于 CallHttp 业务流程协调程序 API,该 API 在存储中保留其请求和响应有效负载。 如果目标 HTTP 终结点需要身份验证,请在活动内实现 HTTP 调用,或使用 CallHttp 提供的内置托管标识支持,该支持不会将凭据保存到存储中。

注意

为了防止拥有日志读取访问权限的人员(例如,在 Application Insights 中的人员)获取这些机密,避免记录包含机密的数据。

使用 Azure 存储提供程序时,会自动静态加密所有数据。 但是,有权访问存储帐户的任何人都可以读取采用未加密格式的数据。 如果需要对敏感数据提供更强的保护,请考虑首先使用你自己的加密密钥对数据进行加密,从而以预加密的形式保存数据。

另外,.NET 用户也可以选择实现提供自动加密的自定义序列化提供程序。 可以在此 GitHub 示例中找到一个包含加密功能的自定义序列化的示例。

注意

如果决定实施应用程序级别的加密,请注意,业务流程和实体可以存在无限长的时间。 这一点在需要轮换加密密钥时很重要,因为业务流程或实体运行的时间可能比密钥轮换策略要长。 如果发生密钥轮换,则下一次执行业务流程或实体时,用于加密数据的密钥也许不再可用于对数据进行解密。 因此,仅当业务流程和实体需在相对较短的时段内运行时,才建议使用用户加密。

自定义序列化和反序列化

默认序列化逻辑

适用于 .NET(进程内)的 Durable Functions 在内部使用 Json.NET,以便将业务流程和实体数据序列化为 JSON。 使用的默认 Json.NET 设置是:

输入、输出和状态:

JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.None,
    DateParseHandling = DateParseHandling.None,
}

异常:

JsonSerializerSettings
{
    ContractResolver = new ExceptionResolver(),
    TypeNameHandling = TypeNameHandling.Objects,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
}

JsonSerializerSettings阅读有关 的详细文档。

使用 .NET 特性自定义序列化

在序列化的过程中,Json.NET 在用于控制如何从 JSON 序列化和反序列化数据的类和属性上查找各种属性。 如果你拥有传递到 Durable Functions API 的数据类型的源代码,请考虑将这些特性添加到类型以自定义序列化和反序列化。

使用依赖项注入自定义序列化

面向 .NET 并在 Functions V3 运行时上运行的函数应用可以使用依赖项注入 (DI) 来自定义数据和异常的序列化方式。 下面的示例代码演示了如何借助 DI 使用 IMessageSerializerSettingsFactoryIErrorSerializerSettingsFactory 服务接口的自定义实现来重写默认 Json.NET 序列化设置。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Collections.Generic;

[assembly: FunctionsStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddSingleton<IMessageSerializerSettingsFactory, CustomMessageSerializerSettingsFactory>();
            builder.Services.AddSingleton<IErrorSerializerSettingsFactory, CustomErrorSerializerSettingsFactory>();
        }

        /// <summary>
        /// A factory that provides the serialization for all inputs and outputs for activities and
        /// orchestrations, as well as entity state.
        /// </summary>
        internal class CustomMessageSerializerSettingsFactory : IMessageSerializerSettingsFactory
        {
            public JsonSerializerSettings CreateJsonSerializerSettings()
            {
                // Return your custom JsonSerializerSettings here
            }
        }

        /// <summary>
        /// A factory that provides the serialization for all exceptions thrown by activities
        /// and orchestrations
        /// </summary>
        internal class CustomErrorSerializerSettingsFactory : IErrorSerializerSettingsFactory
        {
            public JsonSerializerSettings CreateJsonSerializerSettings()
            {
                // Return your custom JsonSerializerSettings here
            }
        }
    }
}