适用于 Azure Functions 的 Azure Blob 存储触发器

检测到新的或更新的 Blob 时,Blob 存储触发器会启动某个函数。 Blob 内容以函数输入的形式提供。

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

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

¹Blob 存储输入和输出绑定支持仅 Blob 帐户。
²大规模可以宽松地定义为包含 100,000 个以上的 Blob 的容器,或者定义为每秒进行 100 个以上 Blob 更新的存储帐户。

若要了解设置和配置详细信息,请参阅概述

示例

可以使用以下 C# 模式之一创建 C# 函数:

  • 进程内类库:编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。
  • 独立进程类库:编译的 C# 函数,该函数在独立于运行时的进程中运行。 支持在 .NET 5.0 上运行的 C# 函数需要独立的进程。
  • C# 脚本:主要在 Azure 门户中创建 C# 函数时使用。

以下示例演示在 samples-workitems 容器中添加或更新 blob 时写入日志的 C# 函数

[FunctionName("BlobTriggerCSharp")]        
public static void Run([BlobTrigger("samples-workitems/{name}")] Stream myBlob, string name, ILogger log)
{
    log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
}

blob 触发器路径 samples-workitems/{name} 中的字符串 {name} 会创建一个绑定表达式,可以在函数代码中使用它来访问触发 blob 的文件名。 有关详细信息,请参阅本文下文中的 Blob 名称模式

有关 BlobTrigger 特性的详细信息,请参阅特性

myblob 容器中添加或更新 Blob 时,该函数会写入一条日志。

@FunctionName("blobprocessor")
public void run(
  @BlobTrigger(name = "file",
               dataType = "binary",
               path = "myblob/{name}",
               connection = "MyStorageAccountAppSetting") byte[] content,
  @BindingName("name") String filename,
  final ExecutionContext context
) {
  context.getLogger().info("Name: " + filename + " Size: " + content.length + " bytes");
}

以下示例显示了 function.json 文件中的一个 Blob 触发器绑定以及使用该绑定的 JavaScript 代码。 在 samples-workitems 容器中添加或更新 Blob 时,该函数会写入日志。

function.json 文件如下所示:

{
    "disabled": false,
    "bindings": [
        {
            "name": "myBlob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

blob 触发器路径 samples-workitems/{name} 中的字符串 {name} 会创建一个绑定表达式,可以在函数代码中使用它来访问触发 blob 的文件名。 有关详细信息,请参阅本文下文中的 Blob 名称模式

有关 function.json 文件属性的详细信息,请参阅解释了这些属性的配置部分。

JavaScript 代码如下所示:

module.exports = async function(context) {
    context.log('Node.js Blob trigger function processed', context.bindings.myBlob);
};

下面的示例演示如何创建在将文件添加到 source blob 存储容器时运行的函数。

函数配置文件 (function.json) 包含一个绑定,其 typeblobTriggerdirection 设置为 in

{
  "bindings": [
    {
      "name": "InputBlob",
      "type": "blobTrigger",
      "direction": "in",
      "path": "source/{name}",
      "connection": "MyStorageAccountConnectionString"
    }
  ]
}

下面是 run.ps1 文件的关联代码。

param([byte[]] $InputBlob, $TriggerMetadata)

Write-Host "PowerShell Blob trigger: Name: $($TriggerMetadata.Name) Size: $($InputBlob.Length) bytes"

以下示例显示了 function.json 文件中的一个 Blob 触发器绑定以及使用该绑定的 Python 代码。 在 samples-workitems容器中添加或更新 Blob 时,该函数会写入一条日志。

function.json 文件如下所示:

{
    "scriptFile": "__init__.py",
    "disabled": false,
    "bindings": [
        {
            "name": "myblob",
            "type": "blobTrigger",
            "direction": "in",
            "path": "samples-workitems/{name}",
            "connection":"MyStorageAccountAppSetting"
        }
    ]
}

blob 触发器路径 samples-workitems/{name} 中的字符串 {name} 会创建一个绑定表达式,可以在函数代码中使用它来访问触发 blob 的文件名。 有关详细信息,请参阅本文下文中的 Blob 名称模式

有关 function.json 文件属性的详细信息,请参阅解释了这些属性的配置部分。

下面是 Python 代码:

import logging
import azure.functions as func


def main(myblob: func.InputStream):
    logging.info('Python Blob trigger function processed %s', myblob.name)

特性

进程内独立进程 C# 库使用 BlobAttribute 特性来定义函数。 C# 脚本改为使用 function.json 配置文件。

该特性的构造函数采用以下参数:

参数 说明
BlobPath Blob 的路径。
Connection 指定如何连接到 Azure Blob 的应用设置或设置集合的名称。 请参阅连接
访问 表示是要读取还是写入。

C# 类库中,该特性的构造函数采用一个表示要监视的容器的路径字符串,并选择性地采用某种 Blob 名称模式。 下面是一个示例:

[FunctionName("ResizeImage")]
public static void Run(
  [BlobTrigger("sample-images/{name}")] Stream image,
  [Blob("sample-images-md/{name}", FileAccess.Write)] Stream imageSmall)
{
  ....
}

尽管该特性采用 Connection 属性,但你也可以使用 StorageAccountAttribute 来指定存储帐户连接。 如果需要使用一个不同于库中的其他函数的存储帐户,可以执行此操作。 构造函数采用包含存储连接字符串的应用设置的名称。 可以在参数、方法或类级别应用该特性。 以下示例演示类级别和方法级别:

[StorageAccount("ClassLevelStorageAppSetting")]
public static class AzureFunctions
{
    [FunctionName("StorageTrigger")]
    [StorageAccount("FunctionLevelStorageAppSetting")]
    public static void Run( //...
{
    ...
}

要使用的存储帐户按以下顺序确定:

  • 触发器或绑定特性的 Connection 属性。
  • 作为触发器或绑定特性应用到同一参数的 StorageAccount 特性。
  • 应用到函数的 StorageAccount 特性。
  • 应用到类的 StorageAccount 特性。
  • 函数应用的默认存储帐户,在 AzureWebJobsStorage 应用程序设置中定义。

在本地开发时,请将应用程序设置添加到 Values 集合的 local.settings.json 文件

批注

@BlobTrigger 特性用于授予对触发函数的 blob 的访问权限。 有关详细信息,请参阅触发器示例

配置

下表解释了在 function.json 文件中设置的绑定配置属性。

function.json 属性 说明
type 必须设置为 blobTrigger。 在 Azure 门户中创建触发器时,会自动设置此属性。
direction 必须设置为 in。 在 Azure 门户中创建触发器时,会自动设置此属性。 用法部分中已阐述异常。
name 表示函数代码中的 Blob 的变量的名称。
路径 要监视的容器。 可以是某种 Blob 名称模式
连接 指定如何连接到 Azure Blob 的应用设置或设置集合的名称。 请参阅连接

有关完整示例的信息,请参阅示例部分

Metadata

Blob 触发器提供了几个元数据属性。 这些属性可在其他绑定中用作绑定表达式的一部分,或者用作代码中的参数。 这些值具有与 CloudBlob 类型相同的语义。

属性 类型 说明
BlobTrigger string 触发 Blob 的路径。
Uri System.Uri 主位置的 blob 的 URI。
Properties BlobProperties Blob 的系统属性。
Metadata IDictionary<string,string> Blob 的用户定义元数据。

以下示例记录了触发 blob 的路径,包括容器:

public static void Run(string myBlob, string blobTrigger, ILogger log)
{
    log.LogInformation($"Full blob path: {blobTrigger}");
} 

Metadata

Blob 触发器提供了几个元数据属性。 这些属性可在其他绑定中用作绑定表达式的一部分,或者用作代码中的参数。

属性 说明
blobTrigger 触发 Blob 的路径。
uri 主位置的 blob 的 URI。
properties Blob 的系统属性。
metadata Blob 的用户定义元数据。

可以从提供的 context 对象的 bindingData 属性中获取元数据,如下面的示例所示,该属性记录触发 blob 的路径 (blobTrigger),包括容器:

module.exports = async function (context, myBlob) {
    context.log("Full blob path:", context.bindingData.blobTrigger);
};

Metadata

可以通过 $TriggerMetadata 参数获取元数据。

使用情况

Blob 触发器的用法取决于扩展包版本,以及函数应用中使用的 C# 形式,可以是以下形式之一:

进程内类库是编译的 C# 函数,该函数在与 Functions 运行时相同的进程中运行。

选择一个版本以查看模式和版本的使用情况详细信息。

所有版本都支持以下参数类型:

  • Stream
  • TextReader
  • string
  • Byte[]

以下参数类型特定于扩展版本,需要具有 C# 类库的 FileAccess.ReadWrite

有关使用这些类型的示例,请参阅扩展的 GitHub 存储库。 通过 Azure.Storage.Blobs 迁移指南详细了解这些新类型的不同之处,以及如何迁移到这些类型。

还可使用 StorageAccountAttribute 指定要使用的存储帐户。 如果需要使用一个不同于库中的其他函数的存储帐户,可以执行此操作。 构造函数采用包含存储连接字符串的应用设置的名称。 可以在参数、方法或类级别应用该特性。 以下示例演示类级别和方法级别:

[StorageAccount("ClassLevelStorageAppSetting")]
public static class AzureFunctions
{
    [FunctionName("BlobTrigger")]
    [StorageAccount("FunctionLevelStorageAppSetting")]
    public static void Run( //...
{
    ....
}

要使用的存储帐户按以下顺序确定:

  • BlobTrigger 特性的 Connection 属性。
  • 作为 BlobTrigger 特性应用到同一参数的 StorageAccount 特性。
  • 应用到函数的 StorageAccount 特性。
  • 应用到类的 StorageAccount 特性。
  • 函数应用的默认存储帐户,在 AzureWebJobsStorage 应用程序设置中定义。

仅当 blob 大小较小时才建议绑定到 stringByte[]。 我们推荐此做法,因为整个 blob 内容都会加载到内存中。 对于大多数 blob,请使用 StreamCloudBlockBlob 类型。 有关详细信息,请参阅并发和内存使用情况

如果尝试绑定到某个存储 SDK 类型时收到了错误消息,请确保已引用正确的存储 SDK 版本

@BlobTrigger 特性用于授予对触发函数的 blob 的访问权限。 有关详细信息,请参阅触发器示例

使用 context.bindings.<NAME> 访问 blob 数据,其中 <NAME> 与 function.json 中定义的值匹配。

通过与 function.json 文件中绑定名称参数指定的名称匹配的字符串参数访问 Blob 数据。

通过类型为 InputStream 的参数访问 blob 数据。 有关详细信息,请参阅触发器示例

连接

connection 属性是对环境配置的引用,它指定应用应如何连接到 Azure Blob。 它可能指定:

如果配置的值既是单个设置的完全匹配,也是其他设置的前缀匹配,则使用完全匹配。

连接字符串

要获取连接字符串,请执行管理存储帐户访问密钥中显示的步骤。 连接字符串必须属于某个常规用途存储帐户,而不能属于Blob 存储帐户

此连接字符串应存储在应用程序设置中,其名称与绑定配置的 connection 属性指定的值匹配。

如果应用设置名称以“AzureWebJobs”开始,则只能在此处指定该名称的余下部分。 例如,如果将 connection 设置为“MyStorage”,Functions 运行时将会查找名为“AzureWebJobsMyStorage”的应用设置。如果将 connection 留空,Functions 运行时将使用应用设置中名为 AzureWebJobsStorage 的默认存储连接字符串。

基于标识的连接

如果使用 5.x 版或更高版本的扩展,则无需将连接字符串与机密一起使用,而是可以使应用使用 Azure Active Directory 标识。 为此,需要定义公共前缀下的设置,该前缀映射到触发器和绑定配置中的 connection 属性。

如果将 connection 设置为“AzureWebJobsStorage”,请参阅使用标识连接到主机存储。 对于所有其他连接,扩展需要以下属性:

属性 环境变量模板 说明 示例值
Blob 服务 URI <CONNECTION_NAME_PREFIX>__serviceUri1 要连接到的 Blob 服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.blob.core.chinacloudapi.cn

1<CONNECTION_NAME_PREFIX>__blobServiceUri 可以用作别名。 如果连接配置将由 Blob 触发器使用,则 blobServiceUri 还必须带有 queueServiceUri。 请参阅下文。

如果要跨 Blob、队列和/或表使用总体连接配置,则无法使用 serviceUri 窗体。 URI 本身只能指定 Blob 服务。 作为一种替代方案,可以为每个服务专门提供一个 URI,从而允许使用单个连接。 如果这两个版本均提供,则将使用多服务窗体。 若要为多个服务(而不是 <CONNECTION_NAME_PREFIX>__serviceUri)配置连接,请设置:

属性 环境变量模板 说明 示例值
Blob 服务 URI <CONNECTION_NAME_PREFIX>__blobServiceUri 要连接到的 Blob 服务的数据平面 URI,使用 HTTPS 方案。 https://<storage_account_name>.blob.core.chinacloudapi.cn
队列服务 URI(Blob 触发器需要2 <CONNECTION_NAME_PREFIX>__queueServiceUri 使用 HTTPS 方案的队列服务的数据平面 URI。 仅 Blob 触发器需要该值。 https://<storage_account_name>.queue.core.chinacloudapi.cn

2 Blob 触发器通过将有害 blob 写入队列来处理多次重试中出现的故障。 在 serviceUri 窗体中,将使用 AzureWebJobsStorage 连接。 但是,在指定 blobServiceUri 时,还必须为 queueServiceUri 提供队列服务 URI。 建议使用与 Blob 服务相同的存储帐户中的服务。 还需要通过分配存储队列数据参与者等角色来确保触发器可以在配置的队列服务中读取和写入消息。

可以设置其他属性来自定义连接。 请参阅基于标识的连接的通用属性

在 Azure Functions 服务中托管时,基于标识的连接将使用托管标识。 默认情况下使用系统分配的标识,但可以使用 credentialclientID 属性来指定用户分配的标识。 在其他上下文(如本地开发)中运行时,将改用开发人员标识,尽管可以进行自定义。 请参阅使用基于标识的连接进行本地开发

向标识授予权限

无论使用何种标识,都必须具有执行所需操作的权限。 需要使用内置角色或者提供这些权限的自定义角色在 Azure RBAC 中分配角色

重要

某些权限可能由并非所有上下文都需要的目标服务公开。 尽可能遵循最低权限原则,仅授予标识所需的权限。 例如,如果应用只需要从数据源进行读取即可,则使用仅具有读取权限的角色。 分配一个也具有该服务写入权限的角色并不恰当,因为对于读取操作来说,写入是多余的权限。 同样,你也希望确保角色分配的范围仅限于需要读取的资源。

你将需要创建一个角色分配,以便在运行时提供对 Blob 容器的访问权限。 所有者等管理角色还不够。 下表显示了在正常操作中使用 Blob 存储扩展时建议使用的内置角色。 根据所编写的代码,应用程序可能需要具有其他权限。

绑定类型 内置角色示例
触发器 存储 Blob 数据所有者存储队列数据参与者1

此外,还必须为 AzureWebJobsStorage 连接授予其他权限。2
输入绑定 存储 Blob 数据读者
输出绑定 存储 Blob 数据所有者

1 Blob 触发器通过将有害 blob 写入到连接所指定的存储帐户上的队列来处理多次重试中出现的故障。

2 AzureWebJobsStorage 连接在内部用于启用触发器的 blob 和队列。 如果将其配置为使用基于标识的连接,则该连接将需要超出默认要求的其他权限。 存储 Blob 数据所有者存储队列数据参与者存储帐户参与者角色涵盖了这些权限。 若要了解更多信息,请参阅使用标识连接到主机存储

Blob 名称模式

可以在 function.jsonpath 属性中或者在 BlobTrigger 特性构造函数中指定 Blob 名称模式。 名称模式可以是筛选器或绑定表达式。 以下部分提供了有关示例。

提示

容器名称不能在名称模式中包含解析程序。

获取文件名和扩展名

以下示例演示如何分别绑定到 Blob 文件名和扩展名:

"path": "input/{blobname}.{blobextension}",

如果 Blob 名为 original-Blob1.txt,则函数代码中 blobnameblobextension 变量的值为 original-Blob1txt

按 Blob 名称筛选

以下示例仅根据 input 容器中以字符串“original-”开头的 Blob 触发:

"path": "input/original-{name}",

如果 Blob 名称为 original-Blob1.txt,则函数代码中 name 变量的值为 Blob1.txt

按文件类型筛选

以下示例仅根据 .png 文件触发:

"path": "samples/{name}.png",

按文件名中的大括号筛选

若要查找文件名中的大括号,请使用两个大括号将大括号转义。 以下示例筛选名称中包含大括号的 Blob:

"path": "images/{{20140101}}-{name}",

如果 Blob 名为 {20140101}-soundfile.mp3,则函数代码中的 name 变量值为 soundfile.mp3

轮询和延迟

轮询在检查日志和运行定期容器扫描之间起到混合作用。 每次以 10,000 个为一组扫描 Blob,并在间隔之间使用继续标记。 如果函数应用基于消耗计划,则当函数应用处于空闲状态时,处理新 Blob 会出现长达 10 分钟的延迟。

警告

存储日志将基于“尽力而为”的准则创建。 不保证捕获所有事件。 在某些情况下可能会遗漏某些日志。

如果需要更快或更可靠的 Blob 处理,应改为实现以下策略之一:

Blob 回执

Azure Functions 运行时确保没有为相同的新 blob 或更新 blob 多次调用 blob 触发器函数。 为了确定是否已处理给定的 blob 版本,它会维护 blob 回执

Azure Functions 将 Blob 回执存储在函数应用的 Azure 存储帐户中名为 azure-webjobs-hosts 的容器中(由 AzureWebJobsStorage 应用设置定义)。 Blob 回执包含以下信息:

  • 触发的函数(<FUNCTION_APP_NAME>.Functions.<FUNCTION_NAME>,例如:MyFunctionApp.Functions.CopyBlob
  • 容器名称
  • Blob 类型(BlockBlobPageBlob
  • Blob 名称
  • ETag(blob 版本标识符,例如:0x8D1DC6E70A277EF

若要强制重新处理某个 blob,可从 azure-webjobs-hosts 容器中手动删除该 blob 的 blob 回执。 虽然重新处理可能不会立即发生,但它肯定会在稍后的时间点发生。 若要立即重新处理,可以更新 azure-webjobs-hosts/blobscaninfo 中的 scaninfo Blob 。 将再次扫描 LatestScan 属性后具有上次修改时间戳的任何 Blob。

有害 Blob

当给定 blob 的 blob 触发函数失败时,Azure Functions 将默认重试该函数共计 5 次。

如果 5 次尝试全部失败,Azure Functions 会将消息添加到名为 webjobs-blobtrigger-poison 的存储队列。 最大尝试次数可配置。 使用相同的 MaxDequeueCount 设置处理有害 Blob 和有害队列消息。 有害 Blob 的队列消息是包含以下属性的 JSON 对象:

  • FunctionId(格式为 <FUNCTION_APP_NAME>.Functions.<FUNCTION_NAME>
  • BlobType(BlockBlobPageBlob
  • ContainerName
  • BlobName
  • ETag(blob 版本标识符,例如:0x8D1DC6E70A277EF

并发和内存使用情况

Blob 触发器可在内部使用队列,因此并发函数调用的最大数量受 host.json 中的队列配置控制。 默认设置会将并发限制到 24 个调用。 此限制分别应用于使用 blob 触发器的函数。

注意

对于使用 5.0.0 或更高版本的存储扩展的应用,host.json 中的队列配置仅适用于队列触发器。 而 blob 触发器并发由 host.json 中的 blob 配置控制。

消耗计划将虚拟机 (VM) 上的函数应用限制为 1.5 GB 内存。 内存由每个并发执行函数实例和函数运行时本身使用。 如果 blob 触发的函数将整个 blob 加载到内存中,该函数使用的仅用于 blob 的最大内存为 24 * 最大 blob 大小。 例如,包含 3 个由 blob 触发的函数的函数应用和默认设置,其每 VM 最大并发为 3*24 = 72 个函数调用。

JavaScript 和 Java 函数会将整个 blob 加载到内存中,并且如果绑定到 stringByte[],则 C# 函数也会如此。

host.json 属性

host.json 文件包含控制 blob 触发器行为的设置。 有关可用设置的详细信息,请参阅 host.json 设置部分。

后续步骤