我们了解了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缓存,大家可以根据自己的情况选用。
2. 修改jre/lib/security/java.security 下的 networkaddress.cache.ttl 属性
3. jvm启动参数中设置-Dsun.net.inetaddr.ttl=0
4. 通过反射清理,如本文的clearCache方法
- package xiaofei;
- import java.lang.reflect.Field;
- import java.net.InetAddress;
- import java.net.UnknownHostException;
- import java.util.Map;
- /**
- * @author xiaofei.wxf
- * @date 13-12-18
- */
- public class DNSCacheTest {
- /**
- * 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方法清除
- *
- * @param args
- * @throws UnknownHostException
- */
- public static void main(String[] args) throws UnknownHostException, NoSuchFieldException, IllegalAccessException {
- java.security.Security.setProperty("networkaddress.cache.ttl", "0");
- InetAddress addr1 = InetAddress.getByName("www.baidu.com");
- System.out.println(addr1.getHostAddress());
- //clearCache();
- //在下一行设置断点.
- //放在此处无效,因为类加载的时候就确定了这个值(应该在使用InetAddress.getByName之前设置)已经缓存了cache
- //java.security.Security.setProperty("networkaddress.cache.ttl", "0");
- InetAddress addr2 = InetAddress.getByName("www.baidu.com");
- System.out.println(addr2.getHostAddress());
- InetAddress addr3 = InetAddress.getByName("www.google.com");
- System.out.println(addr3.getHostAddress());
- InetAddress addr4 = InetAddress.getByName("www.google.com");
- System.out.println(addr4.getHostAddress());
- //clearCache();
- }
- public static void clearCache() throws NoSuchFieldException, IllegalAccessException {
- //修改缓存数据开始
- Class clazz = java.net.InetAddress.class;
- final Field cacheField = clazz.getDeclaredField("addressCache");
- cacheField.setAccessible(true);
- final Object obj = cacheField.get(clazz);
- Class cacheClazz = obj.getClass();
- final Field cachePolicyField = cacheClazz.getDeclaredField("type");
- final Field cacheMapField = cacheClazz.getDeclaredField("cache");
- cachePolicyField.setAccessible(true);
- cacheMapField.setAccessible(true);
- final Map cacheMap = (Map)cacheMapField.get(obj);
- System.out.println(cacheMap);
- cacheMap.remove("www.baidu.com");
- }
- }
------------------
简单操作 dns cache的一个例子
简单添加host配置到jvm默认的dns查询缓存中
编写了一个操作,可以自己将定义dns指向添加到jvm的dns查询缓存中,适用于不想将dns配置直接写入系统 /etc/hosts的情况。
- /**
- * 从hosts文件中读取dns配置,并加入本地jvm系统缓存中
- * @throws NoSuchFieldException
- * @throws IllegalAccessException
- * @throws NoSuchMethodException
- * @throws IOException
- * @throws InvocationTargetException
- * @return 此次设置dns配置的数量
- */
- public static int load() throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, IOException, InvocationTargetException {
- List<Pair<String,String>> hosts=hosts();//读取项目中的host文件,获得项目中定义的dns配置
- int totalLoaded=0;
- if(hosts.size()>0){
- //获取jvm的dns缓存设置方法
- Field f =InetAddress.class.getDeclaredField("addressCache");
- f.setAccessible(true);
- Object addressCache=f.get(null);
- Method put=addressCache.getClass().getDeclaredMethod("put",String.class,InetAddress[].class);
- put.setAccessible(true);
- //获取原先的缓存策略
- int policy=InetAddressCachePolicy.get();
- //将本地dns设置的缓存策略设置为永远有效
- Field cachePolicy=InetAddressCachePolicy.class.getDeclaredField("cachePolicy");
- cachePolicy.setAccessible(true);
- cachePolicy.set(null,InetAddressCachePolicy.FOREVER);
- //解析host配置,加载入jvm缓存
- for(Pair<String,String> host : hosts){
- String ip=host.getValue();
- String[] hostNames=host.getKey().split(",");
- for(String hostName :hostNames){
- if(hostName.length()==0) continue;
- put.invoke(addressCache,hostName,new InetAddress[]{InetAddress.getByAddress(hostName,address(ip))});
- totalLoaded++;
- log.debug("load InetAddress set "+ip+" "+hostName);
- }
- }
- //将缓存策略替换为原先的默认值
- cachePolicy.set(null,policy);
- }
- return totalLoaded;
- }
- /**
- * 将字符串形式的ip地址转换成字节形式
- * @param ip
- * @return
- */
- private static byte[] address(String ip){
- boolean isIp=true;
- for(char c : ip.toCharArray()){
- if((c>'9'||c<'0')&&c!='.'){
- isIp=false;
- break;
- }
- }
- if(!isIp) return null;
- String[] ipArr=ip.split("\\.");
- byte[] bip=new byte[ipArr.length];
- for(int i=0;i<ipArr.length;++i){
- bip[i]=(byte)(Integer.parseInt(ipArr[i],10)&0xff);
- }
- return bip;
- }
----
开源的 操作 jvn dns cache的一个项目
https://github.com/alibaba/java-dns-cache-manipulator
可以研究一下。