JavaDsCacheMaipulator(DCM)Library
通过代码直接设置Java的DNS(实际上设置的是DNSCache),支持JDK6+,支持IPv6。
功能设置/重置DNS(不会再去LookupDNS)
可以设置单条
或是通过Properties文件批量设置
清空DNSCache(即所有的域名重新LookupDNS)
删除一条DNSCache(即重新LookupDNS)
查看DNSCache内容
修改/查看JVM缺省的DNS的缓存时间
需求场景一些库中写死了连接域名,需要通过修改host文件绑定才能做测试。结果是:
自动持续集成的机器上一般同学是没有权限去修改host文件的,导致项目不能持续集成。实际上是因为这点,催生这个库的需求。
单元测试需要每个开发都在开发机上做host绑定,增加了依赖的配置操作且繁琐重复。
一些功能需要域名作为输入参数,如使用HTTP请求的网关或是有域名检查限制的Web应用。这种情况下,让需要让一个域名连接到测试机器的IP上,或是使用一个还不存在的域名但又不想或不能去配置DNS。
在性能测试时,
不去做网络的DNSLookup(DNS解析消耗),这样使得压测更加关注服务器响应,压测更充分反应出实现代码的性能。
可以动态修改DNS缓存,无需修改host文件和http链接等不灵活的方式。
一个JVM进程可以对应一套域名绑定,相互之间不影响,可以实现多场景,多域名绑定的需求压测。
打开Java中的SecurityMaager时(如在Web容器Tomcat中的Web应用),Java的DNS缺省是不会失效的。如果域名绑定的IP变了,可以通过这个库重置DNS,作为一个临时的手段(强烈不推荐)。
通过JavaDsCacheMaipulatorTool修改运行中JVMDNSCache。无需应用包含了JavaDsCacheMaipulatorLibrary依赖(即Jar)。
或通过执行入口调用JavaDsCacheMaipulatorLibrary的方法,比如远程调用或是jvm-ssh-groovy-shell。需要应用已经包含了JavaDsCacheMaipulatorLibrary依赖(即Jar)。
UserGuide通过类DsCacheMaipulator设置DNS。
直接设置DsCacheMaipulator.setDsCache("www.hello.com", "192.168.1.1");DsCacheMaipulator.setDsCache("www.world.com", "1234:5678:0:0:0:0:0:200e"); // 支持IPv6地址 // 之后Java代码中使用到域名都会解析成上面指定的IP。 // 下面是一个简单获取域名对应的IP,演示一下: Strig ip = IetAddress.getByName("www.hello.com").getHostAddress(); // ip = "192.168.1.1" Strig ipv6 = IetAddress.getByName("www.world.com").getHostAddress(); // ipv6 = "1234:5678:0:0:0:0:0:200e"通过ds-cache.properties文件批量配置在代码测试中,会期望把域名绑定写在配置文件。
使用方式如下:
在ClassPath上,提供文件ds-cache.properties:
# 配置格式: # <host> = <ip> www.hello-world.com=192.168.1.1www.foo.com=192.168.1.2然后通过下面的一行代码完成批量设置:
DsCacheMaipulator.loadDsCacheCofig();在单元测试中,往往会写在测试类的setUp方法中,如:
@BeforeClass public static void beforeClass() throws Exceptio { DsCacheMaipulator.loadDsCacheCofig();}清空JVMDNSCacheDsCacheMaipulator.clearDsCache();删除一条DNSCache即重新LookupDNS。
DsCacheMaipulator.removeDsCache("baidu.com");查看JVMDNSCacheDsCache dsCache = DsCacheMaipulator.getWholeDsCache() System.out.pritl(dsCache);修改/查看JVM缺省的DNS的缓存时间// 查看缓存时间,单位秒。-1表示永远缓存,0表示不缓存 it cachePolicy = DsCacheMaipulator.getDsCachePolicy(); // 设置缓存时间DsCacheMaipulator.setDsCachePolicy(2); // 查看未命中条目的缓存时间DsCacheMaipulator.getDsNegativeCachePolicy() // 设置未命中条目的缓存时间DsCacheMaipulator.setDsNegativeCachePolicy(0);使用注意域名不区分大小写,域名会统一转成小写,再进入DNSCache。其中一个引发的现象是,DNS查询结果的域名会和输入的域名大小写不同,如果输入的域名有大写字母。
对于已经完成解析保存了IP的逻辑,修改JVMDNS缓存,不会生效!可以重新创建连接或Cliet解决。如对于HttpCliet:
HttpCliet cliet = ew HttpCliet();GetMethod m1 = ew GetMethod("https://www.baidu.com");cliet.executeMethod(m1); Strig cotet = m1.getResposeBodyAsStrig(); // 修改DNS,绑定到自己的机器DsCacheMaipulator.setDsCache("www.baidu.com", "192.168.1.1"); // 重新执行m1,仍然是老结果cliet.executeMethod(m1);Strig cotet = m1.getResposeBodyAsStrig(); // 重新创建GetMethod,才能得到自己机器上的结果GetMethod m2 = ew GetMethod("https://www.baidu.com");cliet.executeMethod(m2);cotet = m2.getResposeBodyAsStrig();更多详细功能参见类DsCacheMaipulator的文档说明。经过测试的JDK JDK 系统 O 备注 opejdk664-Bit Liux travis-ci oraclejdk764-Bit Liux travis-ci opejdk764-Bit Liux travis-ci oraclejdk864-Bit Liux travis-ci applejdk664-Bit Mac 个人Macjdk6及以下,Apple提供了自己的Java版本。 oraclejdk764-Bit Mac 个人Mac 从jdk7开始,Macjdk直接在Oracle下载。 oraclejdk864-Bit Mac 个人Mac oraclejdk764-Bit widowsserver2012r2 appveyor oraclejdk732-Bit widowsserver2012r2 appveyor oraclejdk864-Bit widowsserver2012r2 appveyor oraclejdk832-Bit widowsserver2012r2 appveyorPS:感谢 travis-ci 和 appveyor 免费提供了持续集成环境。
JavaAPIDocsJavaAPI文档地址: https://alibaba.github.io/java-ds-cache-maipulator/apidocs
依赖Mave示例:
<depedecy> <groupId>com.alibaba</groupId> <artifactId>ds-cache-maipulator</artifactId> <versio>1.5.0</versio></depedecy>可以在search.mave.org查看最新的版本。
DeveloperGuide如何修改JVM的DNSCacheJVM的DNSCache维护在类IetAddress的addressCache私有字段中,通过反射来修改,具体参见IetAddressCacheUtil。
注意修改JVM的DNSCache的线程安全问题JVM的DNSCache显然是全局共用的,所以修改需要同步以保证没有并发问题。
通过查看类IetAddress的实现可以确定:通过以addressCache字段为锁的sychroized块来保证线程安全。
其中关键代码(JDK7)如下:
/* * Cache the give hostame ad addresses. */ private static void cacheAddresses(Strig hostame, IetAddress[] addresses, boolea success) { hostame = hostame.toLowerCase(); sychroized (addressCache) { cacheIitIfNeeded(); if (success) { addressCache.put(hostame, addresses); } else { egativeCache.put(hostame, addresses); } }}IetAddressCacheUtil类中对DNSCache的读写也一致地加了以addressCache为锁的sychroized块,以保证线程安全。
需要测试不同版本JDK本库实现使用了JDK的非公开API,不同JDK实现会不一样,即需要有兼容逻辑,并对不同版本JDK进行测试,以保证功能。
目前测试包含JDK版本参见【经过测试的JDK】一节。
相关资料tahaichao的javahost项目,该项目的使用文档。本项目如何设置JavaDNSCache的解法来自该项目。刚开始在持续集成项目中碰到host绑定的问题时,也是使用该项目来解决的
类IetAddress的源代码:
JDK6的IetAddress
JDK7的IetAddress
JDK8的IetAddress
JVMNetworkigProperties - javadocs
javads解析缓存之源码解析,写得很完整,源码解析。给出值得注意的结论:
打开Java中的SecurityMaager,DNS缓存将不会失效。
否则,可访问的DNS解析缺省缓存30秒,不可访问的DNS解析缺省缓存10秒。
关于jvmdscache(域名缓存时间),给出“对于多条A记录是采用什么策略返回IP”的结论:
在缓存有效期内,取到的IP永远是缓存中全部A记录的第一条,并没有轮循之类的策略。
缓存失效之后重新进行DNS解析,因为每次域名解析返回的A记录顺序会发生变化(digwww.google.com测试可见),所以缓存中的数据顺序也变了,取到的IP也变化。
通过JAVA反射修改JDK1.6当中DNS缓存内容,给出了修改DNS缓存在性能测试下使用的场景。
javaIetAddress的dscache问题,说明HttpCliet需要重新创建GetMethod/PostMethod对象以使设置DNS生效问题。
DomaiNameSystem-wikipedia
JavaDNS FAQ
JavaDNScache viewer-stackoverflow
Disable DNScachig
FileOutputNode-JavaDNScachigpitfall-quickclarificatioadtips
评论