挂头| java.io.FileInputStream.open(本机方法) | NFS 服务器

Posted

技术标签:

【中文标题】挂头| java.io.FileInputStream.open(本机方法) | NFS 服务器【英文标题】:Hung theads | java.io.FileInputStream.open(Native Method) | NFS server 【发布时间】:2015-08-03 07:12:52 【问题描述】:

我们有四个 lpar,每个 lpar 运行 1 个 java 实例。

他们对共享 NFS 服务器执行大量读/写操作。当 NFS 服务器突然关闭时,这四台服务器中的每台服务器中试图读取图像的所有线程都会进入挂起状态。

以下跟踪显示相同(进程是 websphere applciation 服务器进程)

    虽然我们正在处理 NFS 服务器端的问题,但有没有办法从代码端避免这种情况?

    如果底层连接是基于 tcp 的(我假设是),tcp 读取/连接超时是否应该解决这个问题?基本上我想将线程返回到池中,而不是无限等待对方响应。

    或者这是否应该由源计算机上的 nfs“客户端”处理?客户端上与 nfs 相关的一些配置设置(因为 FileInputStream.open 不知道它尝试读取的文件是在本地服务器上还是在 nfs 服务器中的共享文件夹上)

提前感谢您的回答:)

我们正在使用

java 1.6 on WAS 7.0

[8/2/15 19:52:41:219 GST] 00000023 ThreadMonitor W WSVR0605W:线程 “WebContainer : 77” (00003c2b) 已激活 763879 毫秒 并可能被挂起。服务器中总共有 110 个线程 那可能是挂了。 在 java.io.FileInputStream.open(本机方法) 在 java.io.FileInputStream.(FileInputStream.java:113) 在 java.io.FileInputStream.(FileInputStream.java:73) 在 org.emarapay.presentation.common.util.ImageServlet.processRequest(未知 来源) 在 org.emarapay.presentation.common.util.ImageServlet.doGet(未知 来源) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:718) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:831) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1694) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1635) 在 com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:113) 在 com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:80) 在 com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:908) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:965) 在 com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:508) 在 com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl

【问题讨论】:

这是 NFS 的限制。在 Java 中你无能为力。 EJP - 我同意这是对基础架构方面的限制。然而,代码需要以某种方式处理这个问题。例如。 (虽然可能不是正确的解决方案)使用 FutureTask 读取图像并在几秒钟后超时,以便至少线程返回到池中? 如果 NFS 主机在这些情况下完全挂起,TCP keepalive 可能能够加快检测速度。否则,TCP 将永远等待,因为它不知道上面有什么协议。 【参考方案1】:

检查这个解决方案https://***.com/a/9832633/1609655

您可以执行类似的操作来读取图像。基本上将读取调用包装在 Java Future 实现中,并在操作未在指定时间内完成时发出线程终止信号。

它可能并不完美,但我至少会防止你的服务器永远卡住。

【讨论】:

【参考方案2】:

这是来自@shodanshok 在 serverfault 中的响应,它帮助了我们。

这可能取决于 NFS 共享的挂载方式。默认情况下,NFS 共享使用“硬”参数挂载,这意味着对无响应 NFS 共享的访问将无限期阻塞。

您可以更改客户端挂载点,添加以下参数之一(我这里使用的是 Linux 手册页,可能您的具体选项有些不同):

soft:如果指定了soft选项,则NFS客户端在发送重传重传后失败NFS请求,导致NFS客户端向调用应用程序返回错误intr:选择是否允许信号中断文件操作这个挂载点。使用 intr 选项优于使用 soft 选项,因为它导致数据损坏的可能性要小得多。仅供参考,这在 Linux 内核 2.6.25+ 中已被弃用

来源:Linux nfs 手册页

【讨论】:

【参考方案3】:

http://martinfowler.com/bliki/CircuitBreaker.html

这似乎是这个问题(以及类似问题)的完美解决方案。这个想法是将调用包装在另一个对象中,这将阻止对失败服务的进一步调用(基于您设计此对象以处理这种情况的方式)。

例如当外部服务变得无响应时,线程会慢慢进入挂起状态。相反,如果我们有一个 THRESHOLD LEVLE 可以防止线程进入该状态,那就太好了。如果我们可以配置说,如果外部服务没有响应或等待响应前 30 个请求,则不要尝试连接到外部服务!在这种情况下,第 31 个请求将直接向尝试访问报告的客户抛出错误(或向团队发送错误邮件),但至少第 31 个线程不会等待,而是用于处理来自其他线程的其他请求功能。

参考资料:

http://martinfowler.com/bliki/CircuitBreaker.html

http://doc.akka.io/docs/akka/snapshot/common/circuitbreaker.html

http://techblog.netflix.com/2011/12/making-netflix-api-more-resilient.html

https://github.com/Netflix/Hystrix

【讨论】:

以上是关于挂头| java.io.FileInputStream.open(本机方法) | NFS 服务器的主要内容,如果未能解决你的问题,请参考以下文章