如果在任何5分钟的时间间隔内有5个错误,我想通过IP阻止所有请求,比如说,阻止10分钟。我正在考虑一种方法来存储这些数据,这种方法对性能的影响最小。
特别是关于如何设计数据库表和存储数据。
如果我为IP制作一个固定的表作为主表,例如使用mysql:
ip int(10) unsigned, primary key (ip)
attempts int(5),
lastaccess timestamp default current_timestamp
那么它将不足以积累尝试。。。
另一方面,如果我用时间戳记录所有不正确的尝试,例如:
ip int(10) unsigned,
lastaccess timestamp default current_timestamp,
primary key (ip,lastaccess)
然后在5分钟的时间间隔内倒计时,表可能会随着所有这些数据而变得非常巨大,并减缓系统。。。它还需要维护。
那么,你能给我一些更方便的建议吗?。。。
我会存储最后x次尝试的IP地址和时间戳。在数据库、memcached类型的存储中,或者可能只是一些平面文件,这取决于您预期的流量。
如果是数据库,您可以很容易地查询类似COUNT(timestamps) GROUP BY ip WHERE timestamp [within last 5 minutes]
的内容,偶尔也可以使用简单的DELETE WHERE timestamp [over 5 minutes ago]
来清理数据库。清理可能发生在cron作业中,也可能发生在垃圾收集类系统中的每x个请求中。
如果是memcached或平面文件,请将时间戳存储在FIFO数组中,即不断截断的简单array(123456..., 123456..., ...)
。
试试看。如果你非常担心the table could potentially grow very huge with all this data
,我建议你使用redis
为每个用户生成一个唯一的ID[很可能是IP,但考虑来自同一网络的用户。例如:来自一个组织的用户将具有与所有传出请求关联的相同IP,即使是来自不同机器的请求]和使用字符串数据类型,其中键为唯一ID,值为计数器[存储尝试次数]。
DOC中String
的一个用例
使用INCR系列中的命令将字符串用作原子计数器:INCR,decc,INCRBY。
此外,字符串数据类型支持过期。因此,您生成的所有密钥都将有5分钟的到期时间,一旦达到时间限制,就会自毁。您只需读取计数器值即可确定是否阻止用户。现在你不必担心记录的数量随着一天的进行
Redis将您的所有数据存储在内存中。我认为您可能也会获得一些性能改进