有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用java查找主机名时,性能线程进入阻塞状态。网地址。getLocalHost

请在下面找到发现问题的应用程序/环境详细信息

  • Java Web应用程序部署在Tomcat 9.0.35上,JRE版本为1.8.0çu 231-b11
  • 该应用程序正在部署在OpenShift Kubernetes分发平台上的docker容器中运行

我看到应用程序中的许多线程有时会进入阻塞状态几分钟。在线程转储分析中,发现java。网地址。getLocalHost调用占用的时间太长。很多线都卡在这里了。为应用程序中打印的每个记录器获取主机名

这个问题是间歇性的。但是当它发生时,应用程序/tomcat将进入暂停状态,这将导致大量线程的累积。一段时间(几秒钟)后,所有被阻止的线程将同时被解除阻止。由于请求的并发性,应用程序将耗尽其在池中维护的DB连接,从而导致问题/缓慢/服务可用性。作为修复,我已确保只在静态变量中访问主机名一次,并在整个日志记录过程中使用相同的主机名。我想知道这个问题的详细根源

  • 为什么这个问题会间歇性出现
  • 在这个kubernetes环境中,DNS查找是否有问题
  • 我们正在使用IPV4协议/地址
  • 是否有更好的方法/修复方法来处理此问题

下面是线程转储中的示例:

 "https-jsse-nio-8443-exec-13" #95 daemon prio=5 os_prio=0 tid=0x00007fccadbba800 nid=0xaf5 waiting for monitor entry 0x00007fcb912d1000
       java.lang.Thread.State: BLOCKED (on object monitor)
        at java.net.InetAddress.getLocalHost(InetAddress.java:1486)
        - waiting to lock <0x00000005e71878a0> (a java.lang.Object)

共 (3) 个答案

  1. # 1 楼答案

    也许服务器将使用ipv6,如果未使用,您可以将JVM配置为仅使用IPV4,为此将其添加到选项-Djava中。网preferIPv4Stack=true,或者如果只需要ipv6-Djava。网preferIPv6Stack=true。这将迫使JVM使用正确的协议

  2. # 2 楼答案

    在JDK 8中,InetAddress.getLocalHost()工作as follows

    1. 通过本机gethostname调用以字符串形式获取主机名
    2. 如果上次主机名解析后不到5秒,请返回缓存的IP地址
    3. 否则,请解析主机名:
      • 使用JDK内置的查找缓存,默认TTL为30秒
      • 使用系统调用执行实际的DNS查找(取决于配置,该地址可能会被OS和DNS服务器进一步缓存)
    4. 将解析的本地主机IP地址缓存5秒钟

    步骤2-4在全局^{}下执行。如果在这个过程中出现问题,所有调用InetAddress.getLocalHost()的线程都会在这个锁上阻塞——这正是您观察到的

    通常,本地主机名解析不会在网络调用中结束,只要主机地址硬编码在/etc/hosts中即可。但在您的情况下,似乎涉及到真正的网络请求(只要TTL过期)。当第一个DNS请求超时时(UDP毕竟不是一个可靠的协议),就会发生延迟

    解决方案是将/etc/hosts配置为包含本地主机的名称和地址,例如

    192.168.1.23   myhost.mydomain
    

    其中myhost.mydomainhostname命令返回的字符串相同

    最后,如果主机名在应用程序运行时不会更改,那么在应用程序级别一次性永久缓存它看起来是一个很好的解决方案

  3. # 3 楼答案

    为了解决这个问题,我只加载主机名一次,并在应用程序启动时缓存它。我已经在生产中推出了这个修复程序,我们不再看到线程阻塞问题