Azure Functions 的存储注意事项

创建函数应用实例时,Azure Functions 需要 Azure 存储帐户。 函数应用可以使用以下存储服务:

存储服务 函数用法
Azure Blob 存储 维护绑定状态和函数密钥1
Flex Consumption 计划中运行的应用程序的部署源。
默认用于 Durable Functions 中的任务中心
可用于存储Linux 消耗计划远程生成外部包 URL 部署中所用的函数应用代码。
Azure 文件存储2 文件共享,用于存储和运行消耗计划高级计划中的函数应用代码。
Azure 队列存储 默认用于 Durable Functions 中的任务中心。 用于特定 Azure Functions 触发器中的故障和重试处理。 用于 Blob 存储触发器的对象跟踪。
Azure 表存储 默认用于 Durable Functions 中的任务中心
  1. Blob 存储是功能密钥的默认存储,但你可以配置备用存储
  2. 默认已设置 Azure 文件存储,但在某些情况下,你可以创建不使用 Azure 文件存储的应用

重要注意事项

有关函数应用使用的存储帐户,必须充分考虑以下事实:

  • 当函数应用托管在消耗计划或高级计划上时,函数代码和配置文件将存储在链接存储帐户 Azure 文件存储中。 删除主存储帐户时,此内容将随之删除且无法恢复。 有关详细信息,请参阅存储帐户被删除

  • 重要数据(如函数代码、访问密钥和其他与服务相关的重要数据)可以保留在存储帐户中。 必须通过以下方式仔细管理对函数应用使用的存储帐户的访问:

    • 根据最低特权模型审核和限制应用和用户对存储帐户的访问。 存储帐户权限可以是分配的角色中执行数据操作的权限,也可以是执行 listKeys 操作的权限。

    • 监视存储帐户中的控制平面活动 (例如检索密钥) 和数据平面操作 (如写入 blob)。 请考虑在 Azure 存储以外的位置维护存储日志。 有关详细信息,请参阅存储日志

存储帐户要求

在 Azure 门户的函数应用创建流中创建的存储帐户确定可以使用新函数应用。 选择使用现有存储帐户时,提供的列表不包括某些不受支持的存储帐户。 以下限制适用于函数应用使用的存储帐户,因此必须确保现有存储帐户满足以下要求:

  • 帐户类型必须支持 Blob、队列和表存储。 某些存储帐户不支持队列和表。 这些帐户包括仅 Blob 存储帐户和 Azure 高级存储。 若要了解存储帐户类型的详细信息,请参阅存储帐户概述

  • 当函数应用托管在消耗计划中时,无法使用网络安全存储帐户。

  • 在门户中创建函数应用时,只能选择与要创建的函数应用位于同一区域的现有存储帐户。 这是性能优化,而不是严格的限制。 若要了解详细信息,请参阅存储帐户位置

  • 在启用了可用性区域支持的计划中创建函数应用时,仅支持区域冗余存储帐户

使用部署自动化通过网络安全存储帐户创建函数应用时,必须在 ARM 模板或 Bicep 文件中包括特定的网络配置。 如果不包含这些设置和资源,自动部署可能会通不过验证。 有关更具体的 ARM 和 Bicep 指南,请参阅安全部署。 有关使用网络配置存储帐户的概述,请参阅如何将安全存储帐户用于 Azure Functions

存储帐户指导

每个 Function App 都需要存储帐户才能运行。 如果该帐户已删除,则你的函数应用将不会运行。 若要对存储相关问题进行故障排除,请参阅如何对存储相关问题进行故障排除。 以下其他注意事项适用于函数应用使用的存储帐户。

存储帐户位置

为了获得最佳性能,函数应用应使用同一区域中的存储帐户,从而减少延迟。 Azure 门户强制实施此最佳做法。 如果出于某种原因,需要使用不同于函数应用所在区域的区域中的存储帐户,则必须在门户外创建函数应用。

存储帐户必须可供函数应用访问。 如果需要使用受保护的存储帐户,请考虑将存储帐户限制在虚拟网络中

存储帐户连接设置

默认情况下,函数应用会将 AzureWebJobsStorage 连接配置为存储在 AzureWebJobsStorage 应用程序设置中的连接字符串,但你也可以将 AzureWebJobsStorage 配置为使用基于标识的连接,而无需机密。

在消耗计划(仅限 Windows)或弹性高级计划(Windows 或 Linux)中运行的函数应用可以使用 Azure 文件存储以存储启用动态缩放所需的映像。 对于这些计划,在WEBSITE_CONTENTAZUREFILECONNECTIONSTRING设置中设置存储帐户的连接字符串,并在WEBSITE_CONTENTSHARE设置中设置文件共享的名称。 这通常是用于AzureWebJobsStorage的同一帐户。 还可以创建不使用 Azure 文件存储的函数应用,但缩放可能受到限制。

注意

重新生成存储密钥时,必须更新存储帐户连接字符串。 在此处阅读有关存储密钥管理的详细信息

共享存储帐户

多个函数应用可以共享同一个存储帐户,而不会出现任何问题。 例如,在 Visual Studio 中,可以使用 Azurite 存储模拟器开发多个应用。 在这种情况下,仿真器的作用类似于单个存储帐户。 函数应用使用的同一个存储帐户也可用于存储应用程序数据。 但是在生产环境中,这种方法并不总是个好主意。

可能需要使用单独的存储帐户以避免主机 ID 冲突

生命周期管理策略注意事项

不应将生命周期管理策略应用于函数应用使用的 Blob 存储帐户。 函数使用 Blob 存储来保存重要信息(如函数访问密钥),策略可能会删除 Functions 主机所需的 blob(例如密钥)。 如果必须使用策略,请排除 Functions 使用的容器,这些容器的前缀为 azure-webjobsscm

存储日志

由于函数代码和密钥可能保留在存储帐户中,因此针对存储帐户记录活动是监视未经授权的访问的好方法。 Azure Monitor 资源日志可用于跟踪针对存储数据平面的事件。 有关如何配置和检查这些日志的详细信息,请参阅监视 Azure 存储

Azure Monitor 活动日志显示控制平面事件,包括 listKeys 操作。 但是,还应为存储帐户配置资源日志,以跟踪密钥的后续使用或其他基于标识的数据平面操作。 至少启用 StorageWrite 日志类别,以便识别正常 Functions 操作之外的数据修改。

若要限制任何范围广泛的存储权限的潜在影响,请考虑对这些日志使用非存储目标,例如 Log Analytics。 有关详细信息,请参阅监视 Azure Blob 存储

优化存储性能

若要最大程度地提高性能,请对每个函数应用使用单独的存储帐户。 如果有 Durable Functions 或事件中心触发的函数,则请注意,这两种函数都会产生大量存储事务,这一点特别重要。 当应用程序逻辑与 Azure 存储交互时,无论是直接(使用存储 SDK)交互还是通过某个存储绑定进行交互,都应使用专用存储帐户。 例如,如果有事件中心触发的函数将一些数据写入 Blob 存储,请使用两个存储帐户,一个用于函数应用,另一个用于由函数存储的 Blob。

通过虚拟网络实现一致的路由

同一计划中托管的多个函数应用还可以对 Azure 文件内容共享(由 WEBSITE_CONTENTAZUREFILECONNECTIONSTRING 定义)使用同一个存储帐户。 当此存储帐户也受虚拟网络保护时,所有这些应用程序也应对 vnetContentShareEnabled(以前的 WEBSITE_CONTENTOVERVNET)使用相同的值,以保证系统通过目标虚拟网络以一致的方式路由流量。 如果使用相同 Azure 文件存储帐户的应用之间的此设置不匹配,则可能会导致系统通过公共网络路由流量,从而导致访问被存储帐户网络规则阻止。

使用 Blob

Functions 的一个关键方案是对 Blob 容器中的文件进行文件处理,例如图像处理或情绪分析。 要了解详细信息,请参阅处理文件上传

在 Blob 容器上触发

根据存储容器中 blob 的更改,可通过多种方法执行函数代码。 使用下表确定最适合你需求的函数触发器:

策略 容器(轮询) 容器(事件) 队列触发器 事件网格
延迟 高(最多 10 分钟) 中等
存储帐户限制 不支持仅限 Blob 的帐户¹ 不支持常规用途 v1 不支持常规用途 v1
触发器类型 Blob 存储 Blob 存储 队列存储 事件网格
扩展版本 任意 存储 v5.x+ 任意 任意
处理现有 Blob No
筛选器 Blob 名称模式 事件筛选器 不适用 事件筛选器
需要事件订阅 No
支持弹性消耗计划
支持大规模²
说明 默认触发器行为,即依赖于轮询容器获得更新。 有关详细信息,请查看 Blob 存储触发器参考中的示例。 使用事件订阅中的 Blob 存储事件。 需要 EventGridSource 参数值。 有关详细信息,请参阅教程:使用事件订阅在 Blob 容器上触发 Azure Functions 将 Blob 添加到容器时,会手动将 Blob 名称字符串添加到存储队列中。 此值由队列存储触发器直接传递到同一函数上的 Blob 存储输入绑定。 除了提供这些来自存储容器的事件之外,还提供了基于事件触发的灵活性。 需要同时让非存储事件触发函数时使用。 有关详细信息,请参阅如何在 Azure Functions 中使用事件网格触发器和绑定
  1. Blob 存储输入和输出绑定支持仅 Blob 帐户。
  2. 大规模可以宽松地定义为包含 100,000 个以上的 Blob 的容器,或者定义为每秒进行 100 个以上 Blob 更新的存储帐户。

存储数据加密

Azure 存储可对存储帐户中的所有数据进行静态加密。 有关详细信息,请参阅静态数据的 Azure 存储加密

默认情况下,数据使用 Microsoft 管理的密钥进行加密。 为了进一步控制加密密钥,可以提供客户管理的密钥,用于对 blob 和文件数据进行加密。 这些密钥必须存在于 Azure Key Vault 中,以便 Functions 能够访问存储帐户。 若要了解详细信息,请参阅使用客户管理的密钥进行静态加密

区域内数据驻留

当必须将所有客户数据保留在单个区域内时,与函数应用关联的存储帐户必须是具有区域内冗余的存储帐户。 区域内冗余存储帐户还必须与 Azure Durable Functions 一起使用。

主机 ID 注意事项

Functions 使用主机 ID 值作为唯一标识存储项目中特定函数应用的方法。 默认情况下,此 ID 是根据函数应用的名称自动生成的,截断到前 32 个字符。 然后会在链接存储帐户中存储每应用关联和跟踪信息时使用此 ID。 如果多个函数应用的名称超过 32 个字符,并且其前 32 个字符相同,则此截断可能会导致重复的主机 ID 值。 当两个具有相同主机 ID 的函数应用使用相同的存储帐户时,你会遇到主机 ID 冲突,因为存储的数据不能唯一链接到正确的函数应用。

注意

在生产槽中的函数应用和过渡槽中的相同函数应用之间也会发生这种类型的主机 ID 冲突(当两个槽使用相同的存储帐户时)。

从 Functions 运行时版本 3.x 开始,会检测主机 ID 冲突并记录警告。 在版本 4.x 中会记录一个错误并停止主机,从而导致硬故障。 有关主机 ID 冲突的更多详细信息,请参阅此问题

避免主机 ID 冲突

可以使用以下策略来避免主机 ID 冲突:

  • 对冲突涉及的每个函数应用或槽使用单独的存储帐户。
  • 将其中一个函数应用重命名为长度小于 32 个字符的值,这会更改该应用的计算主机 ID 并去除冲突。
  • 为一个或多个发生冲突的应用设置显式主机 ID。 若要了解详细信息,请参阅主机 ID 替代

重要

更改与现有函数应用关联的存储帐户或更改应用的主机 ID 可能会影响现有函数的行为。 例如,Blob 存储触发器通过在存储中的特定主机 ID 路径下写入回执来跟踪它是否处理了单个 Blob。 当主机 ID 发生更改或你指向新的存储帐户时,以前处理的 Blob 可能会被重新处理。

替代主机 ID

可以使用 AzureFunctionsWebHost__hostid 设置在应用程序设置中为函数应用显式设置特定主机 ID。 有关详细信息,请参阅 AzureFunctionsWebHost__hostid

当槽之间发生冲突时,必须为每个槽(包括生产槽)设置特定的主机 ID。 还必须将这些设置标记为部署设置,以免它们进行交换。 若要了解如何创建应用设置,请参阅使用应用程序设置

创建不使用 Azure 文件存储的应用

Azure 文件存储服务提供支持大规模方案的共享文件系统。 函数应用在 Windows 上以弹性高级计划或消耗计划运行时,默认情况下会在存储帐户中创建 Azure 文件存储共享。 Functions 使用该共享来启用某些功能,例如日志流式处理。 它还用作共享包部署位置,这可保证所部署的函数在所有实例中的一致性。

默认情况下,在高级计划和消耗计划中托管的函数应用使用 zip 部署,部署包存储在此 Azure 文件共享中。 本部分仅与这些托管计划相关。

使用 Azure 文件存储需要使用连接字符串,该字符串以 WEBSITE_CONTENTAZUREFILECONNECTIONSTRING 的形式存储在应用设置中。 Azure 文件存储当前不支持基于标识的连接。 如果你的方案要求你不将任何机密存储在应用设置中,则必须移除应用对 Azure 文件存储的依赖。 为此,可以创建应用而不使用默认的 Azure 文件存储依赖项。

注意

还应考虑在弹性消耗计划的函数应用中运行,该计划可以更好地控制部署包,包括使用托管标识连接的功能。 有关详细信息,请参阅 Flex Consumption 一文中的配置部署设置

要在没有 Azure 文件共享的情况下运行应用,必须满足以下要求:

你负责手动更新部署包和维护部署包 URL,其中可能包含共享访问签名 (SAS)。

  • 应用不能依赖于共享的可写入文件系统。
  • 应用不能使用 1.x 版的 Functions 运行时。
  • 客户端(例如 Azure 门户)中的日志流式处理体验默认使用文件系统日志。 你应该改为依赖 Application Insights 日志。

如果上述要求符合你的方案,可以继续在没有 Azure 文件存储的情况下创建函数应用。 为此,可以在没有 WEBSITE_CONTENTAZUREFILECONNECTIONSTRINGWEBSITE_CONTENTSHARE 应用设置的情况下创建应用。 若要开始,请为标准部署生成 ARM 模板,删除这两个设置,然后部署修改后的模板。

由于 Azure 文件存储用于为 Functions 启用动态横向扩展,因此在弹性高级计划和 Windows 上运行的消耗计划中,在没有 Azure 文件存储的情况下运行应用时,缩放会受到限制。

装载文件共享

目前仅当在 Linux 上运行时,此功能才可用。

可以将现有 Azure 文件共享装载到 Linux 函数应用。 通过将共享装载到 Linux 函数应用,可以在函数中使用现有的机器学习模型或其他数据。 可以使用以下命令将现有共享装载到 Linux 函数应用。

az webapp config storage-account add

在此命令中,share-name 是现有 Azure 文件共享的名称,custom-id 可以是在装载到函数应用时唯一定义共享的任何字符串。 此外,mount-path 是在函数应用中用于访问共享的路径。 mount-path 必须采用 /dir-name 格式,不能以 /home 开头。

有关完整示例,请参阅创建 Python 函数应用并装载 Azure 文件共享中的脚本。

目前仅支持 AzureFilesstorage-type。 只能将五个共享装载到给定函数应用。 装载文件共享可能会至少将冷启动时间增加 200-300 毫秒,当存储帐户处于不同区域时甚至会更多。

装载的共享可供处于指定 mount-path 的函数代码使用。 例如,当 mount-path/path/to/mount 时,可以通过文件系统 API 访问目标目录,如下面的 Python 示例所示:

import os
...

files_in_share = os.listdir("/path/to/mount")

后续步骤

详细了解 Azure Functions 托管选项。