繁忙的发送方可能在所有消息入队之前就用完了请求配额。读取剩余配额可以在更多调用被拒绝之前提前降速。
Bird 如何确定我的限制?
Bird 先应用基础速率,再叠加套餐提升量,最后应用相关分组的覆盖值。覆盖值会替换其他值。
相关端点共享一个分组。耗尽发送分组的配额不会同时耗尽用于读取状态或管理 Webhook 的其他分组。
每个配额的作用范围取决于操作类型:
| 分组 | 谁共享该配额? |
|---|---|
| 产品发送 | 该组织内该产品的所有凭证。 |
| 管理类读取、列表和写入 | 该组织内同一操作凭证发出的请求。 |
| 未认证的登录或密码重置 | 来自同一客户端 IP 的请求。 |
未认证的限制使用固定阈值。请参阅速率限制指南了解各端点所属的分组。
发送限制计数的是请求数,而非收件人数。一个批量请求可以将多条消息入队。其所属分组可能有不同的配额。
比较实时配额和你能合并的收件人数量,再决定是否切换端点。只包含一个收件人的批量请求可能不会带来吞吐量提升。
如何读取响应请求头?
读取 RateLimit-Policy 获取配额和窗口信息,再读取 RateLimit 获取剩余请求数和距离重置的时间。
示例:
RateLimit-Policy: "email_send";q=1000;w=60
RateLimit: "email_send";r=842;t=35
此示例允许每 60 秒窗口内发送 1,000 个请求。剩余 842 个请求,距离重置还有 35 秒。
这些数字仅用于说明请求头,并非承诺的配额。请读取返回给你客户端的实际值。
| 字段 | 含义 |
|---|---|
| 引用名称 | 该策略适用的分组。 |
q | 每个窗口允许的请求数。 |
w | 窗口时长,单位为秒。 |
r | 剩余请求数。 |
t | 距离重置的秒数,不是时间戳。 |
一个响应可以携带多个策略。安排下一个请求时需考虑所有适用的策略。
速率限制失败会返回什么?
API 配额耗尽时返回 429 Too Many Requests,Retry-After 以秒为单位给出延迟。速率限制请求头标识了耗尽的分组,其剩余配额为 r=0。
错误响应包含以下字段:
{
"error": {
"type": "rate_limit_error",
"code": "E01003",
"name": "RateLimited"
}
}
在处理逻辑中匹配 type 或 code。人类可读的 message 可能会变化,但不会改变恢复操作。
我的客户端应如何处理 429?
等待 Retry-After 指定的时间,然后使用有上限的退避策略重试。重复同一写操作时保留相同的幂等键。
协调使用同一分组配额的工作线程。一个工作线程上次收到的响应无法反映其他工作线程此后提交的请求。
随着剩余配额下降逐步降速。保留重试路径以应对并发流量。控制节奏可以减少失败,但无法保证没有请求收到 429。
Bird SDKs 处理 429 重试和 Retry-After。它们不会在你的所有进程之间协调共享队列。
如果配额对于工作负载仍然不足,请联系 Bird 申请覆盖值。创建更多密钥不会增加组织级别的发送限制。
被速率限制的请求是否已执行了任何操作?
Bird 在执行请求的操作之前就会拒绝被速率限制的请求。该拒绝不会消耗其幂等键。等待后使用相同的键重试即可。
如果限流器无法评估限制,会放行请求。因此,评估配额时出现问题本身不会产生 429。
对其他故障也要保持幂等处理。服务器错误或响应丢失可能发生在写操作已经开始之后。
简而言之
从响应中读取配额。
适用的限制取决于分组、套餐和可能存在的覆盖值。写死一个固定数字可能会出错。
协调共享配额的发送方。
发送限制在整个组织范围内生效,因此使用不同的密钥不会创建独立的发送配额。
重试 429 之前先等待。
Retry-After以秒为单位给出延迟时间。限制重试次数。对同一写操作保留相同的幂等键。将请求头视为共享状态。
剩余请求数可能被其他工作线程消耗,因此控制节奏可以减少速率限制失败,但无法完全消除。