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

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

任务中心内容

任务中心存储实例的当前状态和任何挂起的消息:

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

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

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

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

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

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

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

处理敏感数据

使用 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
            }
        }
    }
}