如何在多台机器上实施单一速率限制?

11
我有一个Web服务,使用负载均衡器将请求映射到多台机器。每个请求最终都会发送HTTP调用到外部API,因此我希望限制发送到外部API的请求数量。
我的当前设计如下:
  • 服务在内存中拥有一个队列,用于存储所有接收到的请求
  • 我限制了我们从队列中获取和处理请求的频率。
但是当我使用多台机器时,这种方法就行不通了,因为每台机器都有自己的队列和速率限制器。例如:当我将速率限制器设置为每天10,000个请求时,并且我使用10台机器,我将以满负荷处理每天100,000个请求,因为每台机器都会处理10,000个请求/天。我希望进行速率限制,以便只处理10,000个请求/天,同时仍然对这10,000个请求进行负载平衡。
我正在使用Java和MYSQL。

显而易见的解决方案是创建一个公共队列或公共路径到HTTP API。公共路径可以是一种代理软件,它会限制每个基础(在您的情况下为每天)的请求数量。此外,您能否在API端创建队列? - dkasipovic
4个回答

2
  1. 使用 memcached 或 redis 记录每个客户端的 API 请求计数器,检查每个请求是否超出了速率限制。
  2. 如果您认为在每个请求中进行检查太昂贵,则可以尝试使用 Storm 处理请求日志,并异步计算请求计数器。

1
您提到的两件事是:
1)"I would like to rate limit so that only 10,000 requests get processed/day"
2)"while still load balancing those 10,000 requests."

首先,看起来你正在使用分治法,其中来自终端用户的每个请求都会映射到 n 台机器中的一台。因此,为了确保仅在给定时间范围内处理 10,000 个请求,有两个选项:

1)实现一个组合器,将所有 n 台机器的结果路由到另一个端点,外部 API 便能够访问它。该端点能够计算正在处理的作业数量,如果超过了阈值,则拒绝作业。

2)另一种方法是将您已处理的作业数量作为变量存储在数据库内。通常需要检查在初始请求作业之前(甚至还没将其传递给任何一台机器),通过数据库中的值检查是否已达到阈值。如果已达到阈值,则在开始时拒绝作业。这与适当的消息配合使用可以提供更好的终端用户体验。

为了确保这10,000个请求仍然被负载均衡,以便没有1个CPU处理比任何其他CPU更多的作业,您应该使用简单的轮询方法将作业分配到m个CPU上。与bin /分类方法相比,使用轮询可以尽可能均匀地分配作业请求到n个CPU上。轮询的缺点是,根据您正在处理的作业类型,随着规模的扩大,您可能会复制大量数据。如果您担心这一点,您应该考虑实现一种形式的局部敏感哈希(LSH)函数。虽然良好的哈希函数尽可能均匀地分布数据,但LSH使您暴露于某些属性偏斜的高概率发生的情况下,一个CPU处理比其他CPU更多的作业。像往常一样,两者都有权衡,因此您最了解自己的用例。

0

0

为什么不在你的数据库中实现一个简单的计数器,并让 API 客户端实现限流呢?

用户代理 -> LB -> 你的服务 -> Q -> 你的 Q 消费者 -> API 客户端 -> 外部 API

API 客户端检查数字(今天的请求数),然后您可以实现任何您喜欢的限制算法。例如,如果数字大于10k,则客户端可能会崩溃,将消息放回队列,并继续处理请求,直到今天变成明天,所有排队的请求都可以得到处理。

或者,您可以实现分层限流系统,例如平坦地限流到8k,然后每个节点每5秒钟发送1条消息,直到达到限制,此时可以向用户代理发送503错误。

否则,您可以采用复杂的方法,并实现分布式队列(例如 AMQP 服务器)。但是,这可能并不能完全解决问题,因为您唯一的控制机制就是限流,以便您永远不会比每天的最大限制更快地处理。例如,您的最大限制是10k,因此您永远不会以每8秒钟发送1条消息的速度进行处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接