我有一个带有负载均衡器的Web服务,可以将请求映射到多台计算机。这些请求中的每一个都最终向外部API发送http调用,因此我想对我发送给外部API的请求数量进行速率限制。
我目前的设计:
当我使用多台计算机时,这不起作用,因为每台计算机都有自己的队列和速率限制器。例如:当我将速率限制器设置为10,000个请求/天,并且我使用10台机器时,我将最终在满负荷下处理100,000个请求/天,因为每台机器每天处理10,000个请求。我想率限制,以便每天只处理10,000个请求,同时仍然负载平衡这10,000个请求。
我正在使用Java和MYSQL。
答案 0 :(得分:2)
答案 1 :(得分:0)
为什么不在数据库中实现一个简单的计数器并让API客户端实现限制?
用户代理 - > LB - >您的服务 - >问 - >您的Q消费者 - > API客户端 - >外部API
API客户端检查数字(今天),您可以实现您喜欢的任何速率限制算法。例如,如果数字是> 10k客户端可能只是爆炸,有异常将消息放回队列并继续处理直到今天是明天,并且所有排队的请求都可以得到处理。
或者你可以实现一个分层限制系统,例如平坦直到8k,然后每个节点每5秒发送一条消息,直到达到极限,此时你可以将503错误发送回用户代理。
否则你可以走复杂的路线并实现一个分布式队列(例如AMQP服务器)但是这可能无法完全解决问题,因为你唯一的控制机制会受到限制,以至于你永远不会比低于最大值的东西更快地处理每天限额。例如,你的最大限制是10k,所以你永远不会比每8秒钟更快一次。
答案 2 :(得分:0)
你说的两件事是:
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。与往常一样,这两者都有权衡,因此您最了解您的使用案例。
答案 3 :(得分:0)
如果您对使用库/服务https://github.com/jdwyah/ratelimit-java不感兴趣,则可以轻松获得分布式速率限制。
如果性能最受关注,您可以在请求中获得多于1个令牌,这样您就不需要向限制器发出100k次API请求。有关详细信息,请参阅https://www.ratelim.it/documentation/batches