心有多大舞臺(tái)便有多大

          Embrace changes, pursue excellence, share niceness.

          導(dǎo)航

          <2008年12月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          留言簿(6)

          隨筆分類(82)

          隨筆檔案(94)

          文章分類(21)

          文章檔案(18)

          相冊(cè)

          收藏夾(36)

          好書(shū)推薦

          技術(shù)文章

          朋友的博客

          架構(gòu)

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          java InetAddress 的dns cache問(wèn)題

          jdk的InetAddress有一個(gè)特性,就是當(dāng)系統(tǒng)訪問(wèn)過(guò)一個(gè)域名的時(shí)候,InetAddress就會(huì)通過(guò)其私有變量addressCache把域名對(duì)應(yīng)的ip地址緩存起來(lái).
          雖然緩存起來(lái)能極大的提高系統(tǒng)性能,但有時(shí)候會(huì)給系統(tǒng)帶來(lái)很大的麻煩.例如,當(dāng)對(duì)方改動(dòng)了ip地址后,系統(tǒng)就不能再訪問(wèn)到新的ip地址了,這個(gè)時(shí)候最直接的方案就是:重啟jvm!!!這對(duì)于需要7*24小時(shí)服務(wù)的系統(tǒng)來(lái)說(shuō),是不可忍受的.
          下面一段代碼可以重現(xiàn)這個(gè)現(xiàn)象(但需要你在運(yùn)行的時(shí)候是在調(diào)試模式):
          public void testDnsCachePolicy() throws Exception {
                  InetAddress addr1 = InetAddress.getByName("         System.out.println(addr1.getHostAddress());
                  //在下一行設(shè)置斷點(diǎn).
                  int i = 0;
                  InetAddress addr2 = InetAddress.getByName("
                  System.out.println(addr2.getHostAddress());
          }
          具體測(cè)試方式是:
          1.修改c:/windows/system32/drivers/etc/hosts文件,在文件末尾加入:64.233.189.104    
          www.baidu.com
          這個(gè)ip地址是google的ip
          2.運(yùn)行代碼到斷點(diǎn)處
          這時(shí)候打印出的ip地址是64.233.189.104
          3.修改hosts文件,把"64.233.189.104     4.繼續(xù)運(yùn)行代碼到結(jié)束
          這時(shí)候打印出的ip地址還是64.233.189.104,并沒(méi)有更改為baidu的ip地址.

          那么應(yīng)該怎么來(lái)解決這個(gè)問(wèn)題呢?
          查了下網(wǎng)上的解決方案,一般是在啟動(dòng)jvm的時(shí)候,指定jvm參數(shù):networkaddress.cache.ttl和networkaddress.cache.negative.ttl,具體的含義你可以查看InetAddress的源代碼.
          這種方法的缺點(diǎn)是在JVM啟動(dòng)的時(shí)候就固定了dns的緩存策略.如果不緩存的話,對(duì)系統(tǒng)性能的影響是很大的,那么能不能動(dòng)態(tài)的修改這個(gè)緩存的值呢?
          正好前段時(shí)間寫了篇文章:怎么通過(guò)反射修改類的私有字段值.正好有了用武之地!
          下面是測(cè)試代碼:
          //方法中的字符串常量policy,cache,addressCache請(qǐng)參考InetAddress源代碼.
          public void testDnsCachePolicy() throws Exception {
                  InetAddress addr1 = InetAddress.getByName("
                  System.out.println(addr1.getHostAddress());
                   //在下一行設(shè)置斷點(diǎn).
                  int i = 0;
                  //修改緩存數(shù)據(jù)開(kāi)始
                  Class inetAddressClass = java.net.InetAddress.class;       
                  final Field cacheField = inetAddressClass.getDeclaredField("addressCache");       
                  cacheField.setAccessible(true);       
                  final Object obj = cacheField.get(inetAddressClass);       
                  Class cacheClazz = obj.getClass();       
                  final Field cachePolicyField = cacheClazz.getDeclaredField("policy");       
                  final Field cacheMapField = cacheClazz.getDeclaredField("cache");       
                  cachePolicyField.setAccessible(true);
                  cacheMapField.setAccessible(true);    
                  final Map cacheMap = (Map)cacheMapField.get(obj);
                  cacheMap.remove("
                  //修改緩存數(shù)據(jù)結(jié)束
                  InetAddress addr2 = InetAddress.getByName("
                  System.out.println(addr2.getHostAddress());
          }
          重新按照上面的測(cè)試方法測(cè)試一次,第2次已經(jīng)能夠拿到正確的ip地址了.

          如果在用apache的httpclient,那么,在把緩存中的數(shù)據(jù)清除后,需要重新創(chuàng)建GetMethod/PostMethod對(duì)象.
          例如:
          HttpClient client = new HttpClient();
          GetMethod m1 = new GetMethod("http://www.baidu.com");
          client.executeMethod(m1);
          String content = m1.getResponseBodyAsString();
          ........//通過(guò)上面的反射方法清楚緩存
          //重新執(zhí)行m1,仍然不會(huì)得到正確的結(jié)果
          client.executeMethod(m1);
          String content = m1.getResponseBodyAsString();
          //重新創(chuàng)建GetMethod,才能得到正確的結(jié)果
          GetMethod m2 = new GetMethod("http://www.baidu.com");
          client.executeMethod(m2);
          content = m2.getResponseBodyAsString();

          posted on 2008-07-09 15:57 pony 閱讀(4720) 評(píng)論(3)  編輯  收藏 所屬分類: Java

          評(píng)論

          # re: java InetAddress 的dns cache問(wèn)題 2008-12-24 16:36 路人

          太感謝樓主了,正好遇到這個(gè)問(wèn)題  回復(fù)  更多評(píng)論   

          # re: java InetAddress 的dns cache問(wèn)題 2011-06-29 19:55 private250

          樓主高人!向你致敬!  回復(fù)  更多評(píng)論   

          # re: java InetAddress 的dns cache問(wèn)題 2015-04-24 22:35 Jerry Lee

          寫了操作Java DNS Cache的庫(kù) https://github.com/alibaba/java-dns-cache-manipulator ,可以方便些設(shè)置/重置/清空J(rèn)VM DNS,支持 JDK 6 7 8。可以試試 ~   回復(fù)  更多評(píng)論   

          主站蜘蛛池模板: 岚皋县| 兴宁市| 常熟市| 宁陵县| 娄烦县| 丽水市| 乌兰察布市| 平潭县| 阿克陶县| 永善县| 集安市| 广南县| 太保市| 江川县| 镇江市| 龙岩市| 德庆县| 永福县| 晴隆县| 西安市| 西乌| 霞浦县| 清徐县| 峨山| 礼泉县| 新津县| 河南省| 会同县| 杨浦区| 于田县| 炎陵县| 漠河县| 渭南市| 泗阳县| 竹溪县| 霍州市| 瑞昌市| 阳信县| 康马县| 景东| 航空|