我有一个网络服务,我需要限制客户端可以执行的交易数量。事务正在使用正确的参数访问 URL。每个客户端每秒可以执行的事务数量不同。客户端将根据 IP 地址或 URL 中的参数进行识别。
客户端可以执行的最大 TPS 将保存在数据库或任何其他可配置的方式中。我知道可以编写 servlet 过滤器来执行此操作。过滤器将计算每秒请求数并建立数据库连接以获得客户端的最大 TPS,并在达到 TPS 时拒绝请求,因为它会进一步减慢应用程序响应。但这在 DOS 攻击期间将无济于事。有没有更好的办法?
最佳答案
我不得不做同样的事情。我就是这样做的。
1) 我有一个用于跟踪 IP 请求的数据模型。它主要通过使用一些允许我添加新请求的数学来跟踪请求率,并且该 IP 的新请求率将很快被重新计算。让我们调用这个类 IpRequestRate
。
2) 对于发出请求的每个唯一 IP,IpRequestRate
实例被实例化。每个 IP 只需要一个实例。它们被放入 HashMap 中以进行快速检索。如果有新的 IP 进来,则会为其创建一个新的 IpRequestRate
实例。
3) 当请求进来时,如果 HashMap 中已经有 IpRequestRate
的实例,那么我会将新请求添加到该实例并获取新速率。如果速率高于某个阈值,则不会处理该请求。
4) 如果请求者不小心超出了该阈值,则速率将迅速降至阈值以下。但是,如果它是一个真正的 DOS,或者在我的情况下,尝试访问帐户的次数太多(由于黑客),那么他们的速率将需要更长的时间才能降至阈值以下;这就是我想要的。
5) 我不记得我是否有清除旧 IP 的清理线程,但这在某些时候是需要的。您可以使用 EhCache 作为您的 HashMap,这样它就可以自动为您执行此操作。
6) 它工作得非常好,我考虑将其开源。但它真的很简单,而且很容易重现。您只需要正确地进行数学运算即可。获得速率的数学很容易使其准确,但如果您希望它更快,则有点棘手,因此当将新请求添加到 IpRequestRate 时,CPU 不会花费太多时间来计算新速率
。
这是否回答了您的问题,或者您是否需要有关如何在您的服务器中设置过滤器的更多信息?
编辑:WRT DOS,在 DOS 攻击期间,我们希望浪费尽可能少的资源。如果所有可能的 DOS 检测都应该在负载平衡器或反向代理或网关或防火墙中完成。
如果我们想做每个 IP 的最大传输速率,它存储在数据库中,那么我将只缓存最大传输速率。这可以在不对请求进行数据库查找的情况下完成。我会改为将表加载到 HashMap 中。
1) 在应用程序开始时,比如在 init() 方法中,我会将表加载到将 IP 映射到 maxTransmissionRate 的 HashMap 中。
2) 当请求到来时,尝试从 HashMap 中获取 maxTransmissionRate。如果不存在,则使用默认的 maxTransmissionRate。
3) 在 init() 期间,启动一个 ScheduleExecutorService 以在某个期望的时间间隔更新 HashMap,以保持 HashMap 的新鲜度。这是 ScheduleExecutorService 的链接,它并不难。 http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html
4) 我们应该使用哪种 HashMap 实现?如果我们使用常规的 HashMap 那么当它被 ScheduledExecutorService 更新时我们就会遇到问题。我们可以使用同步的 HashMap,但这会锁定 HashMap 并在并发请求期间损害性能。所以我会选择 ConcurrentHashMap,它是为速度和多线程环境设计的。您可以放心地在单独的线程上安全地更新 ConcurrentHashMap。
如果您应用此技术,那么它仍然是防止 DOS 并支持每个客户端 maxTransmissionRate 的可行解决方案。
关于java - 在没有 DOS 漏洞的 tomcat 服务器中限制每个客户端的每秒事务数 (TPS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31716128/