安卓系统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;

业务场景分析

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

阅读更多
换一批

DNS问题导至安卓系统无法上网

11-06

前两天用户反应手机WIFI无法打开网页,派了技术去处理,发现除采用安卓系统的终端,如:苹果手机,苹果平板,WIN系统的台式机,WIN系统的笔记本都能打开页.rn 亲去现场发现用户采用了一台深信服的AC作上网认证,内网采用DHCP SERVER分配IP,DHCP SERVER做在核 心交换机上DNS是61.139.2.69 202.98.96.68,无线AP采用的一般的无线路由器,没做NAT,安卓系统的终端上网时弹不出认证页面,其它操作系统的终端没问题,怀疑是深信服AC问题,在安卓上采用手工输入AC的认证地址,在认证时没反应.再次进行认证会提示已经已经认证,也就是说AC认证是成功了的,由AC作的是网桥,将AC跳开用网线直连路由器和交换机,安卓系统还是有问题,这样就排除了AC的问题,但问题出在什么地方呢:rn 仔细检查了各终端获得IP、网关、DNS发现都是一样的,但就是安卓系统无法打开网页,郁闷了,客户网开玩笑说看来只有让大家都换苹果了哦 rn后面在笔记本上采用手工输入四川的DNS 61.139.2.69,不设备用DNS,发现笔记本无法打开网页了,改成备用的DNS 202.98.96.68 发现能够打开,由此判断是61.139.2.69的DNS出问题了,在交换机上将DHCP SERVER的DNS设置为202.98.96.68 61.139.2.69安卓重新获取IP后正常。rn 为什么会出现此问题呢?难道是安卓系统只能识别第一个DNS,苹果可以识别两个DNS?不解中

没有更多推荐了,返回首页