crawler_JVM_DNS_在爬虫中的应用

DNS解析:即由域名 经过dns解析,跳转到真正服务器的地址,这个重复解析的耗时占请求很大比例。 在设计爬虫时比较细粒度的控制下,需要考虑dns解析。 jdk从1.5往后对dns缓存有默认设置,

详见jdk源码,不过有部分细节还是需要自己去处理的。

JAVA本身对DNS的缓存时间是多久?

对于爬虫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策略有关,如果没有启用security manager ,默认DNS 缓存时间30秒。策略配置文件:JAVA_HOME/jre/lib/security/java.policy

测试code

 1 import java.net.InetAddress;
 2 
 3 /**
 4  * @declare: DNS缓存研究 <br>
 5  * @author: cphmvp
 6  * @version: 1.0
 7  * @date: 2014-3-17下午5:37:07
 8  */
 9 public class MyDNS {
10     // jvm dns缓存研究
11     public static void main(String[] args) throws Exception {
12         String hostName = "www.baidu.com";
13         String cacheTime = "10";
14         java.security.Security.setProperty("networkaddress.cache.ttl",
15                 cacheTime);
16         for (int i = 0; i < 100; i++) {
17             long time = System.currentTimeMillis();
18             InetAddress addresses1[] = InetAddress.getAllByName(hostName);
19             System.out.println("addresses1:   "
20                     + String.valueOf(System.currentTimeMillis() - time) + "毫秒");
21             for (InetAddress address : addresses1)
22                 System.out.println(address);
23         }
24         // 当缓存时间为 0时,在一百次访问www.baidu.com 都有耗时情况【未考虑操作系统缓存】
25         // 当缓存时间为 10时,在一百次访问www.baidu.com ,只有第一次耗时,后99次不消耗dns查找时间
26         // 如果不设置 networkaddress.cache.ttl,默认为-1
27         // ,只有第一次耗时,后99次不消耗dns查找时间【后多少次都不在耗时,直至JVM重启】
28     }
29 }

默认JVM会缓存每一次DNS的查询结果,并且使缓存结果永远有效,直到你对该JVM重启为止。有时候业务需要系统能对域名切换及时而自动进行切换。这时候你就需要禁用或调整JVM的DNS缓存机制。

在独立运行程序中(非容器环境),可以在应用启动的时候通过以下代码完成:
         //设置解析成功的域名记录JVM中缓存的有效时间,JVM默认是永远有效,这样一来域名IP重定向必须重启JVM,这里修改为3秒钟有效,0表示禁止缓存,-1表示永远有效
        Security.setProperty("networkaddress.cache.ttl", "3");
         //设置解析失败的域名记录JVM中缓存的有效时间,JVM默认是10秒,0表示禁止缓存,-1表示永远有效
        Security.setProperty("networkaddress.cache.negative.ttl", "3");

代码中设置“networkaddress.cache.ttl”值的方式只适用于非容器环境,当应用部署与resin等容器中时该设置控制不了JVM的行为。可行的办法是通过在容器的启动参数中设置JDK系统变量“sun.net.inetaddr.ttl“或“sun.net.inetaddr.negative.ttl”,该参数跟“networkaddress.cache.ttl”和“networkaddress.cache.negative.ttl”的值定义一样,只是一个用于命令行,一个用于程序内部。具体操作方法:
修改httpd.sh,在"args="选项添加参数,如:-Dsun.net.inetaddr.ttl=0
 
如果非Resin容器的Java应用中同时配置了命令参数“sun.net.inetaddr.ttl”和Security属性“networkaddress.cache.ttl”,那么会以Security属性的设置为准。
结论:
方法一: 设置jvm参数,制定缓存有效期
方法二:硬编码 ,java.security.Security.setProperty("networkaddress.cache.ttl",cacheTime); 设置有效期。

一般情况下我们不需要完全取消JVM的DNS缓存,只需要调小有效时间,经过一些测试发现一下结论:
1)1个域名对应一个IP和一个域名对应12个IP,DNS查询响应时间差别极少,后者占用cpu稍高一点点;
2)在高并发时,不做DNS缓存时的CPU耗用比做了3s缓存的CPU耗用要高3/4倍,实时DNS请求相当耗用CPU;
3)3s和30s缓存有效时间对dns查询响应时间的影响差别不大,cpu内存占用都比较接近;
4)建议使用3秒缓存,兼顾运维和性能,对于不常改动指向ip的域名,可以设置时间更长 ,以提高性能。
 
原文地址:https://www.cnblogs.com/cphmvp/p/3605580.html