`
nigelzeng
  • 浏览: 607559 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

【转载】关于java dns cache (域名缓存时间)

    博客分类:
  • Java
阅读更多

今天刚刚碰到一个JVM缓存DNS的引起的问题,分享一下一个同事的博文:

 

------------------------------------------------------丑陋的分割线---------------------------------------------

最近手上的某java应用频繁因网络问题而出现故障,同时也抛出一个问题:JAVA本身对DNS的缓存时间是多久?

对于非公司内部产品的疑问,第一反应Google之,大致有两种说法:
第1种:默认情况下networkaddress.cache.ttl=-1,代表永久缓存(配置文件路径: JAVA_HOME/jre/lib/security/java.security),就是在应用启动之后第一次DNS 解析成功的结果会一直cache到应用停止。显然在域名对应的IP有变更的时候,如果不重启应用就会造成故障。有部分同事以前也做过相关测试,认同这种说法。

第2种:jdk1.5和1.5之前的版本默认DNS 缓存时间是永久缓存,jdk 1.6以后与security manager策略有关(jboss tomcat 等app server默认不启用,详见此文),如果没有启用security manager ,默认DNS 缓存时间30秒。策略配置文件:JAVA_HOME/jre/lib/security/java.policy

根据上述说法,先看一下配置文件JAVA_HOME/jre/lib/security/java.security

?View Code BASH
#
# 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

查看了jboss的run.sh脚本并未设置 java.security 相关参数,那我们的默认缓存时间应该是30 seconds

理论依据往往没有实验结果让人信服,于是又继续搜索相关的内容,终于在stackoverflow上找到了可以输出缓存内容的脚本。
我稍微修改了一下:

?View Code JAVA
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.text.SimpleDateFormat;
 
 
public class DNSCache {
  public static void main(String[] args) throws Exception {
    Date d = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    InetAddress.getByName("www.google.com");
    try {
        InetAddress.getByName("nowhere.example.com");
    } catch (UnknownHostException e) {
 
    }
 
    System.out.println("current time:" + sdf.format(d));
    String addressCache = "addressCache";
    System.out.println(addressCache);
    printDNSCache(addressCache);
    String negativeCache = "negativeCache";
    System.out.println(negativeCache);
    printDNSCache(negativeCache);
  }
  private static void printDNSCache(String cacheName) throws Exception {
    Class<InetAddress> klass = InetAddress.class;
    Field acf = klass.getDeclaredField(cacheName);
    acf.setAccessible(true);
    Object addressCache = acf.get(null);
    Class cacheKlass = addressCache.getClass();
    Field cf = cacheKlass.getDeclaredField("cache");
    cf.setAccessible(true);
    Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache);
    for (Map.Entry<String, Object> hi : cache.entrySet()) {
        Object cacheEntry = hi.getValue();
        Class cacheEntryKlass = cacheEntry.getClass();
        Field expf = cacheEntryKlass.getDeclaredField("expiration");
        expf.setAccessible(true);
        long expires = (Long) expf.get(cacheEntry);
 
        Field af = cacheEntryKlass.getDeclaredField("address");
        af.setAccessible(true);
        InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry);
        List<String> ads = new ArrayList<String>(addresses.length);
        for (InetAddress address : addresses) {
            ads.add(address.getHostAddress());
        }
 
        System.out.println(hi.getKey() + " "+new Date(expires) +" " +ads);
    }
  }
}

编译 javac -Xlint:unchecked DNSCache.java
执行 java DNSCache 得到结果:

current time:2012-07-27 11:35:31
addressCache
0.0.0.0 Fri Jul 27 11:36:01 CST 2012 [0.0.0.0]
www.google.com Fri Jul 27 11:36:01 CST 2012 [74.125.71.105, 74.125.71.106, 74.125.71.147, 74.125.71.99, 74.125.71.103, 74.125.71.104]
negativeCache
nowhere.example.com Fri Jul 27 11:35:41 CST 2012 [0.0.0.0]

解析成功的域名www.google.com 缓存时间正好30 seconds
解析失败的域名nowhere.example.com 缓存时间正好10 seconds
与前面的理论完全对上,而且我们还看到对于多条A记录的域名它会全部缓存起来,并不是只缓存其中的一条A记录。
这里又引出了一个疑问:对于多条A记录是采用轮循还是什么策略使用呢?

我们可以修改脚本测试一下:

?View Code JAVA
 
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.text.SimpleDateFormat;
 
 
public class DNSCache {
  public static void main(String[] args) throws Exception {
    System.out.println("start loop\n\n");
    for(int i = 0; i < 30; ++i) {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("current time:" + sdf.format(d));
        InetAddress addr1 = InetAddress.getByName("www.google.com");
        String addressCache = "addressCache";
        System.out.println(addressCache);
        printDNSCache(addressCache);
        System.out.println("getHostAddress:" + addr1.getHostAddress());
        System.out.println("*******************************************");
        System.out.println("\n");
        java.lang.Thread.sleep(10000);
    }
 
    System.out.println("end loop");
  }
 
 
  private static void printDNSCache(String cacheName) throws Exception {
    Class<InetAddress> klass = InetAddress.class;
    Field acf = klass.getDeclaredField(cacheName);
    acf.setAccessible(true);
    Object addressCache = acf.get(null);
    Class cacheKlass = addressCache.getClass();
    Field cf = cacheKlass.getDeclaredField("cache");
    cf.setAccessible(true);
    Map<String, Object> cache = (Map<String, Object>) cf.get(addressCache);
    for (Map.Entry<String, Object> hi : cache.entrySet()) {
        Object cacheEntry = hi.getValue();
        Class cacheEntryKlass = cacheEntry.getClass();
        Field expf = cacheEntryKlass.getDeclaredField("expiration");
        expf.setAccessible(true);
        long expires = (Long) expf.get(cacheEntry);
 
        Field af = cacheEntryKlass.getDeclaredField("address");
        af.setAccessible(true);
        InetAddress[] addresses = (InetAddress[]) af.get(cacheEntry);
        List<String> ads = new ArrayList<String>(addresses.length);
        for (InetAddress address : addresses) {
            ads.add(address.getHostAddress());
        }
 
        System.out.println(hi.getKey() + " "+new Date(expires) +" " +ads);
    }
  }
}

编译执行

?View Code BASH
start loop
 
 
current time:2012-07-28 15:30:58
addressCache
0.0.0.0 Sat Jul 28 15:31:28 CST 2012 [0.0.0.0]
www.google.com Sat Jul 28 15:31:28 CST 2012 [74.125.71.103, 74.125.71.104, 74.125.71.105, 74.125.71.106, 74.125.71.147, 74.125.71.99]
getHostAddress:74.125.71.103
*******************************************
 
 
current time:2012-07-28 15:31:08
addressCache
0.0.0.0 Sat Jul 28 15:31:28 CST 2012 [0.0.0.0]
www.google.com Sat Jul 28 15:31:28 CST 2012 [74.125.71.103, 74.125.71.104, 74.125.71.105, 74.125.71.106, 74.125.71.147, 74.125.71.99]
getHostAddress:74.125.71.103
*******************************************
 
 
current time:2012-07-28 15:31:18
addressCache
0.0.0.0 Sat Jul 28 15:31:28 CST 2012 [0.0.0.0]
www.google.com Sat Jul 28 15:31:28 CST 2012 [74.125.71.103, 74.125.71.104, 74.125.71.105, 74.125.71.106, 74.125.71.147, 74.125.71.99]
getHostAddress:74.125.71.103
*******************************************
 
 
current time:2012-07-28 15:31:28
addressCache
www.google.com Sat Jul 28 15:31:58 CST 2012 [74.125.71.104, 74.125.71.105, 74.125.71.106, 74.125.71.147, 74.125.71.99, 74.125.71.103]
getHostAddress:74.125.71.104
*******************************************
#后面省略

结论:在缓存有效期内,取到的IP永远是缓存中全部A记录的第一条,并没有轮循之类的策略。
缓存失效之后重新进行DNS解析,因为每次域名解析返回的A记录顺序会发生变化(dig www.google.com测试可见),所以缓存中的数据顺序也变了,取到的IP也变化。

当然最可靠的还是看下源码实现,有研究的同学请告诉我一下:)

最后附上几种修改缓存时间的方法:
1. jvm启动参数里面配置-Dsun.net.inetaddr.ttl=value
2. 修改 配置文件JAVA_HOME/jre/lib/security/java.security相应的参数networkaddress.cache.ttl=value
3. 代码里直接设置:java.security.Security.setProperty(”networkaddress.cache.ttl” , “value”);

参考资料:
http://docs.oracle.com/javase/6/docs/api/java/net/InetAddress.html
http://kenwublog.com/java-dns-cache-setting
http://stackoverflow.com/questions/1835421/java-dns-cache-viewer
http://docs.jboss.org/jbossas/docs/Server_Configuration_Guide/4/html/Security_on_JBoss-Running_JBoss_with_a_Java_2_security_manager.html

 

来源:飘零的代码 piao2010 ’s blog

分享到:
评论
1 楼 oldrat 2015-04-14  
还给出了 给出“对于多条A记录是采用什么策略返回IP”的结论,赞!

写了操作Java DNS Cache的库 https://github.com/alibaba/java-dns-cache-manipulator ,方便用起来,支持 JDK 6 7 8。可以试试 ~ :)

相关推荐

    java实现清理DNS Cache的方法

    1. **设置安全属性**:在首次调用`InetAddress.getByName()`之前,可以通过`java.security.Security.setProperty("networkaddress.cache.ttl", "0")`来设置DNS缓存的生存时间(TTL)为0,使其立即过期。这样,每次...

    org.xbill.DNS_java工具类.

    5. **缓存机制**:`Cache`类实现了DNS缓存,可以提高DNS查询的效率,减少网络通信。 三、应用示例 1. **查询IP地址**:使用`Resolver`进行A记录查询,获取指定域名的IP地址。 ```java Resolver resolver = new ...

    DNS过滤转发器源码(java)

    10. **安全性**:源码可能考虑了防止DNS欺骗(DNS Cache Poisoning)和中间人攻击等安全措施,例如使用DNSSEC(DNS安全扩展)来验证响应的来源。 总的来说,这个DNS过滤转发器项目涵盖了网络编程、数据结构、算法、...

    【BUPT】北京邮电大学 DNS relay(JAVA).zip

    4. **DNS缓存**:理解缓存策略,避免重复查询,提高响应速度,同时要考虑到缓存过期和更新的问题。 5. **安全与防攻击措施**:防止DNS欺骗(DNS Cache Poisoning)和其他类型的网络攻击,如使用DNSSEC(DNS安全扩展...

    DnsQuery_SUN_java.zip

    - 缓存时间可以通过系统属性`sun.net.dns.cache.timeout`进行设置,默认值为60秒。 3. **DNSSEC(DNS Security Extensions)**: - Java支持DNSSEC,可以验证DNS查询响应的来源和完整性。这通过`java.net.DNS...

    l3dns:用Java编写的DNS服务器

    【l3dns:用Java编写的DNS服务器】 l3dns是一个用Java语言开发的DNS(Domain Name System)服务器,它提供了对于DNS协议的全面支持,包括解析查询、处理响应以及维护DNS记录。DNS是互联网的核心服务之一,它将人类可...

    sourcecode:原始学习1)HashMap 2)NIO编程模型,利用Java的NIO实现完成聊天室程序

    且ctrl + f5会避免请求浏览器自身缓存直接向目标网址发起请求DNS域名解析过程a)浏览器缓存b)操作系统文件c)本地DNS服务器(ISP的LDNS)查看缓存(有-&gt;返回)d)根服务器e)gTLD主域名服务器f)gTLD主域名服务器...

    云端加速背后的技术支撑-白宇

    一个请求(request)的生命周期通常包括以下几个步骤:DNS解析、前端负载均衡检查(FL check)、页面优化(Page optimization)、缓存管理(Cache management)、缓存服务(Cache service)、上层服务(Upstream ...

    2011年计算机专业考研大纲.pdf

    2. 存储结构:提到了cache(缓存)、TLB(转换后备缓冲区)和各种存储器类型(如SRAM、DRAM、CPU RAM等),意味着需要掌握计算机存储体系结构和存储介质特性。 3. 计算机组成原理:提到了MIPS、MFLOPS、CPU、ALU等...

    计算机基础知识大赛考题.pdf

    互联网协议相关知识包含IP(互联网协议)、Cache、DNS(域名系统)、WWW/HTTP(万维网/超文本传输协议)、IP地址等,这些都是互联网通信的基础知识点。 网络和媒体文件格式也有所涉及,如BMP、GIF、WMF、TIF、AVI、...

    (最新)2012计算机专业考研大纲.pdf

    Cache(高速缓存)是位于CPU与主存之间的存储设备,用来减少处理器访问内存所需的时间;总线是连接多个部件的信息传输通道;I/O系统负责计算机与外部设备之间的数据交换。 计算机网络部分的知识点涵盖了数据链路层...

    OKhttp3源码

    `Dns`接口用于解析域名到IP地址,`Route`对象封装了服务器的地址信息。 4. **TCP连接与SSL握手**:通过`SocketFactory`创建TCP连接,如果服务器支持HTTPS,会进行SSL/TLS握手。`SSLSocketFactory`处理加密通信。 5...

    大学计算机基础笔试理论部分.pdf

    - DNS(域名系统)用于将域名转换成IP地址,便于网络通信。 其他: - ASCII码是一种字符编码,用于将字符转换为计算机可以识别的数字代码。 - ADSL(非对称数字用户线)是一种在普通电话线上进行宽带通信的技术。 ...

    smack4.1.5 实现xmpp 所需要的所有jar

    6. minidns-0.1.3.jar:这是一个小型DNS解析库,Smack用它来解析XMPP服务器的域名,帮助建立连接。 7. smack-bosh-4.1.5.jar:支持HTTP绑定(BOSH)协议,这是一种让XMPP客户端通过HTTP长轮询与服务器保持连接的...

    HTTP 超全汇总.pdf

    DNS(域名系统)负责将URL解析为IP地址,以便建立连接。URI(统一资源标识符)是资源的全局唯一标识,URL是URI的一个子集,包含了获取资源的具体途径。 HTTPS(安全套接字层超文本传输协议)是HTTP的安全版本,它...

    淘宝技术架构.pdf

    在处理CDN的架构上,淘宝使用了DNS服务器和GSLB来平衡请求,通过CDN节点和LB设备来处理cache未命中情况。同时,淘宝的技术架构使用了多级数据库集群技术,例如Oracle的RAC、SAN低端存储和分域名的Denali集群。此外,...

    字节跳动(抖音面试题)

    从域名到IP地址的过程包括本地缓存、hosts文件、DNS查询(递归查询和迭代查询)。 19. 跨域与解决方案: 同源策略限制了跨域请求,解决方案包括JSONP、CORS、WebSocket等。 20. Cookie与Session: Cookie存储在...

    一年计算机一级B考试复习提纲.pdf

    5. 域名系统DNS:将易于记忆的域名转换为IP地址,便于网络访问。 复习这些知识点对于参加计算机一级B考试至关重要,理解并掌握它们将有助于在考试中取得好成绩。在复习过程中,考生应注重理论与实践相结合,通过...

    计算机网络面试常考题总结

    例如,Cache-Control用于控制缓存行为,Date用于指定日期和时间。 - **请求头报文**:包含客户端信息以及请求参数等,帮助服务器了解客户端环境。 - **响应头**:服务器通过响应头向客户端提供关于响应的信息,如...

    英语]计算机英语词汇【全本】

    - **DNS (Domain Name System)**(域名系统):DNS是一种将域名转换为IP地址的服务,使得互联网用户可以通过易于记忆的域名访问网站。 - **DRAM: Dynamic Random Access Memory**(动态随机访问存储器):DRAM是一种...

Global site tag (gtag.js) - Google Analytics