Linux性能优化实战学习笔记:第三十七讲

1、上节回顾

上一节,我带你一块儿学习了网络性能的评估方法。简单回顾一下,Linux 网络基于 TCP/IP协议栈构建,而在协议栈的不一样层,咱们所关注的网络性能也不尽相同。git

在应用层,咱们关注的是应用程序的并发链接数、每秒请求数、处理延迟、错误数等,可使用 wrk、Jmeter 等工具,模拟用户的负载,获得想要的测试结果。github

而在传输层,咱们关注的是 TCP、UDP 等传输层协议的工做情况,好比 TCP 链接数、TCP 重传、TCP 错误数等。此时,你可使用 iperf、netperf 等,来测试 TCP 或 UDP的性能。docker

再向下到网络层,咱们关注的则是网络包的处理能力,即 PPS。Linux 内核自带的pktgen,就能够帮你测试这个指标。ubuntu

因为低层协议是高层协议的基础,因此通常状况下,咱们所说的网络优化,实际上包含了整个网络协议栈的全部层的优化。固然,性能要求不一样,具体须要优化的位置和目标并不
彻底相同。后端

前面在评估网络性能(好比 HTTP 性能)时,咱们在测试工具中指定了网络服务的 IP 地址。IP 地址是 TCP/IP 协议中,用来肯定通讯双方的一个重要标识。每一个 IP 地址又包括了
主机号和网络号两部分。相同网络号的主机组成一个子网;不一样子网再经过路由器链接,组成一个庞大的网络。浏览器

然而,IP 地址虽然方便了机器的通讯,却给访问这些服务的人们,带来了很重的记忆负担。我相信,没几我的能记得住 Github 所在的 IP 地址,由于这串字符,对人脑来讲并没
有什么含义,不符合咱们的记忆逻辑。缓存

不过,这并不妨碍咱们常用这个服务。为何呢?固然是由于还有更简单、方便的方式。咱们能够经过域名 github.com 访问,而不是必须依靠具体的 IP 地址,这其实正是域
名系统 DNS 的由来。安全

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

DNS 不只方便了人们访问不一样的互联网服务,更为不少应用提供了,动态服务发现和全局负载均衡(Global Server Load Balance,GSLB)的机制。这样,DNS 就能够选择离用
户最近的 IP 来提供服务。即便后端服务的 IP 地址发生变化,用户依然能够用相同域名来访问。服务器

DNS 显然是咱们工做中基础而重要的一个环节。那么,DNS 出现问题时,又该如何分析和排查呢?今天,我就带你一块儿来看看这个问题。

2、域名与 DNS 解析

域名咱们自己都比较熟悉,由一串用点分割开的字符组成,被用做互联网中的某一台或某一组计算机的名称,目的就是为了方便识别,互联网中提供各类服务的主机位置。

要注意,域名是全球惟一的,须要经过专门的域名注册商才能够申请注册。为了组织全球互联网中的众多计算机,域名一样用点来分开,造成一个分层的结构。而每一个被点分割开
的字符串,就构成了域名中的一个层级,而且位置越靠后,层级越高。

咱们以极客时间的网站 time.geekbang.org 为例,来理解域名的含义。这个字符串中,最后面的 org 是顶级域名,中间的 geekbang 是二级域名,而最左边的 time 则是三级域名。

以下图所示,注意点(.)是全部域名的根,也就是说全部域名都以点做为后缀,也能够理解为,在域名解析的过程当中,全部域名都以点结束。

经过理解这几个概念,你能够看出,域名主要是为了方便让人记住,而 IP 地址是机器间的通讯的真正机制。把域名转换为 IP 地址的服务,也就是咱们开头提到的,域名解析服务
(DNS),而对应的服务器就是域名服务器,网络协议则是 DNS 协议。

这里注意,DNS 协议在 TCP/IP 栈中属于应用层,不过实际传输仍是基于 UDP 或者 TCP协议(UDP 居多) ,而且域名服务器通常监听在端口 53 上。

既然域名以分层的结构进行管理,相对应的,域名解析其实也是用递归的方式(从顶级开始,以此类推),发送给每一个层级的域名服务器,直到获得解析结果。

不过不要担忧,递归查询的过程并不须要你亲自操做,DNS 服务器会替你完成,你要作的,只是预先配置一个可用的 DNS 服务器就能够了。

固然,咱们知道,一般来讲,每级 DNS 服务器,都会有最近解析记录的缓存。当缓存命中时,直接用缓存中的记录应答就能够了。若是缓存过时或者不存在,才须要用刚刚提到
的递归方式查询。

因此,系统管理员在配置 Linux 系统的网络时,除了须要配置 IP 地址,还须要给它配置DNS 服务器,这样它才能够经过域名来访问外部服务。

好比,个人系统配置的就是 114.114.114.114 这个域名服务器。你能够执行下面的命令,来查询你的系统配置:

cat /etc/resolv.conf
nameserver 114.114.114.114

实际测试命令以下:

[root@69 ~]# cat /etc/resolv.conf
; generated by /sbin/dhclient-script
nameserver 218.30.19.40
nameserver 61.134.1.4

另外,DNS 服务经过资源记录的方式,来管理全部数据,它支持 A、CNAME、MX、NS、PTR 等多种类型的记录。好比:

A 记录,用来把域名转换成 IP 地址;
CNAME 记录,用来建立别名;
而 NS 记录,则表示该域名对应的域名服务器地址

简单来讲,当咱们访问某个网址时,就须要经过 DNS 的 A 记录,查询该域名对应的 IP 地址,而后再经过该 IP 来访问 Web 服务。

好比,仍是以极客时间的网站 time.geekbang.org 为例,执行下面的 nslookup 命令,就能够查询到这个域名的 A 记录,能够看到,它的 IP 地址是 39.106.233.176:

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

实际测试命令以下:

[root@69 ~]# nslookup time.geekbang.org
Server:		218.30.19.40
Address:	218.30.19.40#53

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

这里要注意,因为 114.114.114.114 并非直接管理 time.geekbang.org 的域名服务器,因此查询结果是非权威的。使用上面的命令,你只能获得 114.114.114.114 查询的结果。

前面还提到了,若是没有命中缓存,DNS 查询其实是一个递归过程,那有没有方法能够知道整个递归查询的执行呢?

其实除了 nslookup,另一个经常使用的 DNS 解析工具 dig ,就提供了 trace 功能,能够展现递归查询的整个过程。好比你能够执行下面的命令,获得查询结果:

# +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

实际测试命令以下:

[root@69 ~]# dig +trace +nodnssec time.geekbang.org

; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.68.rc1.el6_10.3 <<>> +trace +nodnssec time.geekbang.org
;; global options: +cmd
.			794	IN	NS	h.root-servers.net.
.			794	IN	NS	k.root-servers.net.
.			794	IN	NS	m.root-servers.net.
.			794	IN	NS	d.root-servers.net.
.			794	IN	NS	b.root-servers.net.
.			794	IN	NS	j.root-servers.net.
.			794	IN	NS	l.root-servers.net.
.			794	IN	NS	g.root-servers.net.
.			794	IN	NS	e.root-servers.net.
.			794	IN	NS	f.root-servers.net.
.			794	IN	NS	c.root-servers.net.
.			794	IN	NS	a.root-servers.net.
.			794	IN	NS	i.root-servers.net.
;; Received 228 bytes from 218.30.19.40#53(218.30.19.40) in 52 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 437 bytes from 199.7.83.42#53(199.7.83.42) in 254 ms

geekbang.org.		86400	IN	NS	dns9.hichina.com.
geekbang.org.		86400	IN	NS	dns10.hichina.com.
;; Received 85 bytes from 199.249.120.1#53(199.249.120.1) in 117 ms

time.geekbang.org.	600	IN	A	39.106.233.176
;; Received 51 bytes from 140.205.81.16#53(140.205.81.16) in 26 ms

dig trace 的输出,主要包括四部分。

第一部分,是从 114.114.114.114 查到的一些根域名服务器(.)的 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 记录

这个输出里展现的各级域名的 NS 记录,其实就是各级域名服务器的地址,可让你更清楚 DNS 解析的过程。 为了帮你更直观理解递归查询,我把这个过程整理成了一张流程
图,你能够保存下来理解。

固然,不只仅是发布到互联网的服务须要域名,不少时候,咱们也但愿能对局域网内部的主机进行域名解析(即内网域名,大多数状况下为主机名)。Linux 也支持这种行为。

因此,你能够把主机名和 IP 地址的映射关系,写入本机的 /etc/hosts 文件中。这样,指定的主机名就能够在本地直接找到目标 IP。好比,你能够执行下面的命令来操做:

cat /etc/hosts
127.0.0.1   localhost localhost.localdomain
::1         localhost6 localhost6.localdomain6
192.168.0.100 domain.com

或者,你还能够在内网中,搭建自定义的 DNS 服务器,专门用来解析内网中的域名。而内网 DNS 服务器,通常还会设置一个或多个上游 DNS 服务器,用来解析外网的域名。

清楚域名与 DNS 解析的基本原理后,接下来,我就带你一块儿来看几个案例,实战分析DNS 解析出现问题时,该如何定位。

3、DNS 解析失败-案例分析

一、环境准备

本次案例仍是基于 Ubuntu 18.04,一样适用于其余的 Linux 系统。我使用的案例环境以下所示:

机器配置:2 CPU,8GB 内存。
预先安装 docker 等工具,如 apt install docker.io。

你能够先打开一个终端,SSH 登陆到 Ubuntu 机器中,而后执行下面的命令,拉取案例中使用的 Docker 镜像:

docker pull feisky/dnsutils
Using default tag: latest
...
Status: Downloaded newer image for feisky/dnsutils:latest

而后,运行下面的命令,查看主机当前配置的 DNS 服务器:

cat /etc/resolv.conf
nameserver 114.114.114.114

实际测试命令以下:

[root@69 ~]# cat /etc/resolv.conf
; generated by /sbin/dhclient-script
nameserver 218.30.19.40
nameserver 61.134.1.4

能够看到,我这台主机配置的 DNS 服务器是 114.114.114.114。

到这里,准备工做就完成了。接下来,咱们正式进入操做环节。

二、DNS 解析失败

首先,执行下面的命令,进入今天的第一个案例。若是一切正常,你将能够看到下面这个输出:

# 进入案例环境的 SHELL 终端中
$ docker run -it --rm -v $(mktemp):/etc/resolv.conf feisky/dnsutils bash
root@7e9ed6ed4974:/#

注意,这儿 root 后面的 7e9ed6ed4974,是 Docker 生成容器的 ID 前缀,你的环境中极可能是不一样的 ID,因此直接忽略这一项就能够了。

注意:下面的代码段中, /# 开头的命令都表示在容器内部运行的命令。

接着,继续在容器终端中,执行 DNS 查询命令,咱们仍是查询 time.geekbang.org 的 IP地址:

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

你能够发现,这个命令阻塞好久后,仍是失败了,报了 connection timed out 和 noservers could be reached 错误。

看到这里,估计你的第一反应就是网络不通了,究竟是不是这样呢?咱们用 ping 工具检查试试。执行下面的命令,就能够测试本地到 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=56 time=31.116 ms
64 bytes from 114.114.114.114: icmp_seq=1 ttl=60 time=31.245 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=68 time=31.128 ms
--- 114.114.114.114 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 31.116/31.163/31.245/0.058 ms

这个输出中,你能够看到网络是通的。那要怎么知道 nslookup 命令失败的缘由呢?这里其实有不少方法,最简单的一种,就是开启 nslookup 的调试输出,查看查询过程当中的详
细步骤,排查其中是否有异常。

好比,咱们能够继续在容器终端中,执行下面的命令:

/# 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.

从此次的输出能够看到,nslookup 链接环回地址(127.0.0.1 和 ::1)的 53 端口失败。这里就有问题了,为何会去链接环回地址,而不是咱们的先前看到的 114.114.114.114呢?

你可能已经想到了症结所在——有多是由于容器中没有配置 DNS 服务器。那咱们就执行下面的命令确认一下:

/# cat /etc/resolv.conf

果真,这个命令没有任何输出,说明容器里的确没有配置 DNS 服务器。到这一步,很天然的,咱们就知道了解决方法。在 /etc/resolv.conf 文件中,配置上 DNS 服务器就能够了。

你能够执行下面的命令,在配置好 DNS 服务器后,从新执行 nslookup 命令。天然,咱们如今发现,此次能够正常解析了:

/# 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

到这里,第一个案例就轻松解决了。最后,在终端中执行 exit 命令退出容器,Docker 就会自动清理刚才运行的容器。

实际测试命令以下:

root@luoahong:~# docker pull feisky/dnsutils
Using default tag: latest
latest: Pulling from feisky/dnsutils
38e2e6cd5626: Pull complete 
705054bc3f5b: Pull complete 
c7051e069564: Pull complete 
7308e914506c: Pull complete 
9b20820a1a69: Pull complete 
8633a2284391: Pull complete 
89ab6a8002a6: Pull complete 
Digest: sha256:a23534daa60aad8736823219852b6dbd9b51e84ddbaf42e38b54c68954719766
Status: Downloaded newer image for feisky/dnsutils:latest
root@luoahong:~# docker run -it --rm -v $(mktemp):/etc/resolv.conf feisky/dnsutils bash
root@e9ceb1af6733:/# nslookup time.geekbang.org
;; connection timed out; no servers could be reached

root@e9ceb1af6733:/# ping -c3 218.30.19.40
PING 218.30.19.40 (218.30.19.40): 56 data bytes
64 bytes from 218.30.19.40: icmp_seq=0 ttl=56 time=4.203 ms
64 bytes from 218.30.19.40: icmp_seq=1 ttl=56 time=2.846 ms
64 bytes from 218.30.19.40: icmp_seq=2 ttl=56 time=2.683 ms
--- 218.30.19.40 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 2.683/3.244/4.203/0.681 ms
root@e9ceb1af6733:/# cat /etc/resolv.conf
root@e9ceb1af6733:/# echo "nameserver 218.30.19.40" > /etc/resolv.conf
root@e9ceb1af6733:/# nslookup time.geekbang.org
Server:		218.30.19.40
Address:	218.30.19.40#53

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

4、DNS 解析不稳定-案例分析

接下来,咱们再来看第二个案例。执行下面的命令,启动一个新的容器,并进入它的终端中:

docker run -it --rm --cap-add=NET_ADMIN --dns 8.8.8.8 feisky/dnsutils bash
root@0cd3ee0c8ecb:/#

而后,跟上一个案例同样,仍是运行 nslookup 命令,解析 time.geekbang.org 的 IP 地址。不过,此次要加一个 time 命令,输出解析所用时间。若是一切正常,你可能会看到以下输出:

/# 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

能够看到,此次解析很是慢,竟然用了 10 秒。若是你屡次运行上面的 nslookup 命令,可能偶尔还会碰到下面这种错误:

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

real	0m15.011s
user	0m0.006s
sys	0m0.006s

换句话说,跟上一个案例相似,也会出现解析失败的状况。综合来看,如今 DNS 解析的结果不但比较慢,并且还会发生超时失败的状况。

这是为何呢?碰到这种问题该怎么处理呢?

其实,根据前面的讲解,咱们知道,DNS 解析,说白了就是客户端与服务器交互的过程,而且这个过程还使用了 UDP 协议。

那么,对于整个流程来讲,解析结果不稳定,就有不少种可能的状况了。比方说:

DNS 服务器自己有问题,响应慢而且不稳定;
或者是,客户端到 DNS 服务器的网络延迟比较大;
再或者,DNS 请求或者响应包,在某些状况下被链路中的网络设备弄丢了。

根据上面 nslookup 的输出,你能够看到,如今客户端链接的 DNS 是 8.8.8.8,这是Google 提供的 DNS 服务。对 Google 咱们仍是比较放心的,DNS 服务器出问题的几率
应该比较小。基本排除了 DNS 服务器的问题,那是否是第二种可能,本机到 DNS 服务器的延迟比较大呢?

前面讲过,ping 能够用来测试服务器的延迟。好比,你能够运行下面的命令:

/# 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

从 ping 的输出能够看到,这里的延迟已经达到了 140ms,这也就能够解释,为何解析这么慢了。实际上,若是你屡次运行上面的 ping 测试,还会看到偶尔出现的丢包现象。

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=30 time=134.032 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=30 time=431.458 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 2 packets received, 33% packet loss
round-trip min/avg/max/stddev = 134.032/282.745/431.458/148.713 ms

这也进一步解释了,为何 nslookup 偶尔会失败,正是网络链路中的丢包致使的。碰到这种问题该怎么办呢?显然,既然延迟太大,那就换一个延迟更小的 DNS 服务器,
好比电信提供的 114.114.114.114。

配置以前,咱们能够先用 ping 测试看看,它的延迟是否是真的比 8.8.8.8 好。执行下面的命令,你就能够看到,它的延迟只有 31ms:

/# 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 就能够完成解析,比刚才的 10s 要好不少。

到这里,问题看似就解决了。不过,若是你屡次运行 nslookup 命令,估计就不是每次都有好结果了。好比,在个人机器中,就常常须要 1s 甚至更多的时间。

/# 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	0m1.045s
user	0m0.007s
sys	0m0.004s

1s 的 DNS 解析时间仍是太长了,对不少应用来讲也是不可接受的。那么,该怎么解决这个问题呢?我想你必定已经想到了,那就是使用 DNS 缓存。这样,只有第一次查询时需
要去 DNS 服务器请求,之后的查询,只要 DNS 记录不过时,使用缓存中的记录就能够了。

不过要注意,咱们使用的主流 Linux 发行版,除了最新版本的 Ubuntu (如 18.04 或者更新版本)外,其余版本并无自动配置 DNS 缓存。

因此,想要为系统开启 DNS 缓存,就须要你作额外的配置。好比,最简单的方法,就是使用 dnsmasq。

dnsmasq 是最经常使用的 DNS 缓存服务之一,还常常做为 DHCP 服务来使用。它的安装和配置都比较简单,性能也能够知足绝大多数应用程序对 DNS 缓存的需求。

咱们继续在刚才的容器终端中,执行下面的命令,就能够启动 dnsmasq:

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

而后,修改 /etc/resolv.conf,将 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

如今咱们能够看到,只有第一次的解析很慢,须要 0.5s,之后的每次解析都很快,只须要11ms。而且,后面每次 DNS 解析须要的时间也都很稳定。

案例的最后,仍是别忘了执行 exit,退出容器终端,Docker 会自动清理案例容器。

实际测试命令以下:

root@luoahong:~# docker run -it --rm --cap-add=NET_ADMIN --dns 8.8.8.8 feisky/dnsutils bash
root@8131109d361c:/# 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	0m0.217s
user	0m0.008s
sys	0m0.008s
root@8131109d361c:/# 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	0m0.199s
user	0m0.000s
sys	0m0.015s
root@8131109d361c:/# 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	0m0.156s
user	0m0.010s
sys	0m0.014s
root@8131109d361c:/# 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=49 time=52.674 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=49 time=52.476 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=49 time=57.927 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 52.476/54.359/57.927/2.524 ms
root@8131109d361c:/# 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=49 time=52.268 ms
64 bytes from 8.8.8.8: icmp_seq=1 ttl=49 time=52.333 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=49 time=65.540 ms
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 52.268/56.714/65.540/6.241 ms
root@8131109d361c:/# 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=64 time=25.421 ms
64 bytes from 114.114.114.114: icmp_seq=1 ttl=84 time=25.312 ms
64 bytes from 114.114.114.114: icmp_seq=2 ttl=67 time=23.852 ms
--- 114.114.114.114 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 23.852/24.862/25.421/0.715 ms
root@8131109d361c:/# echo nameserver 114.114.114.114 > /etc/resolv.conf
root@8131109d361c:/# 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.076s
user	0m0.003s
sys	0m0.016s
root@8131109d361c:/# 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.063s
user	0m0.008s
sys	0m0.008s


root@8131109d361c:/# /etc/init.d/dnsmasq start
 * Starting DNS forwarder and DHCP server dnsmasq      [ OK ] 
root@8131109d361c:/# echo nameserver 127.0.0.1 > /etc/resolv.conf
root@8131109d361c:/# 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.266s
user	0m0.004s
sys	0m0.017s
root@8131109d361c:/# 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.017s
user	0m0.004s
sys	0m0.009s
root@8131109d361c:/# 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.019s
user	0m0.008s
sys	0m0.008s

5、小结

今天,我带你一块儿学习了 DNS 的基本原理,并经过几个案例,带你一块儿掌握了,发现DNS 解析问题时的分析和解决思路。

DNS 是互联网中最基础的一项服务,提供了域名和 IP 地址间映射关系的查询服务。不少应用程序在最初开发时,并没考虑 DNS 解析的问题,后续出现问题后,排查好几天才能
发现,实际上是 DNS 解析慢致使的。

试想,假如一个 Web 服务的接kou ,每次都须要 1s 时间来等待 DNS 解析,那么,不管你怎么优化应用程序的内在逻辑,对用户来讲,这个接口的响应都太慢,由于响应时间老是
会大于 1 秒的。

因此,在应用程序的开发过程当中,咱们必须考虑到 DNS 解析可能带来的性能问题,掌握常见的优化方法。这里,我总结了几种常见的 DNS 优化方法。

  1. 对 DNS 解析的结果进行缓存。缓存是最有效的方法,但要注意,一旦缓存过时,仍是要去 DNS 服务器从新获取新记录。不过,这对大部分应用程序来讲都是可接受的。
  2. 对 DNS 解析的结果进行预取。这是浏览器等 Web 应用中最经常使用的方法,也就是说,不等用户点击页面上的超连接,浏览器就会在后台自动解析域名,并把结果缓存起来。
  3. 使用 HTTPDNS 取代常规的 DNS 解析。这是不少移动应用会选择的方法,特别是现在域名劫持广泛存在,使用 HTTP 协议绕过链路中的 DNS 服务器,就能够避免域名劫持的问题。
  4. 基于 DNS 的全局负载均衡(GSLB)。这不只为服务提供了负载均衡和高可用的功能,还能够根据用户的位置,返回距离最近的 IP 地址
相关文章
相关标签/搜索