JVM中的DNS缓存

我们了解了DNS的解析过程,那么Java中的JVM也会缓存DNS的解析结果,这个缓存是在InetAddress类中,缓存时间较特殊,两种缓存策略:

1、缓存正确结果

2、缓存失败的结果

两个缓存时间由两个配置项来控制,配置项是在%JAVA_HOME%\lib\security\java.security文件中配置的。

两个配置项分布是networkaddress.cache.ttl和networkaddress.cache.negtive.ttl,其默认值分别是-1(永不失效)和10(保留10秒钟)。

修改方式:

1、直接修改java.secury文件的默认值

2、在JAVA启动时加启动参数 -Dsun.NET.inetaddress.ttl=XXX来修改默认值。

如果要用InetAddress类来解析域名时,一定要采用单例模式,否则会有严重的性能问题,每次都要创建新的类,都要进行完整的域名解析过程。

几种域名解析方式:

1、A表示address,可以将 多个域名解析到一个地址A上,但是反过来不行

2、MX记录,表示的是mail exchange ,将某个域名下的邮件服务器地址指向自己的mail server,例如,taobao.com的域名地址是21.235.19.245,如果MX的地址是

21.235.19.246 他是XX@taobao。com的邮件服务器地址,那么DNS将所有的邮件发送到该地址,然而,正常的WEB请求依然会发送到21.235.19.245.

3、CNAME记录,全名是cannonical name ,别名解析,就是为一个域名设置多个别名。例如,将taobao。com解析到mayun。com,将mayun123.com解析到mayun.com,

,那么mayun.com就是taobao。com节mayun123.com的别名。

4.NS记录,为某个域名指定DNS服务器,即这个域名有指定的IP地址的DNS服务器去解析

 

修改jvm dns cache的方法

一、测试环境

OS:Windows7 x64

JDK:1.6.0_45

二、本人找到四种方式清理jvm的DNS缓存,大家可以根据自己的情况选用。

 1. 在首次调用InetAddress.getByName()前,设置java.security.Security.setProperty("networkaddress.cache.ttl", "0");
2. 修改jre/lib/security/java.security 下的 networkaddress.cache.ttl 属性
3. jvm启动参数中设置-Dsun.net.inetaddr.ttl=0
4. 通过反射清理,如本文的clearCache方法
三、代码
[java] view plain copy

print?

  1. package xiaofei;
  2. import java.lang.reflect.Field;
  3. import java.net.InetAddress;
  4. import java.net.UnknownHostException;
  5. import java.util.Map;
  6. /**
  7. * @author xiaofei.wxf
  8. * @date 13-12-18
  9. */
  10. public class DNSCacheTest {
  11.     /**
  12.      * 1. 在首次调用InetAddress.getByName()前,设置java.security.Security.setProperty("networkaddress.cache.ttl", "0");
  13.      * 2. 修改jre/lib/security/java.security 下的 networkaddress.cache.ttl 属性
  14.      * 3. jvm启动参数中设置-Dsun.net.inetaddr.ttl=0
  15.      * 4. 调用clearCache方法清除
  16.      *
  17.      * @param args
  18.      * @throws UnknownHostException
  19.      */
  20.     public static void main(String[] args) throws UnknownHostException, NoSuchFieldException, IllegalAccessException {
  21.         java.security.Security.setProperty("networkaddress.cache.ttl""0");
  22.         InetAddress addr1 = InetAddress.getByName("www.baidu.com");
  23.         System.out.println(addr1.getHostAddress());
  24.         //clearCache();
  25.         //在下一行设置断点.
  26.         //放在此处无效,因为类加载的时候就确定了这个值(应该在使用InetAddress.getByName之前设置)已经缓存了cache
  27.         //java.security.Security.setProperty("networkaddress.cache.ttl", "0");
  28.         InetAddress addr2 = InetAddress.getByName("www.baidu.com");
  29.         System.out.println(addr2.getHostAddress());
  30.         InetAddress addr3 = InetAddress.getByName("www.google.com");
  31.         System.out.println(addr3.getHostAddress());
  32.         InetAddress addr4 = InetAddress.getByName("www.google.com");
  33.         System.out.println(addr4.getHostAddress());
  34.         //clearCache();
  35.     }
  36.     public static void clearCache() throws NoSuchFieldException, IllegalAccessException {
  37.         //修改缓存数据开始
  38.         Class clazz = java.net.InetAddress.class;
  39.         final Field cacheField = clazz.getDeclaredField("addressCache");
  40.         cacheField.setAccessible(true);
  41.         final Object obj = cacheField.get(clazz);
  42.         Class cacheClazz = obj.getClass();
  43.         final Field cachePolicyField = cacheClazz.getDeclaredField("type");
  44.         final Field cacheMapField = cacheClazz.getDeclaredField("cache");
  45.         cachePolicyField.setAccessible(true);
  46.         cacheMapField.setAccessible(true);
  47.         final Map cacheMap = (Map)cacheMapField.get(obj);
  48.         System.out.println(cacheMap);
  49.         cacheMap.remove("www.baidu.com");
  50.     }
  51. }

------------------

简单操作 dns  cache的一个例子

简单添加host配置到jvm默认的dns查询缓存中

编写了一个操作,可以自己将定义dns指向添加到jvm的dns查询缓存中,适用于不想将dns配置直接写入系统 /etc/hosts的情况。

  1. /**
  2.      * 从hosts文件中读取dns配置,并加入本地jvm系统缓存中
  3.      * @throws NoSuchFieldException
  4.      * @throws IllegalAccessException
  5.      * @throws NoSuchMethodException
  6.      * @throws IOException
  7.      * @throws InvocationTargetException
  8.      * @return 此次设置dns配置的数量
  9.      */
  10.     public static int load() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, IOException, InvocationTargetException {
  11.         List<Pair<String,String>> hosts=hosts();//读取项目中的host文件,获得项目中定义的dns配置
  12.         int totalLoaded=0;
  13.         if(hosts.size()>0){
  14.             //获取jvm的dns缓存设置方法
  15.             Field f  =InetAddress.class.getDeclaredField("addressCache");
  16.             f.setAccessible(true);
  17.             Object addressCache=f.get(null);
  18.             Method put=addressCache.getClass().getDeclaredMethod("put",String.class,InetAddress[].class);
  19.             put.setAccessible(true);
  20.             //获取原先的缓存策略
  21.             int policy=InetAddressCachePolicy.get();
  22.             //将本地dns设置的缓存策略设置为永远有效
  23.             Field cachePolicy=InetAddressCachePolicy.class.getDeclaredField("cachePolicy");
  24.             cachePolicy.setAccessible(true);
  25.             cachePolicy.set(null,InetAddressCachePolicy.FOREVER);
  26.             //解析host配置,加载入jvm缓存
  27.             for(Pair<String,String> host : hosts){
  28.                 String ip=host.getValue();
  29.                 String[] hostNames=host.getKey().split(",");
  30.                 for(String hostName :hostNames){
  31.                     if(hostName.length()==0continue;
  32.                     put.invoke(addressCache,hostName,new InetAddress[]{InetAddress.getByAddress(hostName,address(ip))});
  33.                     totalLoaded++;
  34.                     log.debug("load InetAddress set  "+ip+"    "+hostName);
  35.                 }
  36.             }
  37.             //将缓存策略替换为原先的默认值
  38.             cachePolicy.set(null,policy);
  39.         }
  40.         return totalLoaded;
  41.     }
  42.     /**
  43.      * 将字符串形式的ip地址转换成字节形式
  44.      * @param ip
  45.      * @return
  46.      */
  47.     private static byte[] address(String ip){
  48.         boolean isIp=true;
  49.         for(char c : ip.toCharArray()){
  50.             if((c>'9'||c<'0')&&c!='.'){
  51.                 isIp=false;
  52.                 break;
  53.             }
  54.         }
  55.         if(!isIp) return null;
  56.         String[] ipArr=ip.split("\\.");
  57.         byte[] bip=new byte[ipArr.length];
  58.         for(int i=0;i<ipArr.length;++i){
  59.             bip[i]=(byte)(Integer.parseInt(ipArr[i],10)&0xff);
  60.         }
  61.         return bip;
  62.     }

 

----

开源的 操作 jvn dns cache的一个项目

https://github.com/alibaba/java-dns-cache-manipulator

可以研究一下。

发表评论