Google Ads API 会分别针对客户 ID 和 Google Cloud 项目,按每秒查询次数 (QPS) 强制执行速率限制。除了每分钟请求数(用于衡量 API 调用频率)之外,Google Ads API 还会对每分钟操作数(用于衡量所有请求中的 API 操作总数)施加限制。Google Ads API 使用令牌桶算法来计量请求并确定适当的 QPS 限制,因此确切的限制会因任何给定时间的总体服务器负载而异。
实施速率限制的目的是防止某个用户有意或无意地发出大量请求,给 Google Ads API 服务器带来过重负担,从而中断其他用户的服务。
违反速率限制的请求会被拒绝,并显示以下错误:RESOURCE_TEMPORARILY_EXHAUSTED。
您可以通过主动减少请求数量和在客户端限制 QPS 来控制应用并缓解速率限制。
您可以通过多种方式降低超出速率限制的可能性。熟悉企业集成模式 (EIP) 概念(例如消息传递、重新传送和限制)有助于您构建更强大的客户端应用。
以下推荐做法按复杂程度排序,较简单的策略排在前面,更强大但更复杂的架构排在后面:
指数退避算法
当您的应用收到 RESOURCE_TEMPORARILY_EXHAUSTED 错误时,请先使用具有随机抖动的指数退避算法策略,然后再重试失败的请求。指数退避算法会逐步增加重试之间的等待时间(例如,等待 2 秒,然后等待 4 秒,再等待 8 秒,外加一个随机的小延迟),从而让服务器负载和配额桶得以恢复,同时防止客户端实例之间出现同步重试高峰。
限制并发任务数
导致速率超限的一个根本原因是客户端应用产生了过多的并行任务。虽然我们不限制客户端应用可以发出的并行请求数,但这可能会超出 Google Cloud 项目级层的每秒请求数限制。
我们建议对所有进程和机器上将会发送请求的并行任务总数设置合理的上限,并以之为基础向上调整,从而在不超出速率限制的情况下优化吞吐量。
此外,您还可以考虑从客户端限制 QPS(请参阅限制和速率限制器)。
批量请求
考虑将多项操作批量处理为单个请求。这最适用于各种服务的 Mutate 调用。例如,如果您要更新 AdGroupAd 的多个实例的状态,可以调用 MutateAdGroupAds 一次,并传入多个 operations,而不是为每个 AdGroupAd 调用 MutateAdGroupAds 一次。如需查看更多示例,请参阅我们的批量操作指南。
虽然批量请求可以减少 API 调用总数并缓解每分钟请求数的速率限制,但如果您对单个账号执行大量操作,则可能会触发每分钟操作数的速率限制。
限流和使用速率限制器
除了限制应用中的线程总数之外,您还可以在客户端实现速率限制器。这样可以确保进程和/或集群中的所有线程都受客户端特定 QPS 限制的约束。
请参阅 Guava RateLimiter,或为集群环境实现您自己的令牌桶算法。例如,您可以在分布式、低延迟的内存中数据存储区(例如 Redis 或 Memcached)中管理令牌,其中每个客户端在处理请求之前都会获取并使用令牌。如果令牌用尽,客户端会等待下一批令牌补充完毕。
队列
消息队列是用于分配操作负载的解决方案,同时还可以控制请求和使用者速率。可用的消息队列方案有许多:一些是开源的,一些是专有的,而且其中许多都支持各种不同的语言。
在使用消息队列时,您可以有多个推送消息到队列的生成者和多个处理这些消息的使用者。您可以在使用方端通过限制并发使用方的数量来实现限制,也可以为提供方或使用方实现速率限制器或限制器。
例如,如果消息使用方遇到速率限制错误,该使用方可以将请求返回到队列,并设置标准化的重试延迟时间(使用指数退避算法),然后更新共享速率限制器反馈环,以便所有使用方在从错误中恢复时自动降低其处理速率。