安卓系统dns缓存策略

背景
安卓客户端上报出不少UnknownHostException,引起了大家的重视,于是决定深入研究一番。
UnknownHostException是个什么异常?让我们来谷歌的源代码是怎么说的:

/**
* Thrown when a hostname can not be resolved.
*/

原来就是说域名无法被解析的时候会抛这个异常啊。那我就先来大致了解一下域名解析在客户端是怎么做的吧。
 

基本原理
通常客户端在进行接口调用、页面访问的时候都会通过域名来定位目标主机,从而与目标主机中的服务进行通信。不过,要定位一个进程,需要的是IP+端口号。所以我们要先把域名解析成IP形式。
这个过程大致是:客户端向域名服务器发送一个UDP请求,查询域名相对应的IP。服务器收到查询请求后,向客户端返回相应的IP。好吧,没有这么简单,实际过程要复杂得多。


我们这次会把注意力集中在客户端一侧,至于如何递归查询就不深入讨论了。下面我们抓包举例,这是友盟sdk在向它的服务器上传数据的开始过程。

 


首先,发送DNS查询请求。很幸运,响应很快就返回了,而且IP地址还不止一个。是的,DNS查询的返回可能会是多个IP地址。
然后,客户端向其中一个IP地址发起了经典的3次握手:SYN – SYN,ACK – ACK。
接下来,就可以发送数据了。
我们发现,DNS查询需要向域名服务器发请求,DNS服务器还有可能会进行一系列的递归查询。这是一个并不高效的过程,而且实际上域名所对应的IP并不经常变化。为了提高效率,工程师们就开始对DNS查询的结果进行层层缓存。

 

 

 

DNS缓存

言归正传,我们看看安卓系统到底都做了什么缓存。
安卓系统对DNS缓存 有两个地方,一个是虚拟机层,一个是框架层 java.net.InetAddress类内部维护了一个缓存。系统会先从框架层缓存中查找,如果没有找到,再到虚拟机层查找。缓存命中,则直接返回缓存IP,而不会真的发送DNS请求。
缓存的有效期被称为TTL(time to live)。
DNS查询结果缓存分2种:成功(positive)的查询和失败(negative)的查询(比如域名不存在)。而系统不仅会缓存成功的查询结果,还会把失败的结果也缓存起来!
缓存时效的修改
1)虚拟机层

 

Security.setProperty("networkaddress.cache.ttl", String.valueOf(0));  
Security.setProperty("networkaddress.cache.negative.ttl", String.valueOf(0))

参数单位为秒,0代表不缓存,-1代表永久缓存(慎用)。
2)框架层
很不幸,框架层的缓存有效期是无法修改的。让我们来看看AddressCache.java:

// Default time-to-live for positive cache entries. 600 seconds (10 minutes).
private static final long DEFAULT_POSITIVE_TTL_NANOS = 600 * 1000000000L;
// Default time-to-live for negative cache entries. 10 seconds.
private static final long DEFAULT_NEGATIVE_TTL_NANOS = 10 * 1000000000L;

成功的查询缓存10分钟,失败的查询缓存10秒钟。
上面是OS v4.1及以下版本的实现。就是说当一次查询失败后,框架层会把错误信息直接作为value缓存起来,并保持10秒的有效期。之后10秒内对于同一个域名的查询都会直接抛出UnknownHostException。

/**
  * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
  * negative cache entry.)
  */
public void putUnknownHost(String hostname, String detailMessage) {
    put(hostname, detailMessage);
}

这个设计有些不够人性,对于接口访问密集的场景,会造成大量UnknownHostException。估计谷歌也意识到了这个问题,在v4.2之后,框架层成功和失败的缓存时效都变成了2秒。

// The TTL for the Java-level cache is short, just 2s.
private static final long TTL_NANOS = 2 * 1000000000L;

 

业务场景分析
结合App的场景,10秒的缓存时效的确有一定问题。如果一个接口发生域名解析失败,接下来的10秒内所有接口都会发生UnknownHostException。即便没有集中的接口访问,若安卓客户端10秒内重试,那么必然会再发生一次UnknownHostException。这便造成了安卓客户端在一定程度上UnknownHostException数量的升高。
不过,目前大部分设备的系统版本都比较高,仍然需要进一步研究,找出问题根源。

 

 

-------------------------------------原创内容,转载请说明出处-----------------------------------------

欢迎联系

微信:oscaryue001

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值