我们已经准备好了,你呢?

2024我们与您携手共赢,为您的企业形象保驾护航!

作者丨小楼

最近,我在DNS解析中遇到了一个小陷阱。 虽然问题解决了,但是排查过程却相当曲折。 到最后,我还是没有弄清楚一件事。 我想和大家分享一下整个过程。

背景

我负责的服务最近需要更换机器。 很多朋友可能不知道什么是换机,因为平时接触不到。 下面我简单解释一下什么是换机以及为什么需要换机。

通俗地说,机器更换就是更换机器,将服务从一台机器迁移到另一台机器。

为什么要换机? 表面原因可能是机器硬件有故障或者机器已经过保修期。

有的朋友可能要问,我在公司也负责很多服务,为什么我从来没有换过机器呢? 原因可能是使用了容器,并不是直接部署在物理机上,更换机器的任务转移到了云平台的运维人员身上; 也可能是你有专门的运维来帮忙处理这件事。 对于开发者来说,几乎是透明的。

为什么我负责的服务需要更换? 因为机器已经过保修期了。 为什么服务部署在物理机上? 因为它是一项基础服务,所以它不同于一般服务。 它有一些限制,只能部署在物理机上。 为什么没有运维人员帮忙? 因为公司很多基础服务都是自运和维护的,所以开发者既做开发,又做运维。

域名解析速度_域名解析慢的原因_域名解析时间太长

说完换机,我们再来说说这个基础服务。 它是一个用 Go 编写的服务,不断发送 HTTP 请求。 只要记住这一点,其他的都不重要。

更换该服务的机器后,HTTP 请求时间慢了很多。 如下图所示,黄色机器为旧机,蓝色机器为新机。 该指标的值是HTTP请求时间(毫秒),大约相差1.5倍。 这就是我今天要分享的问题。 接下来我就讲一下我的故障排除过程。

域名解析速度_域名解析时间太长_域名解析慢的原因

故障排除

遇到这种情况,首先检查机器的各项指标,如CPU、网络情况等,看是否有异常情况,并确认是否受到其他指标的影响。 但看了一圈,发现新机的各项指标甚至比旧机还要好。

然后我就询问提供机器的同学,看看机器有没有什么异常,结果没有。

由于HTTP请求变慢了,我想到看看请求的哪一部分变慢了。 使用以下命令来测试它。 我就用百度的域名代替域名:

卷曲 -o /dev/null -s -w %{}::%{}::%{}"\n"

这里每个参数代表的含义(也可以是其他一些参数):

这样就可以看到域名解析、连接、传输各个阶段的时间消耗。 比较新旧机器。 如果有一项特别高,那么这一项肯定有问题。

只需算一下:

虽然从这次的测试数据来看,新机的DNS解析似乎慢了一些,但如果仔细看这个值,它对请求整体耗时几乎没有影响。 经过多次测试,我们发现两台机器的DNS解析其实是差不多的。

但我还是没有信心。 验证DNS是否有问题,然后使用dig命令重试。

执行的时候明显感觉卡住了,确定是DNS有问题。

域名解析速度_域名解析慢的原因_域名解析时间太长

问题解决了

起初,我在网上搜索了慢速DNS相关的文章,找到了一篇文章《 DNS in Go net 》,但稍微验证了一下,与我的案例无关。 这篇文章是一篇好文章。 所以我也贴了一个链接,有兴趣的可以看一下。

“解决 Go 网络库中的 DNS 问题”

然后我就去找网络群里的同学。 网络群里的同学一看,就知道原因了。 他们说新机器还没有安装。 这意味着什么? 不要惊慌,先上网查一下,再接电话。

域名解析慢的原因_域名解析速度_域名解析时间太长

提供DNS缓存和DHCP服务功能。 作为域名解析服务器 (DNS),您可以通过缓存 DNS 请求来提高访问 URL 的连接速度。 作为DHCP服务器,它可以用来分配内网IP地址,并为局域网计算机提供路由。 DNS和DHCP两种功能可以同时实现,也可以分别实现。 轻量级且易于配置,适合个人用户或主机数量少于50台的网络。 此外,它还配备了 PXE 服务器。

简单来说,它起到DNS缓存的作用,提高DNS查询速度。

说到这里,我补充一点知识。 我一直以为DNS会被操作系统缓存。 不知道大家是否有这样的错觉,但实际上,Linux下如果没有特殊处理,每次DNS解析都要查询DNS服务器。 这是一个很好的证明。 您可以尝试使用DNS捕获包。 我当时也尝试过,每次都会远程获取DNS解析结果。 这个结论也可以在《TCP/IP详解卷一》中的相关描述中找到:

域名解析时间太长_域名解析慢的原因_域名解析速度

只有较新的Linux系统才可以在客户端缓存DNS,而且Linux系统需要手动开启,所以默认情况下必须远程获取DNS缓存。

言归正传,网络组的同学说要么安装一台,要么更改DNS服务器的配置,也就是/etc/.conf文件。 由于机器上已经有服务,因此他们选择了更改配置的更安全的方法。

更改之前,/etc/.conf的第一行是127.0.0.1,这意味着本地机器也被用作DNS服务器,但实际上本地DNS服务并没有启用。 网络群的同学说可以通过配置或者安装第一行来去掉。 。

首先把127.0.0.1的配置去掉,结果还是一样!

域名解析慢的原因_域名解析速度_域名解析时间太长

然后添加127.0.0.1的配置并安装,时间消耗减少了。

域名解析速度_域名解析慢的原因_域名解析时间太长

整个解决过程中,程序没有重启,唯一的变量是安装了,所以这肯定是DNS的错。

问题反思

虽然问题解决了,但我还是有几个疑问:

为什么配置了127.0.0.1的DNS却没有开启?

为什么删除 127.0.0.1 配置没有效果?

第一个问题比较容易弄清楚。 我问了系统部的同学,他说本来应该是启用的,但是出了点小错误,只配置了127.0.0.1。

域名解析慢的原因_域名解析速度_域名解析时间太长

我们再来看第二个问题。 DNS本地缓存和远程查询差距这么大吗? 据网络群的同学介绍,DNS是公司搭建的。 内网传输其实并不慢,使用dig很容易测试。 使用第2行和第3行的DNS进行测试时,发现dig的速度非常快。

挖@主机

为什么127.0.0.1的配置变得这么慢? 我们先从我的一些猜测开始,一一证明。 不过在猜测之前,我们先来了解一下Go程序解析DNS的过程。

Go的DNS解析流程

Go的DNS解析分为两种:

由于需要适配各种平台,所以每个平台都有相应的实现。

这部分代码位于net包下。 追踪它非常简单。 编写代码建立连接,一步步调试,找到域名解析的地方。

我直接从.go文件的方法告诉你吧。 当然,这仅适用于Unix系统,包括Mac和Linux。 然而,Mac 不使用纯 Go 代码。 被迫使用cgo。 在Linux上,没有特殊配置,使用纯Go代码。 Go实现的DNS解析,以下代码以Linux为例:

func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
 // ①强制走纯Go的DNS解析器
 if r.preferGo() {
  return r.goLookupIP(ctx, host)
 }
 // ②根据解析顺序解析
 order := systemConf().hostLookupOrder(r, host)
 if order == hostLookupCgo {
  if addrs, err, ok := cgoLookupIP(ctx, network, host); ok {
   return addrs, err
  }
  // cgo not available (or netgo); fall back to Go's DNS resolver
  // ③如果cgo搞不定,降级到先文件再DNS
  order = hostLookupFilesDNS
 }
 ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
 return ips, err
}

以下是以下类型的订单:

hostLookupCgo      hostLookupOrder = iota // cgo
hostLookupFilesDNS                 // 文件优先
hostLookupDNSFiles                 // DNS优先
hostLookupFiles                    // 只查文件
hostLookupDNS                      // 只查DNS

这里的文件是/etc/hosts,最终被调用了,但是这个方法的代码太长,所以这里只讲一下大概的流程:

如果需要先查询hosts文件,就先检查一下,找到就直接返回。

读取/etc/.conf文件,取出DNS配置,每5秒更新一次

构造 DNS 请求并将其发送到服务器。 UDP 读取的默认超时时间为 5 秒,可以在 /etc/.conf 文件中配置。 同一域名的不同类型(如ipv4、ipv6)的查询可以配置为并行或串行。 好的

轮询机制用于向 DNS 发送请求。 如果其中一个请求失败,则将推迟到下一个请求。 默认重试次数为2次,可以在/etc/.conf文件中配置。

最后,解析并返回查询结果。 如果结果为空,且配置了hosts文件,则查询一次该文件。

好了,流程就简单介绍到这里,接下来我就验证一下我的一些猜测。

猜测1:Go在程序启动时只读取一次/etc/.conf文件吗?

这个猜想的依据是,如果查询DNS时得到的是127.0.0.1的DNS,而本地没有启用DNS服务,可能会很慢,而且如果修改了配置文件,如果Go程序只读取文件一旦在初始化的时候,那么自然改变配置文件就没有效果了。

但这种情况并非如此。 如上所述,Go 每 5 秒延迟更新一次 DNS 配置文件。

func (conf *resolverConfig) tryUpdate(name string) {
 // 初始化,只做一次
  conf.initOnce.Do(conf.init)
  // ...
 now := time.Now()
 if conf.lastChecked.After(now.Add(-5 * time.Second)) {
  return
 }
 conf.lastChecked = now
  // ... 
 dnsConf := dnsReadConfig(name)
 conf.mu.Lock()
 conf.dnsConfig = dnsConf
 conf.mu.Unlock()
}

我做了一个实验,写了一个DNS解析的测试代码。 我在配置了 127.0.0.1 但未打开的服务器上运行它。 我抓到了127.0.0.1 53端口(DNS默认端口)的数据包,发现有流量。 ,然后修改/etc/.conf配置,去掉127.0.0.1,发现无法捕获127.0.0.1端口53的流量。 这证明与代码逻辑是一致的,这个猜想不成立。

猜想二:远程DNS查询比本地慢很多

这个很容易证明,还是用上面的程序

在没有 127.0.0.1 配置的服务器上运行

在配置并启用 127.0.0.1 的服务器上运行

结果两者的耗时几乎是一样的,甚至在配置了127.0.0.1但未开启的服务器上耗时也基本相同。

这说明无论怎么查询DNS,都不慢。

猜想三:是否是并发太高导致的?

为什么我会有这个猜想呢? 首先,在线QPS在50左右,与上面测试的场景不同。 其次,我看到了上面代码中的锁。 并发高后,锁带来的开销增加?

我写了一段100并发的代码来查询DNS,发现这段代码在以下三种场景下花费的时间差不多:

没有配置 127.0.0.1 的服务器

有一个服务器已配置并在 127.0.0.1 开启

配置了127.0.0.1但未开启的服务器

同时我也问过网络群里的一个同学,他说DNS可以承受百万QPS,对服务器没有压力。

域名解析时间太长_域名解析慢的原因_域名解析速度

终于

写到最后,我emo~虽然问题已经解决了,但是我还是不知道为什么当时DNS查询慢。 如果您看完文章知道问题出在哪里,或者有什么更好的排查方法,欢迎大家一起讨论。 反正我是没法再查了。

最后我想说,写文章很辛苦,需要一些鼓励。 请点赞、阅读并关注。 下一期再见。

域名解析时间太长_域名解析慢的原因_域名解析速度

1、

2、

3.

4.

5.

域名解析时间太长_域名解析慢的原因_域名解析速度

二维码
扫一扫在手机端查看

本文链接:https://by928.com/1270.html     转载请注明出处和本文链接!请遵守 《网站协议》
我们凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求,请立即点击咨询我们或拨打咨询热线: 13761152229,我们会详细为你一一解答你心中的疑难。

项目经理在线

我们已经准备好了,你呢?

2020我们与您携手共赢,为您的企业形象保驾护航!

在线客服
联系方式

热线电话

13761152229

上班时间

周一到周五

公司电话

二维码
微信
线