背景
Echo Nest有一个限速API。使用API密钥识别的应用程序可以每分钟最多进行120个REST调用。服务响应包括上一分钟内所做调用的总数估计;滥用API(超过限制)可能导致API密钥被吊销。
当从单个机器(为客户提供服务的Web服务器)使用时,很容易控制访问-服务器完全了解请求历史记录并可以正确地进行调节。
但是,我正在开发一个程序,其中分布式、独立的客户端并行发出请求。
在这种情况下,什么是最佳解决方案就不太清楚了。而且通常问题看起来是不可解的-如果超过120个没有先前历史记录的客户端同时发出初始请求,那么速率将超过限制。
由于这是一个个人项目,客户端使用预计会间歇性地发生(爆发式),而且我的项目从未取得过巨大的成功,因此这不被认为是一个巨大的问题。更可能的问题是,在较短的时间内有少量客户端希望尽可能快地发出大量请求(例如,当客户端第一次启动时,可能需要异常地发出数千个请求 - 可能会有两个客户端在同一时间启动,因此它们必须合作共享可用带宽)。鉴于上述所有情况,对于客户端来说,哪些适当的算法可以使其适当地限制速率?请注意,由于API返回了“所有”客户端在最后一分钟内的请求总数,因此有限的合作是可能的。
当前解决方案
我的当前解决方案(在撰写本文时 - 一个更好的方法已经给出作为答案)非常简单。每个客户端都记录了上次调用的时间以及在该调用中由API报告的最近一分钟内所做的调用数量。如果调用数量小于60(限制的一半),则客户端不进行限流。这允许快速突发小数量的请求。
否则(即存在更多先前的请求时),客户端会计算其需要工作的限制速率(即
period = 60 / (120 - 先前请求数量)
),然后等待前一次调用和当前时间之间的间隔超过该期间(以秒为单位;每分钟60秒;每分钟最多120个请求)。这有效地限制了速率,以便如果它是单独操作的,它不会超出限制。但上述方法存在问题。仔细思考后,您会发现对于大量请求,单个客户端会振荡并且无法达到最大吞吐量(部分原因是由于“初始爆发”突然“超出窗口”,部分原因是算法未充分利用其历史记录)。多个客户端将在一定程度上合作,但我怀疑这不是最优解决方案。
更好的解决方案:
我可以想象一个更好的解决方案,它使用客户端的完整本地历史记录,并使用隐马尔可夫模型来模拟其他客户端。因此,每个客户端都将使用API报告来模拟其他(未知的)客户端,并相应地调整其速率。
我还可以想象一种算法,适用于单个客户端,它从小突发无限行为逐渐过渡到适用于许多请求的最佳限制行为,而不会引入振荡。
这样的方法存在吗?有人可以提供实现或参考文献吗?有人能想到更好的启发式算法吗?
我想这在某个领域是一个已知的问题。在哪个领域?排队理论?
我还猜测(请参见早期评论)没有最优解,可能有一些传统/被接受的启发式算法,在实践中效果很好。我很想知道...目前我正在努力在已知的网络协议中识别类似的问题(如果是这样,我想Perlman会有一些美妙的解决方案)。
我也对需要中央服务器来帮助协作的解决方案感兴趣(在未来,如果程序变得流行,这点程度上的兴趣)。
免责声明
这个问题并不是要批评Echo Nest;他们的服务和使用条件非常好。但是,我越想如何最好地使用它,它就变得越复杂/有趣...
此外,每个客户端都有一个本地缓存用于避免重复调用。
更新 可能相关的论文。
N
次请求,并在接下来的t
秒内获得允许进行K <= N
次请求。然后,如果需要,服务器可以根据客户端想要进行的请求数量和请求原因对客户端进行优先处理。 - Steve Jessop