处理 Azure 逻辑应用中的限制问题(429 -“请求过多”错误)

适用范围:Azure 逻辑应用(消耗型 + 标准型)

如果逻辑应用工作流遇到限制(当请求数超过目标在特定时间内可以处理的速率时会发生这种情况),则会出现“HTTP 429 请求过多”错误。 限制可能会造成各种问题,例如,数据处理延迟、性能速度下降,以及超过指定的重试策略等错误。

例如,消耗工作流中的以下 SQL Server 操作显示 429 错误,该错误报告了限制问题:

Screenshot showing a Consumption workflow with a SQL Server action that has a 429 error.

以下部分介绍工作流可能会遇到限制的常见级别:

逻辑应用资源限制

Azure 逻辑应用具有自身的吞吐量限制。 如果逻辑应用资源超过这些限制,则逻辑应用资源(而不仅仅是特定工作流实例或运行)将受到限制。

若要在此级别查找限制事件,请执行以下步骤:

  1. Azure 门户中,打开你的逻辑应用资源。

  2. 在逻辑应用资源菜单中,在“监视”下,选择“指标”。

  3. 在“图表标题”下,选择“添加指标”,将另一个指标条添加到图表。

  4. 在第一个指标栏中,从“指标”列表中选择“操作受限制事件”。 从“聚合”列表中,选择“计数”。

  5. 在第二个指标栏中,从“指标”列表中选择“触发器受限制事件”。 从“聚合”列表中,选择“计数”。

该图表现在显示逻辑应用工作流中操作和触发器的受限制事件。 有关详细信息,请查看在 Azure 逻辑应用中查看工作流运行状况和性能的指标

若要处理此级别的限制,可以使用以下选项:

  • 限制可以同时运行的工作流实例数。

    默认情况下,如果同时满足你的工作流的触发器条件多次,则会并发或并行触发和运行该触发器的多个实例。 每个触发器实例会在上一个工作流实例完成运行前触发。

    尽管可以并发运行的默认触发器实例数没有限制,但可以通过启用触发器的并发性设置来限制此数目;如果需要,可选择一个不同于默认值的限制。

  • 启用高吞吐量模式。

  • 在触发器中禁用数组解批或“拆分”行为。

    如果触发器返回了要处理的剩余工作流操作数组,则触发器的拆分设置会拆分数组项,并针对每个数组项启动一个工作流实例。 此行为可有效地触发多个并发运行,直到达到拆分限制

    若要控制限制,请禁用触发器的拆分行为,让工作流通过单个调用处理整个数组,而不是每个调用处理一项。

  • 将操作重构为多个较小的工作流。

    如前所述,消耗逻辑应用工作流在 5 分钟期限内可运行的操作数目存在默认限制。 虽然可以通过启用高吞吐量模式来提高此限制,但也可以考虑是否要将工作流的操作分解为更小的工作流,使每个工作流中运行的操作数目不会超过限制。 这样,便可以减轻单个工作流的负担,并跨多个工作流分配负载。 此解决方案更适合那些处理大型数据集的操作,或者那些启动了许多并发运行操作、循环迭代或每个循环迭代中的操作以至于超出操作执行限制的操作。

    例如,以下消耗工作流会执行从 SQL Server 数据库获取表以及从每个表获取行所需的所有工作。 For each 循环以并发方式遍历每个表,使 Get rows 操作返回每个表的行。 这些操作可能会超出操作执行限制,具体取决于这些表中的数据量。

    Screenshot showing Consumption workflow

    重构后,原始工作流将拆分为父工作流和子工作流。

    以下父工作流将从 SQL Server 获取表,然后针对每个表调用子工作流来获取行:

    Screenshot showing Consumption parent workflow that gets the SQL Server tables and calls the child workflow.

    父工作流会调用以下子工作流来获取每个表的行:

    Screenshot showing Consumption child workflow that gets the rows for each table.

连接器限制

每个连接器具有自身的限制,可以在每个连接器的技术参考页上找到这些限制。 例如,Azure 服务总线连接器的限制为每分钟最多允许 6000 次调用,而 SQL Server 连接器的限制因操作类型而异

某些触发器和操作(例如 HTTP)具有“重试策略”,可以根据重试策略限制对该策略进行自定义以实现异常处理。 此策略指定当原始请求失败或超时并生成 408、429 或 5xx 响应时,触发器或操作是否以及以何频率重试请求。 因此,当限制开始并返回了 429 错误时,逻辑应用在受支持的情况下将遵循重试策略。

若要了解触发器或操作是否支持重试策略,请检查该触发器或操作的设置。 若要查看触发器或操作的重试尝试,请转到逻辑应用的运行历史记录,选择要查看的运行,然后展开该触发器或操作以查看有关输入、输出和任何重试的详细信息。

以下消耗工作流示例演示了可在何处找到 HTTP 操作的此信息:

Screenshot showing Consumption workflow with an HTTP action's run history, retries, inputs, and outputs.

尽管重试历史记录提供了有关错误的信息,但在区分连接器限制和目标限制时可能会遇到麻烦。 在这种情况下,可能必须查看响应的详细信息,或执行一些限制间隔计算来确定来源。

对于多租户 Azure 逻辑应用中的消耗逻辑应用工作流,限制是在连接级别发生的。

若要处理此级别的限制,可以使用以下选项:

  • 为单个操作设置多个连接,使工作流可以对要处理的数据进行分区。

    请考虑是否可以通过以下方式来分配工作负载:使用相同凭据将操作的请求划分到与同一目标建立的多个连接。

    例如,假设工作流从某个 SQL Server 数据库获取表,然后从每个表获取行。 根据需要处理的行数,可以使用多个连接和多个 For each 循环将总行数划分为较小的集进行处理。 此方案使用两个 For each 循环将总行数划分为两半。 第一个 For each 循环使用一个表达式来获取前半部分。 另一个 For each 循环使用另一个表达式获取后半部分,例如:

    • 表达式 1:take() 函数获取集合开头的项。 有关详细信息,请参阅 take() 函数

      @take(collection-or-array-name, div(length(collection-or-array-name), 2))

    • 表达式 2:skip() 函数删除集合开头的项并返回所有其他项。 有关详细信息,请参阅 skip() 函数

      @skip(collection-or-array-name, div(length(collection-or-array-name), 2))

      以下消耗工作流示例演示如何使用这些表达式:

      Screenshot showing a Consumption workflow that uses multiple connections for a single action.

  • 为每个操作设置不同的连接。

    请考虑是否可以通过以下方式分配工作负载:通过每个操作的请求自身的连接来分散这些请求,即使操作连接到同一服务或系统并使用相同的凭据。

    例如,假设工作流从某个 SQL Server 数据库获取表,并获取每个表中的每个行。 可以使用不同的连接,以便在获取表时使用一个连接,获取每个行时使用另一个连接。

    以下示例演示了一个消耗工作流,该工作流为每个操作创建并使用不同的连接:

    Screenshot showing a Consumption workflow that creates and uses a different connection for each action.

  • 更改“For each”循环中的并发度或并行度。

    默认情况下,“For each”循环迭代会同时运行,但不超过并发限制。 如果连接在“每个对象”循环内部受到限制,你可以减少并行运行的循环迭代数。 有关详细信息,请参阅以下文档:

目标服务或系统限制

连接器存在自身的限制,同时,该连接器调用的目标服务或系统也可能存在限制。 例如,Microsoft Exchange Server 中某些 API 的限制比 Office 365 Outlook 连接器的限制更严格。

默认情况下,逻辑应用的工作流实例以及这些实例中的任何循环或分支将会并行运行。 此行为意味着,多个实例可以同时调用同一个终结点。 每个实例不知道其他实例是否存在,因此重试失败的操作可能会造成争用状况,在这种情况下,多个调用尝试会同时运行,但若要成功,这些调用必须在开始发生限制之前抵达目标服务或系统。

例如,假设你的某个数组包含 100 个项。 可使用“每个对象”循环来迭代该数组并启用循环的并发控制,以便可以将并行迭代数限制为 20 或当前默认限制。 在该循环中,某个操作将数组中的某个项插入 SQL Server 数据库,此时每秒只允许 15 次调用。 这种情况会导致限制问题,因为重试会不断积压,而永远不会运行。

下表描述了当操作的重试间隔为 1 秒时,循环中发生的情况的时间线:

时间点 运行的操作数目 失败的操作数目 等待的重试次数
T + 0 秒 20 次插入 5 个操作由于 SQL 限制而失败 5 次重试
T + 0.5 秒 由于前 5 次重试处于等待状态而产生了 15 次插入 所有 15 个操作由于前面的 SQL 限制保持生效 0.5 秒而失败 20 次重试
(前 5 次 + 15 次新重试)
T + 1 秒 20 次插入 5 次加上前 20 次重试由于 SQL 限制而失败 25 次重试(前 20 次 + 5 次新重试)

若要处理此级别的限制,可以使用以下选项:

  • 创建个别工作流,让每个工作流处理一个操作。

    • 沿用本部分中的示例 SQL Server 方案,你可以创建一个工作流,用于将数组项放入队列(例如 Azure 服务总线队列)。 然后,创建另一个工作流,用于仅对该队列中的每个项执行插入操作。 这样,在任意特定时间只会运行一个工作流实例,该实例完成插入操作并转到队列中的下一项;或者,该实例会收到 429 错误,但不会毫无意义地进行重试。

    • 创建一个父工作流,用于为每个操作调用子工作流或嵌套工作流。 如果父级需要根据其结果调用不同的子工作流,则你可以使用条件操作或开关操作来确定要调用哪个子工作流。 此模式可帮助减少调用或操作的数目。

      例如,假设你有两个工作流,每个工作流通过一个轮询触发器每隔一分钟检查电子邮件帐户中的特定主题(例如“成功”或“失败”)。 此设置会导致每小时发出 120 次调用。 如果创建单个父工作流,该应用每隔一分钟轮询一次,但会调用根据主题是“成功”还是“失败”运行的子工作流,则你可以将轮询检查次数减少一半(在本例中为 60 次)。

  • 设置批处理。 (仅限消耗型工作流)

    如果目标服务支持批处理操作,则你可以通过按组或按批对各个项进行处理(而不是逐个处理)来解决限制。 若要实现批处理解决方案,请创建一个“批接收器”逻辑应用工作流和一个“批发送器”逻辑应用工作流。 批发送器不断收集消息或项,直到满足指定的条件,然后将这些消息或项发送到单个组中。 批接收器接受该组,并处理这些消息或项。 有关详细信息,请参阅按组对消息进行批处理

  • 请使用触发器和操作的 Webhook 版本,而不是轮询版本。

    为什么? 轮询触发器按特定的间隔持续检查目标服务或系统。 非常频繁的间隔(例如每秒)可能会造成限制问题。 但是,Webhook 触发器或操作(例如 HTTP Webhook)只会针对目标服务或系统创建单个调用,该调用是在订阅时发生的,并请求目标仅在发生事件时才通知触发器或操作。 这样,触发器或操作就没有必要持续检查目标。

    因此,如果目标服务或系统支持 Webhook 或提供了使用 Webhook 版本的连接器,则此选项比使用轮询版本更好。 可以通过以下方法识别 Webhook 触发器和操作:它们具有 ApiConnectionWebhook 类型,它们也不要求指定重复周期。 有关详细信息,请参阅 APIConnectionWebhook 触发器APIConnectionWebhook 操作

后续步骤