单位 8 / 11

速度限制和弹性错误管理

收益:

  • 可以解释速度限制 (RPM/ITPM/OTPM) 和 429 错误
  • 使用 retry-after 实现指数退避和重试
  • 正确分类处理常见HTTP错误码(400/401/429/500/529)

在生产环境中,没有任何 API 能够始终完美响应。有时您发送请求的速度太快而达到了限制;有时服务器暂时繁忙;有时你的要求从一开始就是错误的。可靠的集成与业余尝试的区别在于,它能够预测性地、自动地处理这些情况。在本单元中,您将了解速率限制 (RPM/ITPM/OTPM)、429 错误、指数退避重试以及常见 HTTP 错误代码的正确分类。目标:构建一个强大到用户永远不会注意到的流程。

什么是速度限制?

提供商限制交换机在给定时间段内可以完成的工作量。这种保护;它可以保护基础设施和您免受突然的成本爆炸的影响。常见的限制类型有以下三种:

  • RPM(每分钟请求数):每分钟请求数。
  • ITPM(每分钟输入令牌数):每分钟可以处理的输入令牌。
  • OTPM(Output Tokens Per Minute):每分钟可以产生的输出代币。

如果超出任何这些限制,提供商将拒绝请求并返回 429 错误代码。限制通常根据您的帐户级别(等级)而有所不同,并且可能会随着时间的推移而增加。

提示:您可以通过响应标头观察何时接近限制。大多数提供商都会使用 x-ratelimit-remaining-* 等标头报告您的剩余配额。监控这些值并限制前面的流量是防止出现 429 问题的最成熟方法。

正常 双线429服 [双线429服]

429(速率限制)是一个临时且可重试的错误。正确的响应是等待请求一段时间,然后重试。但持续的等待是不够的;如果所有人同时再次尝试,则会再次达到限制。解决方案是指数退避:每次失败的尝试都会以指数方式增加等待时间。

# 指数退避逻辑 试验 1 → 429 → 等待 1 秒 试验 2 → 429 → 等待 2 秒 试验 3 → 429 → 等待 4 秒 试验 4 → 429 → 等待 8 秒(+ 小随机“抖动”)... 最多 N 次试验后放弃并报告

添加一点随机性(抖动)可以防止请求在尝试同时重试时发生冲突。此外,429 响应通常带有“retry-after”标头:“在这么多秒内重试”。尊重这个称号,比盲目等待更准确。

注意:当你收到 429 时,“通过发送更多请求来强制它”会使情况变得更糟;限制继续被填满,并且没有请求通过。正确的反应是后退,而不是加速。好消息:大多数官方 SDK 都会自动重试 429 和服务器错误并进行回退 - 在手动安装之前使用 SDK 的这种行为。

HTTP 错误代码分类

并非每个错误都是相同的。关键区别:可以重试还是请求/身份问题?

代码

含义

可以再试一次吗?

正确反应

400

无效请求(格式/参数错误)

更正请求;不要再次发送相同的内容

401

身份验证错误(密钥无效/丢失)

修复键/标题

403

没有授权(无法访问模型/功能)

检查权限/范围

404

未找到(模型 ID/端点不正确)

正确的型号 ID/地址

第429章

超过速度限制

是的

撤退+之后重试

500

服务器错误

是的

再尝试撤退

第529章

服务器超载

是的

再尝试撤退

黄金法则:429、500、529是临时的;再次尝试退出。 400、401、403、404是请求/身份问题;再尝试也解决不了问题,而且还白费力气。您的代码必须区分这两组。

循序渐进:持久的通话

  1. 提交请求。如果成功,则继续。
  2. 对错误代码进行分类。可以再试一次吗?
  3. 如果可尝试:遵循重试后,应用指数退避 + 抖动,尝试有限次数(例如最多 5 次)。
  4. 如果没有尝试过:修复(格式/密钥)并停止;不要在循环中重复相同的错误请求。
  5. 考虑放弃。如果在n次尝试后仍然不成功,则向用户显示礼貌消息并记录该事件(跟踪单元11)。

# 鲁棒调用 伪codedene = 0repeat: response = request_at() if response.success: 返回响应 if response.code in [429, 500, 529] and try < 5: wait = retry_after ?? (2^尝试秒+抖动)睡眠(等待);尝试+= 1;再次 git if response.code in [400, 401, 403, 404]: save_error(response); return "请求必须修复" return "永久错误,稍后再试"

# 向用户礼貌地反馈(当重试次数用尽时)“我现在很忙,无法处理您的请求。请稍后重试,或者我已保存您的请求,准备好后我会回复您。”

弱提示/强提示(这里:错误信息设计)

# 弱(向用户显示原始错误)“错误 429:rate_limit_error”

# STRONG(用户友好、令人放心、建议采取行动)“系统出现暂时拥塞。我们已安全收到您的请求,正在自动重试。如果几秒钟内没有出现结果,您可以刷新页面。”

向最终用户透露原始技术错误既会破坏信任,也可能成为安全漏洞。在内部对错误进行分类,并向用户提供冷静、以行动为导向的消息;只需写下技术细节以供记录。

三个迷你箱

案例一——交通爆炸导致船只失事。活动当天,客户服务机器人收到了 429 的流量激增;代码中没有重试,每个错误都作为“错误”直接反映给用户。他们添加了指数回撤+重试后;对于相同的流量,请求通过延迟几秒钟,用户没有看到任何错误。

案例 2 — 在循环中尝试 400。由于模型 ID 无效,集成收到 404 错误,但将所有错误视为“暂时的”错误并在无限循环中重试;原木膨胀并产生不必要的负载。他们添加了错误分类:404 被认为是永久性的,循环被停止,模型 ID 被更正。教训:不要再犯每一个错误。

案例 3 — 从正面管理限制。数据丰富作业持续在 429 限制下运行。他们遵循 x-ratelimit-remaining 标头并根据配额限制流量。因此,他们保持着稳定的速度,略低于极限,没有跑出任何 429 秒;这项工作的完成更加可预测且更快。

常见错误

  • 429 增加速度:使情况变得更糟;转而撤退。
  • 重试每个错误:400/401/404 是永久性的;再尝试就是一种浪费。
  • 使用固定等待:造成冲突;使用指数+抖动。
  • 忽略“retry-after”:遵守提供商指定的时间是最准确的。
  • 向用户揭示原始错误:动摇信任,产生漏洞;里面分类一下。
  • 无限次重试:设置上限(例如重试5次);然后优雅地放弃。

更深入:队列、并发和断路器

忍受单一的欲望是第一步;真正的成熟是在不达到限制的情况下管理大量请求。三个概念在这里发挥作用。

队列:您将请求放入队列中,以受控的速度发送它们,而不是立即发送。队列可以平滑突发的流量:即使同时有 1,000 个请求到达,队列也会以低于限制的速率释放它们。这样您就可以防止 429,然后您就不必担心修复它。

并发限制:您可以限制同时“空中”的请求数量。无限的并行请求会快速满足 RPM 和 TPM 限制。合理的并发上限(例如不超过 10 个并发请求)既可以维持限制,又可以使系统可预测。

断路器:如果提供者不断返回 500/529,则您不必顽强地尝试每个请求,而是“断开电路”一段时间,然后快速使请求失败,而无需发送请求。等待一段时间后,重新打开电路并尝试。此模式可防止您的系统在临时提供程序故障时崩溃。

这三者共同建立了超越单个调用的重试逻辑的系统级弹性。小规模的话,SDK的自动重试就足够了;随着规模的增长,队列、并发和断路器变得不可或缺。它们都有相同的共同目标:向用户反映临时问题,而不是崩溃,而是几秒钟的隐形延迟。

综上所述

当超过速度限制(RPM/ITPM/OTPM)时返回429;这是一个临时错误,将使用重试后和指数退避 + 抖动重试。 500和529也是临时的; 400/401/403/404 是请求/身份问题,无法通过重试解决。强大的流程将错误分为这两组,尝试有限的次数,从前端监控限制并向用户显示平静的消息。

应用任务

考虑一下你的整合。 (1) 列出您可能遇到的错误代码,并将其分为“可重试/永久”。 (2) 写下您的指数回调计划(初始保持、系数、上限、抖动)。 (3) 指定如何使用retry-after 标头。 (4) 编写重试次数耗尽后向用户显示的礼貌消息。

清单

  • [ ] 我可以解释 RPM/ITPM/OTPM 限制和 429。
  • [ ] 我可以应用指数撤退+抖动+重试后的逻辑。
  • [ ] 我可以将错误代码分类为可重试/永久。
  • [ ] 我知道我们不应该尝试每一个错误。
  • [ ] 我可以向用户显示一条冷静的、面向行动的消息,而不是原始错误。