JDK-8192366 : DNS lookup hangs for 5s when primary nameserver is down
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 8,9,10
  • Priority: P4
  • Status: Resolved
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86_64
  • Submitted: 2017-11-22
  • Updated: 2022-12-07
  • Resolved: 2022-12-07
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java -version
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux rmp-0075919300a78ce99-c-ea 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

EXTRA RELEVANT SYSTEM CONFIGURATION :
point your primary nameserver in /etc/resolv.conf to nameserver that you have access to

A DESCRIPTION OF THE PROBLEM :
Do reverse DNS lookups in multiple threads. Bring down 'named' service in primary nameserver. DNS lookups will hang for 5s intermittently and often until nameserver is backup. 



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following program to do reverse DNS lookup like 

java Test 10.16.33.7

cat Test.java

import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    static {
        java.security.Security.setProperty ("networkaddress.cache.ttl" , "1");
    }
    public static void main (String args[]) throws Exception {
        System.out.println("DEFAULT DNS TTL: "+java.security.Security.getProperty("networkaddress.cache.ttl"));
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        while (true) {
            for (int i = 0; i < 4; i++) {
                executorService.submit(() -> {
                    try {
                        long start = System.currentTimeMillis();
                        System.out.println(InetAddress.getByName(args[0]).getHostName() + " " + (System.currentTimeMillis() - start));
                        //System.out.println(InetAddress.getAllByName(args[0])[0]+ " "+(System.currentTimeMillis() - start));
                        //System.out.println(InetAddress.getAllByName("10.16.36.12") + " "+(System.currentTimeMillis() - start));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
            Thread.sleep(2000);
	    System.out.println("");
        }
    }
}

This will print output like 

DEFAULT DNS TTL: 1
ejp001ea.test.com 16
ejp001ea.test.com 9
ejp001ea.test.com 8
ejp001ea.test.com 8

ejp001ea.test.com 4
ejp001ea.test.com 4
ejp001ea.test.com 3
ejp001ea.test.com 4

ejp001ea.test.com 4
ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 3

ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 4

ejp001ea.test.com 4
ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 3


Now login to primary nameserver and bring down named service.

sudo service named stop

OR run the following rule in nameserver

sudo iptables -A INPUT --src src_java_hostip -p udp --dport 53 -j REJECT


Now output will look like

ejp001ea.test.com 4
ejp001ea.test.com 3
ejp001ea.test.com 4

ejp001ea.test.com 5
ejp001ea.test.com 6
ejp001ea.test.com 5
ejp001ea.test.com 5



ejp001ea.test.com 5007
ejp001ea.test.com 5007
ejp001ea.test.com 5007
ejp001ea.test.com 5007
ejp001ea.test.com 2
ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 3
ejp001ea.test.com 2

ejp001ea.test.com 2


ejp001ea.test.com 5009
ejp001ea.test.com 5009
ejp001ea.test.com 5009
ejp001ea.test.com 2
ejp001ea.test.com 2
ejp001ea.test.com 5007
ejp001ea.test.com 3


ejp001ea.test.com 5008
ejp001ea.test.com 5006
ejp001ea.test.com 5006
ejp001ea.test.com 2
ejp001ea.test.com 2

ejp001ea.test.com 5006
ejp001ea.test.com 3

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Fails over to secondary nameserver without hanging for 5s.
ACTUAL -
Thread hangs for 5s

ERROR MESSAGES/STACK TRACES THAT OCCUR :
stacktrace looks like this

java.lang.Thread.State: RUNNABLE
        at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method)
        at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928)
        at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323)
        at java.net.InetAddress.getAllByName0(InetAddress.java:1276)
        at java.net.InetAddress.getAllByName(InetAddress.java:1192)
        at java.net.InetAddress.getAllByName(InetAddress.java:1126)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    static {
        java.security.Security.setProperty ("networkaddress.cache.ttl" , "1");
    }
    public static void main (String args[]) throws Exception {
        System.out.println("DEFAULT DNS TTL: "+java.security.Security.getProperty("networkaddress.cache.ttl"));
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        while (true) {
            for (int i = 0; i < 4; i++) {
                executorService.submit(() -> {
                    try {
                        long start = System.currentTimeMillis();
                        System.out.println(InetAddress.getByName(args[0]).getHostName() + " " + (System.currentTimeMillis() - start));
                        //System.out.println(InetAddress.getAllByName(args[0])[0]+ " "+(System.currentTimeMillis() - start));
                        //System.out.println(InetAddress.getAllByName("10.16.36.12") + " "+(System.currentTimeMillis() - start));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
            Thread.sleep(2000);
	    System.out.println("");
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Do reverse DNS lookup in one thread.


Comments
So first off, 5 second delay before failing over to secondary nameserver is the default behavior of Linux glibc; you can configure a different delay in resolv.conf if you're interested. Next, Java caches the results of forward name lookups for 30 seconds by default; the cache period can be configured with `networkaddress.cache.ttl` security property and `sun.net.inetaddr.ttl` system property. The cache only applies to forward name lookups, it does not apply to reverse lookups. See JDK-6656822. I'm going to close this as a duplicate of JDK-6656822. Feel free to add a comment here or raise another ticket if you feel that JDK-6656822 is not what you're after.
07-12-2022

From submitter: In addition to openjdk 8u151, the issue is also reproducible in : openjdk 7u85 oracle jdk 8u151 (build 1.8.0_151-b12) oracle jdk 9.0.1 (build 9.0.1+11)
01-12-2017

To submitter: The issue has been reported against OpenJDK 8u151. Can you please let us know if this is reproducible against the Oracle JDK 8u151 as well. Is it reproducible in the latest JDK 9.0.1 version ?
29-11-2017