【问题标题】:Implementing a quota system to limit requests in a web based app实施配额系统以限制基于 Web 的应用程序中的请求
【发布时间】:2017-06-14 05:08:13
【问题描述】:

我想将我的用户限制为 25k/每小时/每天/任何请求。

我的第一个想法是简单地使用 mysql 并在 users 表中有一个列,我将在其中存储请求,并且每次用户发出请求时我都会增加这个计数器。这种方法的问题在于,有时您最终会同时在列中写入,并且您会从 mysql 中遇到死锁,所以这并不是一个真正的好方法,不是吗?

另一种方法是,而不是增加列的计数器,而是在单独的表中插入日志记录,然后在给定的时间跨度内计算这些记录,但这样你可以很容易地得到百万记录表和查询可能太慢了。

使用 RDBMS 时要考虑的另一个方面是,在每次请求时,您都必须从数据库中计算用户配额,这可能需要时间,具体取决于上述任何一种方法。

我的第二个想法,我想使用 redis/memcached 之类的东西(不确定替代方案或其中一个更快)并将请求计数器存储在那里。这足以查询和增加计数器,肯定比 RDBMS 更快,但我还没有尝试过处理大量数据,所以我还不确定它会如何执行。

我的第三个想法,我会将配额数据保存在内存中的映射中,例如map[int]int,其中键是 user_id,值是配额使用情况,我会使用互斥锁保护映射访问.这将是所有解决方案中最快的解决方案,但是如果由于某种原因您的应用程序崩溃,您会丢失与某些用户所做的请求数量相关的所有数据,您会怎么做。一种方法是在崩溃时捕获应用程序并循环遍历地图并更新数据库。这可行吗?

不确定上述任何一种方法是否正确,但我愿意接受建议。

【问题讨论】:

  • 既然你在谈论一个 web 应用程序,一个简单且明显更轻量级的解决方案是使用 HAProxy 来执行此操作,它优化了用于保存大量计数器的内存结构,我相信是 @987654321 @.

标签: mysql go redis memcached quota


【解决方案1】:

当您尝试同时更新一行时,我不确定您所说的“从 mysql 获取死锁”是什么意思。但是一个简单的update rate_limit set count = count + 1 where user_id = ? 应该可以满足您的需求。

就我个人而言,我在使用 Redis 进行速率限制方面取得了巨大成功。有很多资源可以帮助您了解适合您的用例的方法。这是我刚刚看了一眼,似乎可以正确处理事情的一个:https://www.binpress.com/tutorial/introduction-to-rate-limiting-with-redis/155。使用管道 (MULTI) 或 Lua 脚本可能会让事情变得更好。

【讨论】:

  • 感谢您的回复,我手头没有确切的错误代码,但是当我们执行并行请求时会出现问题,并且碰巧有 2 个或更多请求尝试在同时,那么您的示例将失败。我认为需要有一种方法来进行原子更新,但还没有找到。谢谢redis链接,我去看看。
  • @Twisted1919 这不是死锁。原子更新很好,并且锁争用是透明处理的。当两个事务各自尝试获取另一个事务已经持有的锁时,就会发生死锁,而这不会在一行中的一列的简单原子更新中发生。
【解决方案2】:

您可以将map[int]int 保留在 RDBMS 中,也可以不时地保留在文件系统中并保留在延迟函数中。您甚至可以将其用作缓存而不是 redis。当然,无论如何它都会比每次请求都连接到第三方服务更快。您也可以简单地将计数器存储在用户端的 cookie 中。聪明的用户可以清除cookies of douse,但它有那么危险吗?您还可以在cookies中提供一些识别信息,使清除变得不舒服。

【讨论】:

    猜你喜欢
    • 2023-03-07
    • 2012-10-01
    • 2018-04-25
    • 1970-01-01
    • 2018-03-27
    • 2015-03-14
    • 2013-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多