slan's blog

有梦就去追,累了就休息

DNS优先查询ipv6地址导致curl延时

date: 2016-03-29 16:09:15

起因

昨天有大活动,服务器进行扩容,跑的新封装的docker镜像,系统ubuntu14,发现用curl调用微信支付接口出现延时。能正确返回结果,但一般有三秒以上的延时。由于线上服务在跑,没有机会详细调试,于是先忽略之。

复现

今天在本地复现,一个简单的tcp连接,没有其他业务操作,时间花了3秒+,肯定哪里出了问题:

故障

1和2之间花了4秒,代码只有golang的dial函数,测试完整代码如下:

package main

import (
    "net"
    "fmt"
    "log"
)

func main() {

    log.Println(1);

    conn,err:=net.Dial("tcp","api.mch.weixin.qq.com:443")

    log.Println(2);

    if err!=nil {

        fmt.Printf("error: %v",err);

    }

    log.Println(3);

   conn.Write([]byte("hello"));

   log.Printf("remote ip: %s",conn.RemoteAddr().String())

   log.Println(4);
}

反馈给微信技术

联系到昨天在阿里云的服务器上的现象,怀疑是不是微信支付服务器出现网络问题,于是发封邮件反馈之,不料马上被呛了回来,我只能说:从来没有见过如此理直气壮让我滚回去查代码的客服:

微信反馈

相比而言阿里的同学还是好多了,发工单基本能回,不是他们问题也能帮忙协助分析,给些建议。

继续分析

对这样的回复我只能表示无语,不过也只能无奈的继续分析,本来准备抓包把结果丢他们糊他们一脸,结果却发现了一些有意思的事情:

抓包

先查询A记录,然后被cname然后查询AAAA记录,AAAA记录就是ipv6版本的A记录,结果dns服务器返回了查询失败,几个来回几秒的时间就过去了。然后ipv6地址解析失败,继续解析ipv4的地址,能正常解析,访问了。

所以延时的原因应该就清楚了,curl先去解析ipv6的记录,然后再解析ipv4的记录,这样出现了延时

疑问

为什么同样是ubuntu14,我们其他的服务器没有出现,单单docker里面每次都延时?

答:其他服务器默认开启了nscd,缓存了dns查询记录,不会每次查询,所以对业务的影响就很小了。

如何解决

优先方案是开nscd缓存服务,因为不只是解析ipv6的问题,频繁解析dns有很大的时间开销。

然后换个好点的dns,优先ipv6策略越来越多的被使用,为什么影响还不大,因为即使是dns查询失败也可以很快时间的返回,试验过好几个dns,有的dnsAAAA记录即使没有,但是返回时间很短,阿里的dns就卡了数秒,可能跟dns策略有关系。

修改系统配置可能有用,有搜到/etc/gai.conf,但是试验是没效果的,有兴趣的可以研究下。参考:https://community.rackspace.com/products/f/25/t/5110

最次是写host文件,紧急情况下可以用,但一定只能作为临时救急手段。