Android DNS Local Cache的学习


最近在学习DNS加速,所以就查了下Android本地DNS的相关知识。

Android 官网有这么一句话
点击这里查看

DNS caching

In Android 4.0 (Ice Cream Sandwich) and earlier, DNS caching was performed both by InetAddress and by the C library, which meant that DNS TTLs could not be honored correctly. In later releases, caching is done solely by the C library and DNS TTLs are honored.

这句话里面的TTLS是cache过期时间,这句话说明在android4.0和早期版本里面,设置DNS的cache ttls并不会起效,我们只能在之后的版本里设置TTL。

根据JAVA的API来看

networkaddress.cache.ttl
这个属性可以控制DNS Cache
并且以ews.500.com来测试来看
如果缓存10S
第一次获取到的间隔是20毫秒
如果10S内再获取 一般是0
110S外获取 还是20毫秒左右
说明起效

networkaddress.cache.negative.ttl

这个属性是控制如果查询不的DNS 失效的域名缓存时间

测试结果 默认可以得到是10S 可以设置 并且成功 说明起效

但是在Android上 Android5.0为例

这两个属性并不起效

以上两个结果 这个并没有什么特别明显的效果

并且得到的值都是null 设置后时间间隔也并不起效

翻看源码

以Android 4.4.2为例:
在java.net.AddressCache里面对Address进行了缓存
并且存取方式也不一样

// The TTL for the Java-level cache is short, just 2s.

private static final long TTL_NANOS = 2 * 1000000000L;

从上面代码得出。这里默认的TTL是2S

并且 这里的Cache是无法改变的 从这里可以得出 无法改变系统缓存时间来达到目的

之后 对比ApacheHttpClient 发现 Android其实阉割了原版的HttpClient 去掉了之前的部分功能 使其更能适应移动设备的网络请求
但同时其中一些类是新版本httpcore已经抛弃了的

其实是Apache的HttpClient和HttpCore部分有用代码的合集放入进去的

研究源码发现 httpclient4.3版本可以自定义DNS但是android版本的httpclient4.0的 所以如果想要自定义DNS需要用新版本的httpclient
4.3版本可以重写DnsResolver来使得系统使用自定义配置,但同时你要重写HttpClientConnectionManager

为了避免网络请求出现问题 这种方式暂时弃用 暂时采用现有比较成熟的请求方式

在这个前提下

最终采用的方式是 在Http请求头里面加入Host参数 这个参数是自己的域名 并且直接用IP去访问 如果不加入Host 直接用IP访问 会被Forbidden
但是采用头部加入Host的方式可行

这种方式 推测风险是这样的

可能会出现网络切换等 使得DNS变化 网络请求无效

以ews.500.com为例

切换代理为美国IP 拿到的DNS为61.140.14.19

本地IP 拿到的DNS为 113.105.144.42

经测试两个IP在有HOST的情况下都可以直接访问 但在本地IP访问美国DNS的时候 速度可能不是特别快 但速度依旧快于直接访问域名 除非出现DNS缓存服务挂了的情况下 否则一般不会出现问题

测试数据如下:

以50次测试为例:

域名的情况:平均为85ms左右 并且有四次左右的链接超时(可能跟本地网速有关 忽略)

本地访问本地拿到的DNS 平局为35m左右

本地访问拿到的美国DNS 平均为50ms左右

测试证明:采用Host头的方式 可行,并且本地采用这样的策略

每次网络请求前,如果本地没有缓存DNS,先去请求DNS

InetAddress.getAllByName("ews.500.com");

如果本地已经缓存了DNS就使用。

当检测到网络切换的情况下,清空本地缓存DNS,在下次请求时候重新获取

并且根据用户使用习惯,暂定在的时候10分钟清空一次本地缓存的DNS

以便能及时拿到最优的DNS

如果出现超时等网络异常 立马清空DNS缓存

Tips:

   记得:一定要异步去请求DNS  因为有些情况下很慢   我测试的最长是50多s 而且没异常捕捉       
还要记得  拿到后先验证下是否通  否则3g wap方式可能会不通  证明DNS不可用

Warning:

这里只是对本地cache的一些查询,主要是为了做DNS加速时候用的,getAllByName得到的DNS IP只是本地的 不能拿来加速 ,稍后会讲一下DNS加速的方案