这篇文章上次修改于 765 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

1 DNS

DNS(Domain Name System),即域名系统,是互联网中最基础的一项服务,主要提供域名和 IP 地址之间映射关系的查询服务。

DNS 协议属于应用层,传输时基于 TCP 或 UDP(UDP 居多),监听的端口一般是 53。

域名解析是以递归的方式(从顶级域名开始),发送给每个层级的域名服务器,直到得到解析结果。该过程由 DNS 服务器负责。

每级服务器都会有最近解析记录的缓存,当缓存命中时,直接用缓存中的结果应答即可。缓存过期或不存在时,才需要递归查询。

查看域名服务器配置:

$ cat /etc/resolv.conf
nameserver 114.114.114.114

当访问某个网址时,需要通过 DNS 的 A 记录查询域名对应的 IP 地址:

$ nslookup time.geekbang.org
# 域名服务器及端口信息
Server:    114.114.114.114
Address:  114.114.114.114#53

# 非权威查询结果
Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.17

time.geekbang.org 的 IP 地址是 39.106.233.176。

dig 工具可展开整个递归查询过程:

# +trace表示开启跟踪查询
# +nodnssec表示禁止DNS安全扩展
$ dig +trace +nodnssec time.geekbang.org

; <<>> DiG 9.11.3-1ubuntu1.3-Ubuntu <<>> +trace +nodnssec time.geekbang.org
;; global options: +cmd
.      322086  IN  NS  m.root-servers.net.
.      322086  IN  NS  a.root-servers.net.
.      322086  IN  NS  i.root-servers.net.
.      322086  IN  NS  d.root-servers.net.
.      322086  IN  NS  g.root-servers.net.
.      322086  IN  NS  l.root-servers.net.
.      322086  IN  NS  c.root-servers.net.
.      322086  IN  NS  b.root-servers.net.
.      322086  IN  NS  h.root-servers.net.
.      322086  IN  NS  e.root-servers.net.
.      322086  IN  NS  k.root-servers.net.
.      322086  IN  NS  j.root-servers.net.
.      322086  IN  NS  f.root-servers.net.
;; Received 239 bytes from 114.114.114.114#53(114.114.114.114) in 1340 ms

org.      172800  IN  NS  a0.org.afilias-nst.info.
org.      172800  IN  NS  a2.org.afilias-nst.info.
org.      172800  IN  NS  b0.org.afilias-nst.org.
org.      172800  IN  NS  b2.org.afilias-nst.org.
org.      172800  IN  NS  c0.org.afilias-nst.info.
org.      172800  IN  NS  d0.org.afilias-nst.org.
;; Received 448 bytes from 198.97.190.53#53(h.root-servers.net) in 708 ms

geekbang.org.    86400  IN  NS  dns9.hichina.com.
geekbang.org.    86400  IN  NS  dns10.hichina.com.
;; Received 96 bytes from 199.19.54.1#53(b0.org.afilias-nst.org) in 1833 ms

time.geekbang.org.  600  IN  A  39.106.233.176
;; Received 62 bytes from 140.205.41.16#53(dns10.hichina.com) in 4 ms
  • 从 114.114.114.114 查到一些根 . 域名服务器的 NS 记录。NS 记录表示域名对应的域名服务区地址。
  • 从 NS 记录选中一个(h.root-servers.net),并查询顶级域名 .org 的 NS 记录。
  • 从 .org 的 NS 记录中选中一个(b0.org.afilias-nst.org),并查询二级域名 geekbang.org 的 NS 记录。
  • 从 geekbang.org 的 NS 记录中选中一个(dns10.hichina.com),查到最终主机 time.geekbang.org 的 A 记录。

有时候也需要对局域网内部的主机进行域名解析,可将主机名和 IP 地址的映射关系写入本机的 /etc/hosts 文件中。也可以在内网中搭建自定义的 DNS 服务器。

2 案例

2.1 DNS 解析失败

执行 DNS 查询:

$ nslookup time.geekbang.org
;; connection timed out; no servers could be reached

阻塞后失败。调试:

$ nslookup -debug time.geekbang.org
;; Connection to 127.0.0.1#53(127.0.0.1) for time.geekbang.org failed: connection refused.
;; Connection to ::1#53(::1) for time.geekbang.org failed: address not available.

发现连向的是环回地址,说明没有配置 DNS 服务器地址,验证:

$ cat /etc/resolv.conf

没有输出。配置 DNS 服务器地址后再次解析:

$ echo "nameserver 114.114.114.114" > /etc/resolv.conf
$ nslookup time.geekbang.org
Server:    114.114.114.114
Address:  114.114.114.114#53

Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.176

解析成功。

2.2 DNS 解析不稳定

$ time nslookup time.geekbang.org
Server:    8.8.8.8
Address:  8.8.8.8#53

Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.176

real  0m10.349s
user  0m0.004s
sys  0m0.0

DNS 解析耗时达到 10s,较慢,多次运行上述命令可能还会发送丢包错误。可能的原因:

  • DNS 服务器本身响应慢且不稳定。通过 nslookup 输出得知 8.8.8.8 是谷歌提供的,有问题的可能性较低。
  • 本机到 DNS 服务器的网络延迟较大。可能性较大。
  • 或者 DNS 请求或响应包在某些情况下被链路中的网络设备弄丢了。

查看本机到 8.8.8.8 的网络延迟:

$ ping -c3 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=31 time=137.637 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=31 time=144.743 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=31 time=138.576 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 137.637/140.319/144.743/3.152 ms

网络延迟达到 140ms,延迟较大,多次运行还会出现丢包现象。

更换一个延时更小的 DNS 服务器,如 114.114.114.114:

$ ping -c3 114.114.114.114
PING 114.114.114.114 (114.114.114.114): 56 data bytes
64 bytes from 114.114.114.114: icmp_seq=0 ttl=67 time=31.130 ms
64 bytes from 114.114.114.114: icmp_seq=1 ttl=56 time=31.302 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=56 time=31.250 ms
--- 114.114.114.114 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 31.130/31.227/31.302/0.072 ms

延迟确实小了一些。更换 DNS 服务器并再次执行 nslookup:

$ echo nameserver 114.114.114.114 > /etc/resolv.conf
$ time nslookup time.geekbang.org
Server:    114.114.114.114
Address:  114.114.114.114#53

Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.176

real    0m0.064s
user    0m0.007s
sys     0m0.006s

64ms 完成解析,比之前好了很多。

但多次运行 nslookup 命令,并不是每次结果都很好,有时候会达到 1s,这时候需要开启 DNS 缓存(Ubuntu 18.04 及之后的版本会自动开启:

$ /etc/init.d/dnsmasq start
 * Starting DNS forwarder and DHCP server dnsmasq                    [ OK ]

修改 DNS 服务器为 dnsmasq 的监听地址,这里为 127.0.0.1,然后多次执行 nslookup 命令:

$ echo nameserver 127.0.0.1 > /etc/resolv.conf
$ time nslookup time.geekbang.org
Server:    127.0.0.1
Address:  127.0.0.1#53

Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.176

real  0m0.492s
user  0m0.007s
sys  0m0.006s

/# time nslookup time.geekbang.org
Server:    127.0.0.1
Address:  127.0.0.1#53

Non-authoritative answer:
Name:  time.geekbang.org
Address: 39.106.233.176

real  0m0.011s
user  0m0.008s
sys  0m0.003s

可以看到除了第一次查询较慢外,后续的 DNS 解析都比较稳定。

参考

倪朋飞. Linux 性能优化实战.