本文介绍使用 适用于 Azure Cosmos DB for NoSQL 的 Azure Functions 触发器时的常见问题、解决方法和诊断步骤。
依赖关系
Azure Cosmos DB for NoSQL 的 Azure Functions 触发器和绑定依赖于基于 Azure Functions 运行时的扩展包 Microsoft.Azure.WebJobs.Extensions.CosmosDB 。 始终更新这些包,因为它们包括修补程序和新功能,可帮助解决可能遇到的任何潜在问题。
独立使用 Azure Cosmos DB SDK
扩展包的主要功能是为 Azure Cosmos DB 的 Azure Functions 触发器和绑定提供支持。 该包还包括 Azure Cosmos DB .NET SDK,如果要在不使用触发器和绑定的情况下以编程方式与 Azure Cosmos DB 交互,这非常有用。
如果你想使用 Azure Cosmos DB SDK,请确保不要向你的项目添加其他 NuGet 包引用。 而是让 SDK 引用通过 Azure Functions 扩展包解析。 与触发器和绑定分开使用 Azure Cosmos DB SDK。
此外,如果要手动创建自己的 Azure Cosmos DB SDK 客户端实例,则应遵循只有一个客户端实例并使用 单一实例模式方法的模式。 此过程可避免在操作中出现潜在的套接字问题。
常见方案和解决方法
您的 Azure 函数失败,并出现关于集合“doesn't exist”的错误消息
Azure 函数失败并显示以下错误消息:“源集合(在数据库中collection-name)或租约集合database-namecollection2-name (在数据库中database2-name)不存在。 在侦听器启动之前,这两个集合必须存在。 若要自动创建租约集合,请设置为 CreateLeaseCollectionIfNotExiststrue。
此错误意味着触发器正常工作所需的一个或两个 Azure Cosmos DB 容器存在以下情况之一或两者:
- 不存在
- 无法访问 Azure 函数
错误文本本身会根据配置告知触发器要查找的 Azure Cosmos DB 数据库和容器。
若要解决此问题,请执行下列操作:
验证属性
Connection,以及它是否引用了 Azure 函数应用中存在的设置。- 此属性上的值不应是连接字符串本身,而是配置设置的名称。
请确认
databaseName和containerName值是否存在于您的 Azure Cosmos DB 帐户中。- 如果使用自动值替换(使用
%settingName%模式),请确保设置的名称存在于 Azure 函数应用中。
- 如果使用自动值替换(使用
如果未指定
LeaseContainerName/leaseContainerName值,则默认值为leases。 验证此类容器是否存在。- (可选)您可以将触发器中的
CreateLeaseContainerIfNotExists属性设置为true来自动创建它。
- (可选)您可以将触发器中的
若要确保 Azure Cosmos DB 帐户未阻止 Azure 函数,请验证 Azure Cosmos DB 帐户的防火墙配置。
Azure 函数无法启动,出现错误消息“Shared throughput collection should have a partition key”
以前版本的 Azure Cosmos DB 扩展不支持使用在 共享吞吐量数据库中创建的租约容器。
若要解决此问题,请执行下列操作:
- 更新 Microsoft.Azure.WebJobs.Extensions.CosmosDB 扩展以获取最新版本。
Azure 函数无法启动,出现错误消息“PartitionKey must be supplied for this operation”
此错误意味着你当前正在使用具有旧 扩展依赖项的分区租约集合。
若要解决此问题,请执行下列操作:
- 升级到最新的可用版本。
Azure 函数无法启动,出现错误消息“Forbidden (403); Substatus: 5300... The given request [POST ...] can't be authorized by Microsoft Entra token in data plane”
此错误意味着您的函数尝试 使用 Microsoft Entra 身份执行非数据操作。 使用 Microsoft Entra 标识时无法使用 CreateLeaseContainerIfNotExists = true 。
Azure 函数无法启动,出现错误消息“The lease collection, if partitioned, must have partition key equal to id”
此错误表示当前租用容器已分区,但分区键路径不是 /id。
若要解决此问题,请执行下列操作:
-
使用分区键重新创建租约容器
/id。
尝试运行触发器时,会收到错误消息“Value can't be null. Parameter name: o" in your Azure function logs”
如果使用 Azure 门户,在检查使用触发器的 Azure 函数时选择 “运行 ”按钮,则可能会出现此问题。 触发器不需要选择"运行"以启动它。 部署函数时,它会自动启动。
若要解决此问题,请执行下列操作:
- 若要在 Azure 门户中检查函数的日志流,请转到受监视的容器并插入一些新项。 触发器自动运行。
更改需要太长的时间才能收到
这种情况可能有多个原因。 请考虑尝试以下任何或全部解决方案:
Azure 函数和 Azure Cosmos DB 帐户是否部署在单独的区域中? 为了获得最佳网络延迟,应将 Azure 函数和 Azure Cosmos DB 帐户并置在同一 Azure 区域中。
Azure Cosmos DB 容器中发生的更改是连续还是偶发的?
Azure Cosmos DB 容器可能会 受到速率限制。
可以使用
PreferredLocations触发器中的属性来指定以逗号分隔的 Azure 区域列表来定义自定义首选连接顺序。处理新更改的速度决定了触发器接收这些更改的速度。 验证函数的执行 时间或持续时间。 如果函数速度缓慢,这会增加触发器获取新更改所需的时间。 如果看到持续时间最近有所增加,最近的代码更改可能会对此产生影响。 如果在 Azure Cosmos DB 容器中接收操作的速度比触发器的更快,那么它就会滞后。 你可能想要调查函数的代码,以确定最耗时的作以及如何对其进行优化。
可以使用 调试日志 检查诊断,并验证是否存在网络延迟。
我触发器中的一些更改重复了
更改的概念是对项的操作。 接收同一项事件的最常见场景包括:
您的函数在执行期间失败。 如果为函数启用了 重试策略 ,或者如果函数执行超过允许的执行时间,则可以将同一批更改再次传递到函数。 此失败是预期的,根据设计,请查看函数日志,了解故障指示,并确保启用 触发器日志 以获取更多详细信息。
在实例之间进行租约的负载均衡。 当实例增加或减少时, 负载均衡 可能会导致同一批更改传递到多个函数实例。 此负载均衡是预期的,并且是设计如此,应该是暂时性的。 触发器日志包括实例获取和释放租约时的事件。
该项目正在更新。 更改馈送可以包含同一项的多个操作。 如果项正在接收更新,它可以选取多个事件(每个更新一个)。 区分同一项目的不同操作的一种简单方法是跟踪
_lsn每个更改的属性信息。 如果属性不匹配,则更改不同。如果仅通过
id来识别项,请记住,项的唯一标识符是id及其分区键。 (两个项目可以具有相同id但不同的分区键)。
触发器中缺少一些更改
你可能会发现该函数未检测到发生在 Azure Cosmos DB 的 NoSQL 容器中的某些更改。 或者在您复制更改时,目标位置缺少了一些更改。 如果是,请尝试本部分中的解决方案。
请确保已启用 日志 。 验证处理过程中未发生任何错误。
当 Azure 函数收到更改时,它通常会处理这些更改,并且可以选择性地将结果发送到另一个目标。 在调查缺少的更改时,请确保你检测数据引入点接收到的更改。 请在 Azure 函数启动时进行测量,而不是在目标位置。
如果目标上缺少某些更改,则此行为可能表示在收到更改后 Azure 函数执行期间发生了一些错误。
在此方案中,最佳的行动方案是在代码中添加
try/catch块,并在可能处理这些更改的循环内添加块。 添加它有助于检测特定子集项的任何故障并相应地处理它们(将它们发送到另一个存储以进一步分析或重试)。 或者,可以配置 Azure Functions 重试策略。注释
默认情况下,对于 Azure Cosmos DB for NOSQL 的 Azure Functions 触发器,如果在代码执行期间出现未经处理的异常,则不会重试一批更改。 这意味着更改没有到达目标的原因可能是你未能成功处理这些更改。
如果目标是另一个 Azure Cosmos DB 容器,并且要执行更新插入操作来复制项,请验证这两个容器的分区键定义。 受监视容器和目标容器上的分区键必须相同。 由于此配置差异,Upsert操作可能会将多个源数据项合并保存为目标中的一个。
如果发现触发器未收到一些更改,最常见的情况是另一个 Azure 函数正在运行。 另一个函数可能部署在 Azure 中,或者某个函数可能在开发人员的计算机上本地运行,其配置完全相同。 如果是这样,此函数可能会窃取预期 Azure 函数要处理的一部分更改。
此外,如果知道正在运行的 Azure 函数应用实例数,则可以验证方案。 如果检查租约容器并计算其中租约项的数量,则属性 Owner 的不同值应等于函数应用实例的数量。 如果所有者数超过已知的 Azure 函数应用实例,则意味着这些额外的所有者是“窃取”更改的所有者。
一种简单的解决方法是,对您的函数应用LeaseCollectionPrefix/leaseCollectionPrefix,以新的或不同的值,或使用一个新租约容器进行测试。
需要从头开始重启并重新处理容器中的所有项
若要从头开始重新处理容器中的所有项,
如果 Azure 函数当前正在运行,请停止该函数。
删除租约集合中的文档(或删除并重新创建租约集合,使其为空)。
将函数中的 StartFromBeginning CosmosDBTrigger 属性设置为
true。重启 Azure 函数。 函数现在从头开始读取和处理所有更改。
设置 StartFromBeginning 以 true 指示 Azure 函数从集合历史记录的开头开始读取更改,而不是当前时间。
仅当尚未创建租约(即租约集合中的文档)时,此解决方案才有效。
将此属性设置为 true 在已创建租约时不起作用。 在此方案中,当函数停止并重新启动时,它将从最后一次检查点开始读取,此检查点是由租约集合定义的。
错误:Binding can be done only with IReadOnlyList<Document> or JArray
如果 Azure Functions 项目包含与版本冲突的 Azure Cosmos DB SDK 的手动 NuGet 包引用,则会发生此错误。 此错误通常发生,因为包的版本不同于 Azure Functions 的 Azure Cosmos DB 扩展提供的版本。
若要解决此问题,请删除添加的手动 NuGet 引用,让 Azure Cosmos DB SDK 引用通过 Azure Functions 包的 Azure Cosmos DB 扩展解析。
更改 Azure 函数的轮询间隔以检测更改
如之前在 “您的更改接收时间过长” 部分中所述,您的 Azure 函数会在检查新更改之前休眠一段可配置的时间(默认情况下为5秒),以避免高RU消耗。 可以通过FeedPollDelay/feedPollDelay中的设置来配置此睡眠时间(该值应为毫秒)。