我正在尝试使用非常基本的j2ee servlet和MySQL构建HTTP API。
有一个要求,我必须限制特定用户调用我们服务器的频率。假设当我检测到他们的TPS限制为20时,一旦他们在同一秒进行21次通话,我就需要返回错误。
到目前为止,我知道有两种方法可以实现:
=========================
UserId | Datetime | Count
=========================
-- On every calls made (there's unique index on userId + datetime)
INSERT INTO hitrate (userId, datetime, count) VALUES (123, NOW(), 1)
ON DUPLICATE KEY UPDATE count = count + 1;
-- Before every call, check
SELECT count FROM hitrate where userId = 123 and datetime = NOW();
我所要做的就是一旦发现计数超过20,就返回一个错误。缺点是它涉及太多的数据库事务,并且每个事务之间的等待时间都被杀死,因此这种方法不是很大。
private static HashMap<String, Integer> hitrate = new HashMap<String, Integer>();
String tag = inUsername + "-" + (System.currentTimeMillis() / 1000);
Integer count = hitrate.get(tag);
if (count == null) {
hitrate.put(tag, 1);
} else {
if (count >= 20) {
// return error;
} else {
count++;
hitrate.put(tag, count);
}
}
在所需的资源和时间方面,这种方法效率更高。但是问题是我的哈希图会越来越大。
有人有管理此方面的经验,并且知道采用这种逻辑的最佳方法是什么吗?
谢谢。
答案 0 :(得分:0)
您似乎正在寻找一种叫做“速率限制器”的东西。 这可以通过多种方式来完成。 例如,著名的Guava库中有一个限速器
在RDBMS上实现它不是IMO的好方法,因为数据库调用非常昂贵,尽管它对于小型设置来说是可行的解决方案。
但是,与您提供的哈希图解决方案和Guava方法相比,如果您的设置中有更多服务器集群并且想要限制用户访问权限,而无论用户调用哪个服务器,它都将起作用。 / p>
如果您具有这种设置,则必须使用“分布式”解决方案。
一种这样的解决方案已经超过Redis。
甚至还有一个库:ratelimitj。