根据这篇文章的分析,Java代码中调用InetAddress.getByName(host)进行域名解析后(可能得到有效解析结果,也可能解析失败),会将结果数据保存到缓存中。当下次域名解析时,如果缓存中数据未过期,可以直接使用缓存数据。
而缓存数据的过期策略,可以通过下面的方式配置:
如果开启了SecurityManager,会从${java.home}/jre/lib/security/java.security中读取配置项:
有效结果缓存时间配置:networkaddress.cache.ttl (缺省值30,单位秒)
失败结果缓存时间配置:networkaddress.cache.negative.ttl (缺省值10,单位秒)
如果未开启SecurityManager,会从启动参数读取配置项:
有效结果缓存时间配置:sun.net.inetaddr.ttl
失败结果缓存时间配置:sun.net.inetaddr.negative.ttl
以上配置未生效情况下,缺省配置是:
有效结果缓存时间:-1(永不过期)
失败结果缓存时间:0(立刻过期,即不做缓存)
这个缺省配置在实践中会出问题:如果域名解析发生变更,但因为有效结果缓存永不过期,应用一直使用旧的解析结果,会导致连接异常等错误(类似java.net.ConnectException: Tried all: '1' addresses, but could not connect over HTTP to server)。如果域名解析失败,对失败结果不做缓存,可能会出现持续解析失败,这种情况往往降低可用性。
本文参考的源码及配置为Java1.8版本。进一步了解SecurityManager,请参考。
**最佳实践**:java.security的缺省配置比较合理,如果不确定应用是否开启了SecurityManager,可以在Java Options中将相关启动参数配置成60/10,保持和java.security的缺省配置一致。