【问题标题】:Monitoring and killing blocked threads in Java在 Java 中监视和杀死阻塞的线程
【发布时间】:2011-08-16 09:41:17
【问题描述】:

在我目前正在编写的基于 servlet 的应用程序中,我们为读取器和写入器提供了单独的线程类。使用LinkedBlockingQueue<byte[]> 将数据从写入器传输到多个读取器,因此如果没有从写入器获取的新数据,读取器会安全地阻塞。问题是,如果这些读取器线程服务的远程客户端终止连接,Tomcat 不会抛出损坏的管道,除非写入器发送新数据并尝试将这个新块传输到远程客户端。换句话说,可以对我们的服务执行以下攻击:

  1. 启动流式写入请求,并且根本不向其中写入任何数据。
  2. 继续创建和删除读取连接。由于写入器不产生任何数据,因此连接到写入器的读取线程将保持阻塞并消耗内存和其他资源。
  3. 观察服务器快速耗尽内存。

我是否应该创建一个维护线程来监视属于 阻塞 读取器线程的套接字并将interrupt() 发送给似乎与各自客户端失去连接的那些?上述架构中是否存在任何重大缺陷?谢谢。

【问题讨论】:

  • 您可以限制每个 IP 地址允许的传入连接数。
  • 分布式攻击并不是什么新鲜事,这不太可能缓解这个问题。
  • 那么keepalives和通信异常中断怎么办?

标签: java multithreading tomcat6


【解决方案1】:

在我看来,漏洞在于您的读者永远等待,无论传入连接的状态如何(当然,您无法知道)。

因此,如果合适的话,解决这个问题的一种直接方法是在BlockingQueue 上使用poll 方法,而不是take。调用poll 允许您指定超时,之后读者将如果队列中没有添加数据,则返回null

通过这种方式,阅读器不会永远被阻塞,并且应该相对较快地回到正常的处理循环,允许他们的资源被适当地释放。

(这当然不是万能药;当超时仍在运行时,读取器会消耗资源。但最终,资源有限的服务器会容易受到 DDOS 攻击 - 这会将其影响降低到可定制的小窗口,至少不会让您的服务器永久瘫痪。)

【讨论】:

  • Andrzej,谢谢,这看起来非常像我需要的解决方案。我是否也应该尝试写例如当poll() 返回null 时,一个空字节[] 到输出流,这样Tomcat 就有机会抛出IOException
  • 这取决于您希望如何处理该错误情况(超时),这取决于您的应用程序如何工作,您的基础设施是什么样的等等。主要的是您有机会做这个现在而不是读者永远阻塞。
  • @David,写一个空字节[] 可能什么都不做。即它不会检测到断开的连接。如果您想检测断开的连接,您需要超时和/或检测信号。
  • @Peter,正确,写一个空字节[] 是一个非常愚蠢的想法。您能否澄清一下,您建议跟踪的具体内容超时?恐怕无法在单独的连接中 ping 客户端,因此我们只能从单个 servlet 请求/响应对象对推断其状态。
  • @David,我知道您在与客户的互动中受到限制。但是,在某个时间点,您可能会收到来自客户端的数据,或者您可能会因写入失败而超时。如果您有一个打开的套接字,一段时间内没有发送任何内容,您可以关闭连接并强制客户端重新连接。
【解决方案2】:

我过去采用的方法是阻塞连接,只有读取线程。当您想写入多个连接时,您可以在当前线程中执行此操作。如果您担心每个人的写入阻塞,您可以使用一个监视线程来关闭阻塞的连接。

您仍然可以将资源绑定在未使用的套接字中,但我会有另一个线程来查找未使用的套接字并关闭它们。

这样每个连接只有一个线程,外加几个监控线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    相关资源
    最近更新 更多