为什么API请求会因为“速率限制”而被拒绝

应用程序接口(API)的请求,之所以会因为“速率限制”而被拒绝,其根本原因在于服务提供方,为了保障其后端系统的“稳定性”与“可用性”,而主动采取的一种“流量控制”与“自我保护”机制。一个对外开放的接口,是一种有限的、需要被所有用户公平共享的“公共资源”。如果没有速率限制,任意一个客户端,都可能,因为恶意的攻击或无意的程序缺陷,在短时间内,发起海量的请求,从而耗尽服务器的计算、内存或网络资源。这套机制的运作,主要涉及五大核心因素:为了保护后端服务的“稳定性”与“可用性”、防止恶意的“拒绝服务”攻击、保障所有用户的“公平”访问权益、实现服务成本的“可控性”与“商业化”、以及引导开发者形成“良性”的调用习惯

为什么API请求会因为“速率限制”而被拒绝

其中,为了保护后端服务的“稳定性”与“可用性”,是最核心、最不容妥协的原因。一个接口服务器,其所能处理的并发请求数量,是存在物理上限的。速率限制,就如同在一条高速公路的入口处,设立了一个“收费站”,它通过有节奏地,控制进入车流的速度,来确保主干道,永远不会,因为车辆过多,而陷入“交通瘫痪”,从而,保障了对所有用户的、整体的服务质量。

一、为何要“限制”:从“无限畅饮”到“按需配给”

在探讨“速率限制”的具体技术实现之前,我们必须首先,从“服务提供方”的视角,去深刻理解“为何‘限制’是必要的”。

1. 应用程序接口是一种“共享资源”

一个对外提供服务的应用程序接口,其背后,所依赖的,是一整套复杂的、由服务器、数据库、缓存系统、网络带宽等共同构成的、成本高昂且容量有限的“计算资源”。当一万个不同的开发者,都在调用你的接口时,他们实际上,是在共享这同一套计算资源。

2. “公地悲剧”的重现

如果,对这种共享资源的使用,不加任何限制,那么,经济学中经典的“公地悲剧”现象,就将不可避免地,在数字世界中重演。

一个“行为不佳”的客户端:它可能,因为一个程序缺陷(例如,一个没有终止条件的循环),而在无意中,向你的服务器,发起了每秒数千次的请求。

一个“恶意”的攻击者:他可能会,通过组织大量的“僵尸网络”,来对你的接口,发起一次有预谋的“分布式拒绝服务”攻击。

无论是“无意”还是“恶意”,这种无节制的资源消耗,其最终的结果,都是一样的:服务器因为不堪重负而响应缓慢,甚至彻底崩溃。这导致,所有其他那些“行为良好”的、正常的用户,其合法的、低频的请求,也同样,无法得到服务

3. 速率限制的“四大战略目标”

因此,服务提供方,实施“速率限制”,并非一种“不友好”的行为,而是一种对所有用户负责的、保障服务长期健康的、必要的“治理”手段。其背后,通常,有四大战略目标:

服务保护:这是最首要的目标。防止因“流量洪峰”而导致的系统过载和崩溃。

安全防护:有效地,缓解“分布式拒绝服务”攻击和“密码暴力破解”等恶意行为。

保障公平性:确保没有任何一个单一的用户或应用,能够“垄断”和“霸占”所有的服务资源,从而保障了所有用户的、公平的访问权益。

支撑商业模式:速率限制,也是一种常见的“商业化”手段。服务提供方,可以为“免费版”用户,提供一个较低的速率限制;而为“付费版”或“企业版”用户,提供一个远高于前者的、更宽松的限制。

二、核心算法一:“令牌桶”

“令牌桶”,是实现速率限制的、最常用、也最灵活的一种算法。

1. 工作原理

我们可以将“令牌桶”的工作原理,分解为以下几个步骤:

一个固定容量的“桶”:系统,在内存中,为每一个需要被限制的用户或接口,都维护了一个“桶”。这个桶,有一个固定的“容量上限”(例如,100个令牌)。

匀速放入的“令牌”:系统,会以一个固定的、预设的速率(例如,每秒向桶里放入5个令牌),持续地,向这个桶里,添加“令牌”。

满了则“丢弃”:如果,在某个时刻,桶里的令牌,已经达到了“容量上限”,那么,新生成的令牌,就会被直接“丢弃”,桶里的令牌数,不会再增加。

请求消耗“令牌”:当一个用户的接口请求,到达服务器时,它必须,首先,尝试,从属于它的那个“令牌桶”中,“获取”一个令牌。

有令牌则“放行”,无令牌则“拒绝”:如果,此时,桶里,有可用的令牌,那么,请求,就会被允许通过,并消耗掉一个令牌。如果,桶里,已经“”了,那么,这个请求,就会被立即“拒绝”,并返回一个“速率超限”的错误。

2. 核心特性:允许“突发流量”

“令牌桶”算法的最大优点,在于它的“灵活性”和对“突发流量”的友好性。因为,只要桶里,还有剩余的令牌,那么,即便是,在100毫秒内,瞬间,到达了100个请求,这些请求,也都能被“立即处理”,而不会被强制性地“排队”。它,允许用户,在需要时,“透支”未来一段时间的流量。

三、核心算法二:“漏桶”

“漏桶”算法,是另一种经典的、与“令牌桶”思路相反的限流算法。

1. 工作原理

一个有固定流出速率的“桶”:我们可以,将这个算法,想象成一个底部,有一个“固定大小”的“洞”的“漏斗”。

请求进入“队列”:所有到达的接口请求,都如同“水流”,被注入到这个“漏斗”之中,并在内部,形成一个“先进先出”的队列。

以“固定速率”处理:无论,水流注入的速度,有多快,这个漏斗,永远,都只会以那个“洞”所决定的、固定的、恒定的速率,向外“漏出”水流(即处理请求)。

满了则“溢出”:如果,水流注入的速度,在一段时间内,持续地,大于“漏出”的速度,那么,漏斗,就会被逐渐“装满”。一旦装满,后续,所有新注入的水流(请求),都将“溢出”,即被“拒绝”。

2. 核心特性:平滑“流量

“漏桶”算法的最大优点,在于它能够,强制性地,将所有不规则的、脉冲式的“上游”流量,都“整形”和“平滑”为,一股速率完全固定的、可预测的“下游”流量。这对于保护那些处理能力有限、且对“瞬时冲击”非常敏感的、后端的“核心业务系统”,具有极佳的保护效果。

四、如何“感知”限制:协议与通信

作为一个接口的“调用方”,我们如何,才能,在代码中,“感知”到速率限制的存在,并优雅地,应对它呢?一个设计良好的接口,会通过标准的网络协议,向我们,清晰地,传递这些信息。

1. 状态码:429 Too Many Requests

当你,因为速率超限,而被拒绝时,服务器,不应返回一个模糊的500(服务器内部错误)。标准的、语义化的做法,是返回一个429状态码,它明确地告诉你:“你发送的请求,太多了”。

2. 响应头:获取“配额”信息

更重要的是,在每一次的成功响应中,一个友好的接口,都应通过“响应头”,来向你,实时地,同步你当前的“配额”信息。常见的响应头字段包括:

X-RateLimit-Limit:在一个时间窗口内,你被允许的“总请求次数”。(例如,3600,表示每小时3600次)

X-RateLimit-Remaining:在当前的时间窗口内,你“剩余的”可用请求次数。(例如,1500

X-RateLimit-Reset:本次时间窗口,“将会重置”的、世界标准时间的“时间戳”。(例如,1661385600

一个专业的、负责任的接口调用者,其代码,应该主动地,去读取和解析这些“响应头”,并依据“剩余配额”,来动态地,调整自己后续的请求发送速率

五、客户端的“优雅”应对策略

当我们的程序,收到了一个429错误时,最糟糕的做法,就是“立即重试”。这只会,导致我们,立即,收到第二个429错误,并进一步,加剧服务器的压力。

1. 指数退避与重试

“指数退避”,是业界公认的、在面对“速率限制”时,最标准、最优雅的“重试”策略

流程

当收到一个429错误后,不要立即重试,而是等待一个随机的、较短的时间(例如,1秒 + 随机几十毫秒)。

然后,进行第一次重试。

如果,依然失败,那么,就将等待时间,“翻倍”(例如,等待2秒),再进行第二次重试。

如果,还失败,就将等待时间,再次翻倍(例如,等待4秒),进行第三次重试……

在重试了若干次(例如,5次)之后,如果依然失败,就应放弃,并将该任务,标记为“失败”,交由人工处理。

为何有效?:“指数级”的等待时间增长,能够确保,我们的程序,在遇到持续的限制时,能够“礼貌地、快速地”,降低对服务器的访问压力。而“随机性”的加入,则避免了,当有成千上万个客户端,在同一时刻,都被限制时,它们,又在“同一个”精确的未来时间点,发起“雪崩”式的重试。

2. 客户端侧的“自我限流”与“缓存”

自我限流:在我们的调用代码中,主动地,实现一个“客户端侧”的限流器(例如,一个简单的“令牌桶”),确保我们自己,向外发送请求的速率,永远不会,超过接口文档中所规定的上限。

缓存:对于那些“查询类”的、其返回结果,在一段时间内,不会发生变化的接口,我们应该,在自己的应用层,对其返回结果,进行“缓存”。这能够极大地,减少不必要的、重复的接口调用。

在设计复杂的、需要与多个外部接口进行交互的系统时,对其“速率限制”和“容错策略”的设计,是**API网关**或架构评审中的一个核心环节。

常见问答 (FAQ)

Q1: 为什么应用程序接口服务提供商要设置速率限制?

A1: 主要有四个目的:保护服务稳定(防止过载)、保障用户公平(防止资源垄断)、抵御恶意攻击(如拒绝服务攻击)、以及支撑商业模式(例如,为付费用户,提供更高的速率限制)。

Q2: 429503这两个错误码有什么区别?

A2: 429 Too Many Requests(请求过多),是一个“客户端”侧的错误。它明确地,表示“你,作为调用者,发送的请求,太快了”。而503 Service Unavailable(服务不可用),则是一个“服务器”侧的错误。它表示“我,作为服务提供方,因为过载或维护,暂时,无法处理任何请求,请稍后再试。”

Q3: 如果我的业务确实需要很高的请求速率,该怎么办?

A3: 首先,应仔细阅读接口的文档,看其是否,为“付费”或“企业级”用户,提供了更高等级的速率限制方案。其次,可以主动地,联系接口的“提供方”,说明你的业务场景和需求,看是否,可以为你,申请一个“特批”的、更高的配额

Q4: 什么是“指数退避”?

A4: “指数退避”,是一种网络通信中,用于“失败重试”的经典算法。其核心思想是,在每一次重试失败后,都将下一次重试的“等待间隔”,进行“指数级”的增加(例如,1秒、2秒、4秒、8秒…),从而,在出现持续性问题时,能够智能地、快速地,降低对服务器的请求压力。

文章包含AI辅助创作,作者:mayue,如若转载,请注明出处:https://docs.pingcode.com/baike/5215125

(0)
mayuemayue
免费注册
电话联系

4008001024

微信咨询
微信咨询
返回顶部