JVM DNS IP 地址缓存 (InetAddress)

(本文所有内容基于 Oracle JDK)

JVM IP 地址缓存

JVM 的缓存策略

由于 DNS 解析是一个访问量大的不是很可靠的网络调用,因此通常大部分系统都会对 DNS 解析的结果进行一定程度的缓存。如运营商的 LDNS、常用的浏览器、包括操作系统本身,都会对 DNS 解析的结果进行缓存。在 JVM 中,为了加速 DNS 解析的过程,当然也进行了相关的缓存。

在 Java 中,最常用的进行 DNS 解析的方法就是:

java.net.InetAddress.getAllByName(“www.google.com”);

而这个方法本身也会对解析的结果进行相应的缓存。看官方文档:

InetAddress Caching

The InetAddress class has a cache to store successful as well as unsuccessful host name resolutions.

By default, when a security manager is installed, in order to protect against DNS spoofing attacks, the result of positive host name resolutions are cached forever. When a security manager is not installed, the default behavior is to cache entries for a finite (implementation dependent) period of time. The result of unsuccessful host name resolution is cached for a very short period of time (10 seconds) to improve performance.

If the default behavior is not desired, then a Java security property can be set to a different Time-to-live (TTL) value for positive caching. Likewise, a system admin can configure a different negative caching TTL value when needed.

Two Java security properties control the TTL values used for positive and negative host name resolution caching:

networkaddress.cache.ttl
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. The default setting is to cache for an implementation specific period of time.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”.

简单来说,在默认情况下,成功解析到 IP 的解析结果会被永久缓存,而解析失败的结果会被缓存 10s。

虽然在一般情况下,这个缓存有利于提高系统的效率,减少网络交互。但是当我们依赖 DNS 进行负载均衡的时候,就会出现问题了。

修改策略

想要修改 JVM 默认的缓存策略,有三种方法实现:

  1. 修改 java.sercurity 配置文件
  2. JVM 启动时添加启动参数
  3. JVM 启动后,通过 System 修改系统类属性

修改配置文件

在 JDK 的 %JAVA_HOME%/jre/lib/security  目录下存在 java.security 文件。通过修改文件中的 networkaddress.cache.ttl  和 networkaddress.cache.negative.ttl  可以达到修改缓存策略的目的。配置信息如下:

#
# 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 in this implementation
# 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

# The Java-level namelookup cache policy for failed lookups:
#
# any negative value: cache forever
# any positive value: the number of seconds to cache negative lookup results
# zero: do not cache
#
# In some Microsoft Windows networking environments that employ
# the WINS name service in addition to DNS, name service lookups
# that fail may take a noticeably long time to return (approx. 5 seconds).
# For this reason the default caching policy is to maintain these
# results for 10 seconds.
#
#
networkaddress.cache.negative.ttl=10

JVM 启动时修改启动参数

同样的可以通过启动参数的方式来改变这个值:

https://docs.oracle.com/javase/8/docs/technotes/guides/net/properties.html

sun.net.inetaddr.ttlThis is a Oracle JDK private system property which corresponds to networkaddress.cache.ttl. It takes the same value and has the same meaning, but can be set as a command-line option. However, the preferred way is to use the security property mentioned above.


sun.net.inetaddr.negative.ttlThis is a Oracle JDK private system property which corresponds to networkaddress.cache.negative.ttl. It takes the same value and has the same meaning, but can be set as a command-line option. However, the preferred way is to use the security property mentioned above.

运行时通过 System 类修改

通过 java.lang.System  类在JVM启动后修改。

System.setProperty("sun.net.inetaddr.ttl", "60");
System.setProperty("sun.net.inetaddr.negative.ttl", "10");

或者

java.security.Security.setProperty("networkaddress.cache.ttl", "60");
java.security.Security.setProperty("networkaddress.cache.negative.ttl", "10");