速率限制

为了向遍布全球的 AdWords API 用户提供可靠的服务,我们使用令牌桶算法来衡量请求数并确定每秒查询数 (QPS) 速率。这样做的目的是阻止恶意的或不可控的软件大量入侵 AdWords API 服务器,影响其他用户。

例如,如果某个失控的客户端意外产生数以千计的线程来同时调用 AdWords API,AdWords API 服务器就会在发现后返回一个 RateExceededError,要求调用软件减速。

必须注意的是,速率限制会因为不同的变量(包括服务器负载)而有所波动。因此,我们不推荐固定的每秒查询数 (QPS) 限制。更加重要的是,您必须了解如何处理 RateExceededError,并在开发软件时考虑到速率限制情况。

本指南将深入介绍更多详情,帮助您了解 RateExceededError 以及如何避免超出速率限制。

历史

在旧版 AdWords API 中,超出限制的请求会在 API 服务器上排队,一直等到可以运行为止,从而导致一些请求的执行时间可能看起来非常长。但最新的 API 不会长时间阻塞客户端,而是会迅速失败并返回 RateExceededError。我们相信这是一个非常重要的反馈机制,可确保您发现问题并相应调整您的应用。

速率限制类型

我们意识到,有时您的 AdWords API 客户端应用之所以会超出限制并收到 RateExceededError,是由于一些您无法完全控制的因素。需要注意的是,这种情况并不会遭致惩罚。 RateExceededError 通常是短暂的,会在闲置 30 秒后自动解决。

服务器可能会强制执行多种不同类型的速率限制。客户端应用可能超出经理帐号的开发者令牌范围内的速率限制或 AdWords 帐号范围内的速率限制。在每个范围内,系统并非采用严格的每秒查询数速率限制,而是每分钟请求数、每分钟操作数和/或其他类型的速率限制。这使得稳定流量和突发流量都能流入 AdWords API。范围和速率限制名称都会包含在返回的 RateExceededError 中。

基于权限级别的操作限制

只有一种类型的速率限制不会波动,那就是基于您开发者令牌的访问权限级别的操作限制。有两种访问权限级别:基本标准。对基本访问权限级别帐号的限制是每天 10,000 次操作,每天 1,000 次报告下载。新获批准的开发者令牌默认会获得基本访问权限级别。如果计划每日执行超过 10,000 次的操作或超过 1,000 次的报告下载,您可以填写 AdWords API 标准权限申请表来申请标准权限级别。使用任一权限级别均无需支付任何费用。如需了解操作的计数方式,请参阅价目表

除操作限制外,其他所有速率限制都可能波动。因此,您必须处理应用中的 RateExceededError

RateExceededError 的元素

我们来更详细地了解一下 RateExceededError,它包含 3 个非常重要的字段:

  • rateScope - 所超出的速率范围,可以是 ACCOUNTDEVELOPER
  • rateName - 包含所超出速率限制的名称。例如,值可以是 RequestsPerMinute
  • retryAfterSeconds - 包含您的应用在重试请求前至少应该等待的秒数。我们建议在确定等待秒数时,将随机乘数(例如 1 和 2 之间的浮点值,包含边界值)应用于 retryAfterSeconds。如果您的程序并行发送请求(例如多线程),请确保它们在等待后不会同时发送新请求。

如果您的应用持续超出速率限制,那么您需要了解 rateScoperateName,以在应用中实施更长期的限制策略。

帐号范围与开发者范围

速率范围的值可以是 ACCOUNTDEVELOPER,这取决于您是在 AdWords 帐号一级还是在开发者令牌一级超出速率限制。

开发者令牌速率范围

每个注册使用 AdWords API 的 AdWords 经理帐号都使用一个开发者令牌,您发出的每个请求都很可能与该开发者令牌关联在一起。如果使用同一开发者令牌的所有客户端请求合起来的 QPS 超出特定的速率限制,则可能会返回 RateExceededError,其中指明超出了开发者速率范围的限制。

例如,如果经理帐号管理 100 个 AdWords 帐号,并且有多个客户端软件实例使用相同的开发者令牌,每秒跨不同的进程、线程或机器总共产生数百个请求,则客户端软件可能会收到有关开发者令牌速率范围的 RateExceededError

帐号速率范围

如果同一个应用在由经理帐号管理的单个 AdWords 帐号上发送的每秒请求数较高,AdWords API 服务器可能会针对这种超出帐号范围内速率限制的行为返回 RateExceededError。例如,如果您的客户端应用针对单个 AdWords 帐号生成多个线程来执行过多的 mutate() 操作,就可能会发生这种情况。

请注意,此帐号速率范围内的速率限制是按对单个 AdWords 帐号发送的请求总数来衡量的,而不管发送请求时所用的是哪个开发者令牌。

假设一个 AdWords 帐号由五个不同的经理帐号管理,则可能所有五个经理帐号都会同时针对同一个 AdWords 帐号提出请求。如果所有经理帐号合起来的每秒查询数超过限制,那么客户端将收到有关帐号速率范围的 RateExceededError

速率名称及其重要性

除了了解速率范围之外,您还必须了解所超出的速率限制类型。速率限制的类型会在 rateName 字段中返回。常见的速率限制名称包括:

  • RequestsPerMinute
  • OperationsPerMinute
请求与操作之间的区别

RequestsPerMinuteOperationsPerMinute 之间的区别是什么?每个 SOAP 服务调用都记为一次请求。例如,每次您调用 CampaignService.mutate() 时,系统都会将其记录为一次请求。不过,在 mutate 请求中,您可能传送了 100 次 CampaignOperation,这将记为 100 次操作!

在上述示例中,虽然您可以通过将多项操作组合为一个请求来避开 RequestPerMinute 速率限制,但仍有可能触及 OperationsPerMinute 速率限制。

如需有关如何计算操作次数的更多示例,请访问价目表页面。

边缘案例

以上是较为常见的速率名称,但请注意,您可能还会超出其他类型的速率限制。如果您遇到这些问题,请在 AdWords API 论坛中告知我们。

降速

如果您的应用收到 RateExceededError,就应该减慢速度!否则可能会进一步延误应用从错误中恢复。最简单的降速方法之一是在重新尝试请求和/或继续其他请求时考虑 RateExceededError.retryAfterSeconds 的值。

例如,在 Java 中,要在处理其他请求前暂停线程,最简单的方法之一是执行 Thread.sleep()

try {
  ...
} catch (ApiException e) {
  for (ApiError error : e.getErrors()) {
    if (error instanceof RateExceededError) {
      RateExceededError rateExceeded = (RateExceededError) error;
      Thread.sleep(rateExceeded.getRetryAfterSeconds() * 1000);
    }
  }
  ...
}

这种方法简单而直接,但可能无法取得最佳的总吞吐量,因此应用作最后的防御手段。

有许多方法可以降低超出速率限制的几率。掌握企业集成模式 (EIP) 概念(如消息传递、重新传递和限流)可帮助您开发更强大的客户端应用。

我们将在下一节介绍这些推荐做法。请注意,即使采用了缓减措施,您还是应具备处理 RateExceededError 的能力。

掌控

通过主动减少请求数量和从客户端限制 QPS,您可以控制应用并尽可能减少 RateExceededError

下面是一些推荐的做法,按从最简单的策略到最强大但最复杂的架构排列:

  • 限制并发线程数
  • 批量发送请求
  • 使用 BatchJobService
  • 限流/使用速率限制器
  • 向不同帐号交错发送请求
  • 排队
  • 区别对待新帐户与现有帐户

限制并发线程数

通常发生 RateExceededError 的根本原因是客户端应用产生了过多的线程,并且所有线程都在同时调用 AdWords API。虽然我们不限制客户端应用可以拥有的并发线程数,但是通过不限量的线程并发发送请求,可能很容易就会超过开发者令牌级别的每秒请求数限制。

我们建议设置合理的并发请求线程总数上限(包括所有进程和机器),并从这一上限点向上调整,以在不超出速率限制的情况下优化吞吐量。

此外,您可以考虑从客户端限制所有线程总的 QPS(参阅限流/使用速率限制器)。

批量发送请求

尽可能考虑批量处理多个请求,将其放入单个请求中,此方法最适用于 mutate() 调用。例如,如果您要更新 AdGroupAd 的多个实例的状态,而不是对每个 AdGroupAd 调用 mutate() 一次,则可以调用 mutate() 一次,并一次传入多个 AdGroupAdOperation。如需了解更多示例以及组合操作的最佳做法,请参阅最佳做法一节。

在将多个操作组合为单个请求时,请一定注意大部分请求都是不可分割的。如果某个操作失败,则整个请求都将失败,不会更新任何内容。您可以利用部分失败功能来改变这种行为。

最后,虽然批量发送请求可以减少请求总数并减缓超出“每分钟请求数”速率限制的情况,但如果您对单个帐号执行大量的操作,还可能触发“每分钟操作数”速率限制。

使用 BatchJobService

如果作业时间较长,需要处理大量操作,或者有跨越多项服务的大量操作,请考虑使用 BatchJobService。BatchJobService 可为您在 Google 云端中以异步方式安排和执行数以千计的操作,而您要做的就是轮询结果以查看作业是否完成。

详情请参阅批处理指南

限流/使用速率限制器

除了在客户端应用中限制线程总数之外,您还可以在客户端实施速率限制器。这样的策略可确保各进程和/或集群中的所有线程都受到客户端指定的 QPS 限制的约束。

例如,您可以试试 Guava 速率限制器,或自行实施适合在集群环境中使用的令牌桶算法。例如,您可以生成令牌并将其存储在共享的事务性存储区(如数据库)中,每个客户端在处理请求之前都需要先获取和使用一个令牌。如果令牌用尽,客户端必须等待系统生成下一批令牌。

在大多数情况下,限流操作可帮助您避免超出开发者令牌范围内的速率限制。

向不同帐号交错发送请求

如果您超出了帐号范围的速率限制,则可以在客户端对帐号设置速率限制 QPS;但如果您有成千上万个帐号需要管理,这可能并不轻松。与此相比,更为简单的策略是基于帐号交错发送请求。

例如,如果您要对 10 个帐号执行 5000 次 mutate() 操作,其中一种方法是依序先将批量操作发送到帐号 1,然后发送到帐号 2、帐号 3,依此类推:

  1. 为帐号 1 发送 500 个 mutate 操作(重复 10 次即可达到 5000 次操作)
  2. 为帐户2发送500个mutate操作(同样重复10次)
  3. …(直到完成对所有 10 个帐号的操作)

这种方法非常简单,但您可能在每分钟操作数方面超出帐号范围内的速率限制。

通过交错帐号,请求顺序会变成如下这样:

  1. 为帐户1发送500次mutate操作
  2. 为帐户2发送500次mutate操作
  3. 为帐户3发送500次mutate操作
  4. …(直到完成对所有10个帐户的操作)
  5. 为帐户1发送500次mutate操作
  6. 为帐户2发送500次mutate操作
  7. …(直到为每个帐号发送完 5000 次操作)

以上示例展示了如何基于帐号交错发送请求,但您也应检查 BatchJobService 是否满足您的要求。详情请参阅批处理指南

排队

消息队列是分配操作负载的最佳解决方案,同时还控制请求和使用者速率。可用的消息队列方案有许多:有些是开源的,有些是专有的,而且其中有许多支持不同的语言。

在使用消息队列时,您可以有多个推送消息到队列的生成者和多个处理这些消息的使用者。限流可在使用者一端实施,方法是限制并发使用者的数量,或者为生成者或使用者实施速率限制器或限流器。

例如,如果消息使用者遇到 RateExceededError,那么该使用者可以将请求返回到要重试的队列。与此同时,该使用者还可以通知所有其他使用者暂停处理几秒钟,以等待从错误中恢复。

针对新帐号和现有帐号使用不同的队列或速率限制器

当您实施排队或速率限制器策略时,请务必注意,对新的 AdWords 帐号的速率限制可能明显严格于现有帐号(即 QPS 更低)。因此,如果您的组织经常创建新帐号且有大量的老帐号需要管理,则您可以考虑针对这两种类型的帐号使用不同的速率限制器或限流器。

通过这种方式,您可以最大限度地提高两类帐号的吞吐量,而不会受限于 QPS 最低的帐号。

一般情况下,新 AdWords 帐号所受的严格限制会在帐号发布广告后放宽。

发送以下问题的反馈:

此网页
AdWords API
AdWords API
需要帮助?请访问我们的支持页面