How to make Java honor the DNS Caching Timeout?

Viewed 124112

We use GSLB for geo-distribution and load-balancing. Each service is assigned a fixed domain name. Through some DNS magic, the domain name is resolved into an IP that's closest to the server with least load. For the load-balancing to work, the application server needs to honor the TTL from DNS response and to resolve the domain name again when cache times out. However, I couldn't figure out a way to do this in Java.

The application is in Java 5, running on Linux (Centos 5).

7 Answers

Java has some seriously weird dns caching behavior. Your best bet is to turn off dns caching or set it to some low number like 5 seconds.

networkaddress.cache.ttl (default: -1)
Indicates the caching policy for successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the successful lookup. A value of -1 indicates "cache forever".

networkaddress.cache.negative.ttl (default: 10)
Indicates the caching policy for un-successful name lookups from the name service. The value is specified as as integer to indicate the number of seconds to cache the failure for un-successful lookups. A value of 0 indicates "never cache". A value of -1 indicates "cache forever".

To expand on Byron's answer, I believe you need to edit the file java.security in the %JRE_HOME%\lib\security directory to effect this change.

Here is the relevant section:

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
#       serious security implications. Do not set it unless 
#       you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1 

Documentation on the java.security file here.

According to the official oracle java properties, sun.net.inetaddr.ttl is Sun implementation-specific property, which "may not be supported in future releases". "the preferred way is to use the security property" networkaddress.cache.ttl.

So I decided to look at the java source code because I found official docs a bit confusing. And what I found (for OpenJDK 11) mostly aligns with what others have written. What is important is the order of evaluation of properties.

InetAddressCachePolicy.java (I'm omitting some boilerplate for readability):


String tmpString = Security.getProperty("networkaddress.cache.ttl");
if (tmpString != null) {
   tmp = Integer.valueOf(tmpString);
   return;
}
...
String tmpString = System.getProperty("sun.net.inetaddr.ttl");
if (tmpString != null) {
   tmp = Integer.valueOf(tmpString);
   return;
}
...
if (tmp != null) {
  cachePolicy = tmp < 0 ? FOREVER : tmp;
  propertySet = true;
} else {
  /* No properties defined for positive caching. If there is no
  * security manager then use the default positive cache value.
  */
  if (System.getSecurityManager() == null) {
    cachePolicy = 30;
  }
}

You can clearly see that the security property is evaluated first, system property second and if any of them is set cachePolicy value is set to that number or -1 (FOREVER) if they hold a value that is bellow -1. If nothing is set it defaults to 30 seconds. As it turns out for OpenJDK that is almost always the case because by default java.security does not set that value, only a negative one.

#networkaddress.cache.ttl=-1 <- this line is commented out
networkaddress.cache.negative.ttl=10

BTW if the networkaddress.cache.negative.ttl is not set (removed from the file) the default inside the java class is 0. Documentation is wrong in this regard. This is what tripped me over.

Related