上一节,咱们学习了 DNS 性能问题的分析和优化方法。简单回顾一下,DNS 能够提供域名和 IP 地址的映射关系,也是一种经常使用的全局负载均衡(GSLB)实现方法。程序员
一般,须要暴露到公网的服务,都会绑定一个域名,既方便了人们记忆,也避免了后台服务 IP 地址的变动影响到用户。web
不过要注意,DNS 解析受到各类网络情况的影响,性能可能不稳定。好比公网延迟增大,缓存过时致使要从新去上游服务器请求,或者流量高峰时 DNS 服务器性能不足等,都会
致使 DNS 响应的延迟增大。缓存
此时,能够借助 nslookup 或者 dig 的调试功能,分析 DNS 的解析过程,再配合 ping等工具调试 DNS 服务器的延迟,从而定位出性能瓶颈。一般,你能够用缓存、预取、
HTTPDNS 等方法,优化 DNS 的性能。bash
上一节咱们用到的 ping,是一个最经常使用的测试服务延迟的工具。不少状况下,ping 能够帮咱们定位出延迟问题,不过有时候, ping 自己也会出现意想不到的问题。这时,就需
要咱们抓取 ping 命令执行时收发的网络包,而后分析这些网络包,进而找出问题根源。tcpdump 和 Wireshark 就是最经常使用的网络抓包和分析工具,更是分析网络性能必不可少的利器。服务器
tcpdump 仅支持命令行格式使用,经常使用在服务器中抓取和分析网络包。 Wireshark 除了能够抓包外,还提供了强大的图形界面和汇总分析工具,在分析复杂的网络情景时,尤其简单和实用。
于是,在实际分析网络性能时,先用 tcpdump 抓包,后用 Wireshark 分析,也是一种经常使用的方法。网络
今天,我就带你一块儿看看,怎么使用 tcpdump 和 Wireshark ,来分析网络的性能问题。负载均衡
本次案例仍是基于 Ubuntu 18.04,一样适用于其余的 Linux 系统。我使用的案例环境是这样的:curl
tcpdump 仅支持命令行格式使用,经常使用在服务器中抓取和分析网络包。
Wireshark 除了能够抓包外,还提供了强大的图形界面和汇总分析工具,在分析复杂的网络情景时,尤其简单和实用。tcp
机器配置:2 CPU,8GB 内存。
预先安装 tcpdump、Wireshark 等工具,如:工具
# Ubuntu apt-get install tcpdump wireshark # CentOS yum install -y tcpdump wireshark
因为 Wireshark 的图形界面,并不能经过 SSH 使用,因此我推荐你在本地机器(好比Windows)中安装。你能够到 https://www.wireshark.org/ 下载并安装 Wireshark。
跟之前同样,案例中全部命令,都默认以 root 用户(在 Windows 中,运行 Wireshark 时除外)运行。若是你是用普通用户身份登录系统,请运行 sudo su root 命令切换到 root 用户。
前面讲过,ping 是一种最经常使用的网络工具,经常使用来探测网络主机之间的连通性以及延迟。关于 ping 的原理和使用方法,我在前面的 Linux 网络基础篇 已经简单介绍过,而 DNS
缓慢的案例中,也屡次用到了 ping 测试 DNS 服务器的延迟(RTT)。
不过,虽然 ping 比较简单,但有时候你会发现,ping 工具自己也可能出现异常,好比运行缓慢,但实际网络延迟却并不大的状况。
接下来,咱们打开一个终端,SSH 登陆到案例机器中,执行下面的命令,来测试案例机器与极客邦科技官网的连通性和延迟。若是一切正常,你会看到下面这个输出:
# ping 3 次(默认每次发送间隔 1 秒) # 假设 DNS 服务器仍是上一期配置的 114.114.114.114 $ ping -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=1 ttl=43 time=36.8 ms 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=2 ttl=43 time=31.1 ms 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=3 ttl=43 time=31.2 ms --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 11049ms rtt min/avg/max/mdev = 31.146/33.074/36.809/2.649 ms
ping 的输出界面, Linux 网络基础篇 中咱们已经学过,你能够先复习一下,本身解读而且分析此次的输出。
不过要注意,假如你运行时发现 ping 很快就结束了,那就执行下面的命令,再重试一下。至于这条命令的含义,稍后咱们再作解释。
# 禁止接收从 DNS 服务器发送过来并包含 googleusercontent 的包 $ iptables -I INPUT -p udp --sport 53 -m string --string googleusercontent --algo bm -j DROP
根据 ping 的输出,你能够发现,geektime.org 解析后的 IP 地址是 35.190.27.188,然后三次 ping 请求都获得了响应,延迟(RTT)都是 30ms 多一点。
但汇总的地方,就有点儿意思了。3 次发送,收到 3 次响应,没有丢包,但三次发送和接受的总时间竟然超过了 11s(11049ms),这就有些难以想象了吧。
会想起上一节的 DNS 解析问题,你可能会怀疑,这多是 DNS 解析缓慢的问题。但究竟是不是呢?
再回去看 ping 的输出,三次 ping 请求中,用的都是 IP 地址,说明 ping 只须要在最开始运行时,解析一次获得 IP,后面就能够只用 IP 了。
咱们再用 nslookup 试试。在终端中执行下面的 nslookup 命令,注意,此次咱们一样加了 time 命令,输出 nslookup 的执行时间:
time nslookup geektime.org Server: 114.114.114.114 Address: 114.114.114.114#53 Non-authoritative answer: Name: geektime.org Address: 35.190.27.188 real 0m0.044s user 0m0.006s sys 0m0.003s
能够看到,域名解析仍是很快的,只须要 44ms,显然比 11s 短了不少。
到这里,再日后该怎么分析呢?其实,这时候就能够用 tcpdump 抓包,查看 ping 在收发哪些网络包。
咱们再打开另外一个终端(终端二),SSH 登陆案例机器后,执行下面的命令:
tcpdump -nn udp port 53 or host 35.190.27.188
固然,你能够直接用 tcpdump 不加任何参数来抓包,但那样的话,就可能抓取到不少不相干的包。因为咱们已经执行过 ping 命令,知道了 geekbang.org 的 IP 地址是
35.190.27.188,也知道 ping 命令会执行 DNS 查询。因此,上面这条命令,就是基于这个规则进行过滤。
我来具体解释一下这条命令。
-nn ,表示不解析抓包中的域名(即不反向解析)、协议以及端口号。 udp port 53 ,表示只显示 UDP 协议的端口号(包括源端口和目的端口)为 53 的包。 host 35.190.27.188 ,表示只显示 IP 地址(包括源地址和目的地址)为 35.190.27.188的包。 这两个过滤条件中间的“ or ”,表示或的关系,也就是说,只要知足上面两个条件中的任一个,就能够展现出来。
接下来,回到终端一,执行相同的 ping 命令:
ping -c3 geektime.org ... --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 11095ms rtt min/avg/max/mdev = 81.473/81.572/81.757/0.130 ms
命令结束后,再回到终端二中,查看 tcpdump 的输出:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 14:02:31.100564 IP 172.16.3.4.56669 > 114.114.114.114.53: 36909+ A? geektime.org. (30) 14:02:31.507699 IP 114.114.114.114.53 > 172.16.3.4.56669: 36909 1/0/0 A 35.190.27.188 (46) 14:02:31.508164 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 1, length 64 14:02:31.539667 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 1, length 64 14:02:31.539995 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44) 14:02:36.545104 IP 172.16.3.4.60254 > 114.114.114.114.53: 49932+ PTR? 188.27.190.35.in-addr.arpa. (44) 14:02:41.551284 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 2, length 64 14:02:41.582363 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 2, length 64 14:02:42.552506 IP 172.16.3.4 > 35.190.27.188: ICMP echo request, id 4356, seq 3, length 64 14:02:42.583646 IP 35.190.27.188 > 172.16.3.4: ICMP echo reply, id 4356, seq 3, length 64
此次输出中,前两行,表示 tcpdump 的选项以及接口的基本信息;从第三行开始,就是抓取到的网络包的输出。这些输出的格式,都是 时间戳 协议 源地址. 源端口 > 目的
地址. 目的端口 网络包详细信息(这是最基本的格式,能够经过选项增长其余字段)。前面的字段,都比较好理解。但网络包的详细信息,自己根据协议的不一样而不一样。因此,
要理解这些网络包的详细含义,就要对经常使用网络协议的基本格式以及交互原理,有基本的了解。
固然,实际上,这些内容都会记录在 IETF( 互联网工程任务组)发布的 RFC(请求意见稿)中。
好比,第一条就表示,从本地 IP 发送到 114.114.114.114 的 A 记录查询请求,它的报文格式记录在 RFC1035 中,你能够点击这里查看。在这个 tcpdump 的输出中,
36909+ 表示查询标识值,它也会出如今响应中,加号表示启用递归查询。 A? 表示查询 A 记录。 geektime.org. 表示待查询的域名。 30 表示报文长度。
接下来的一条,则是从 114.114.114.114 发送回来的 DNS 响应——域名 geektime.org.的 A 记录值为 35.190.27.188。
第三条和第四条,是 ICMP echo request 和 ICMP echo reply,响应包的时间戳14:02:31.539667,减去请求包的时间戳 14:02:31.508164 ,就能够获得,此次 ICMP 所
用时间为 30ms。这看起来并无问题。
但随后的两条反向地址解析 PTR 请求,就比较可疑了。由于咱们只看到了请求包,却没有应答包。仔细观察它们的时间,你会发现,这两条记录都是发出后 5s 才出现下一个网络
包,两条 PTR 记录就消耗了 10s。
再往下看,最后的四个包,则是两次正常的 ICMP 请求和响应,根据时间戳计算其延迟,也是 30ms。
到这里,其实咱们也就找到了 ping 缓慢的根源,正是两次 PTR 请求没有获得响应而超时致使的。PTR 反向地址解析的目的,是从 IP 地址反查出域名,但事实上,并不是全部 IP 地
址都会定义 PTR 记录,因此 PTR 查询极可能会失败。
因此,在你使用 ping 时,若是发现结果中的延迟并不大,而 ping 命令自己却很慢,不要慌,有多是背后的 PTR 在搞鬼。
知道问题后,解决起来就比较简单了,只要禁止 PTR 就能够。仍是老路子,执行 manping 命令,查询使用手册,就能够找出相应的方法,即加上 -n 选项禁止名称解析。比
如,咱们能够在终端中执行以下命令:
ping -n -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 35.190.27.188: icmp_seq=1 ttl=43 time=33.5 ms 64 bytes from 35.190.27.188: icmp_seq=2 ttl=43 time=39.0 ms 64 bytes from 35.190.27.188: icmp_seq=3 ttl=43 time=32.8 ms --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2002ms rtt min/avg/max/mdev = 32.879/35.160/39.030/2.755 ms
你能够发现,如今只须要 2s 就能够结束,比刚才的 11s 但是快多了。到这里, 我就带你一块儿使用 tcpdump ,解决了一个最多见的 ping 工做缓慢的问题。
案例最后,若是你在开始时,执行了 iptables 命令,那也不要忘了删掉它:
iptables -D INPUT -p udp --sport 53 -m string --string googleusercontent --algo bm -j DROP
不过,删除后你确定还有疑问,明明咱们的案例跟 Google 没啥关系,为何要根据googleusercontent ,这个绝不相关的字符串来过滤包呢?
实际上,若是换一个 DNS 服务器,就能够用 PTR 反查到 35.190.27.188 所对应的域名:
$ nslookup -type=PTR 35.190.27.188 8.8.8.8 Server: 8.8.8.8 Address: 8.8.8.8#53 Non-authoritative answer: 188.27.190.35.in-addr.arpa name = 188.27.190.35.bc.googleusercontent.com. Authoritative answers can be found from:
你看,虽然查到了 PTR 记录,但结果并不是 geekbang.org,而是188.27.190.35.bc.googleusercontent.com。其实,这也是为何,案例开始时将包含
googleusercontent 的丢弃后,ping 就慢了。由于 iptables ,其实是把 PTR 响应给丢了,因此会致使 PTR 请求超时。
tcpdump 能够说是网络性能分析最有效的利器。接下来,我再带你一块儿看看 tcpdump 的更多使用方法。
[root@luoahong ~]# ping -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 188.27.190.35.bc.googleusercontent.com (35.190.27.188): icmp_seq=1 ttl=50 time=60.7 ms 64 bytes from 188.27.190.35.bc.googleusercontent.com (35.190.27.188): icmp_seq=2 ttl=50 time=61.7 ms 64 bytes from 188.27.190.35.bc.googleusercontent.com (35.190.27.188): icmp_seq=3 ttl=50 time=60.5 ms --- geektime.org ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2003ms rtt min/avg/max/mdev = 60.559/61.012/61.739/0.592 ms [root@luoahong ~]# iptables -I INPUT -p udp --sport 53 -m string --string googleusercontent --algo bm -j DROP [root@luoahong ~]# ping -c3 geektime.org PING geektime.org (35.190.27.188) 56(84) bytes of data. 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=2 ttl=50 time=61.6 ms 64 bytes from 35.190.27.188 (35.190.27.188): icmp_seq=3 ttl=50 time=60.7 ms --- geektime.org ping statistics --- 3 packets transmitted, 2 received, 33% packet loss, time 13749ms rtt min/avg/max/mdev = 60.711/61.204/61.697/0.493 ms [root@luoahong ~]# time nslookup geektime.org Server: 218.30.19.40 Address: 218.30.19.40#53 Non-authoritative answer: Name: geektime.org Address: 35.190.27.188 real 0m0.014s user 0m0.005s sys 0m0.006s
实际测试并无和老师的环境同样
咱们知道,tcpdump 也是最经常使用的一个网络分析工具。它基于 libpcap ,利用内核中的AF_PACKET 套接字,抓取网络接口中传输的网络包;并提供了强大的过滤规则,帮你从
大量的网络包中,挑出最想关注的信息。
tcpdump 为你展现了每一个网络包的详细细节,这就要求,在使用前,你必需要对网络协议有基本了解。而要了解网络协议的详细设计和实现细节, RFC 固然是最权威的资料。
不过,RFC 的内容,对初学者来讲可能并不友好。若是你对网络协议还不太了解,推荐你去学《TCP/IP 详解》,特别是第一卷的 TCP/IP 协议族。这是每一个程序员都要掌握的核心
基础知识。
再回到 tcpdump 工具自己,它的基本使用方法,仍是比较简单的,也就是 tcpdump [选项] [过滤表达式]。固然,选项和表达式的外面都加了中括号,代表它们都是可选的。
提示:在 Linux 工具中,若是你在文档中看到,选项放在中括号里,就说明 这是一个可选选项。这时候就要留意一下,这些选项是否是有默认值。
查看 tcpdump 的 手册 ,以及 pcap-filter 的 手册,你会发现,tcpdump 提供了大量的选项以及各式各样的过滤表达式。不过不要担忧,只须要掌握一些经常使用选项和过滤表达
式,就能够知足大部分场景的须要了。
为了帮你更快上手 tcpdump 的使用,我在这里也帮你整理了一些最多见的用法,而且绘制成了表格,你能够参考使用。
首先,来看一下经常使用的几个选项。在上面的 ping 案例中,咱们用过 -nn 选项,表示不用对 IP 地址和端口号进行名称解析。其余经常使用选项,我用下面这张表格来解释。
接下来,咱们再来看经常使用的过滤表达式。刚刚用过的是 udp port 53 or host35.190.27.188 ,表示抓取 DNS 协议的请求和响应包,以及源地址或目的地址为
35.190.27.188 的包。
其余经常使用的过滤选项,我也整理成了下面这个表格。
最后,再次强调 tcpdump 的输出格式,我在前面已经介绍了它的基本格式:
时间戳 协议 源地址. 源端口 > 目的地址. 目的端口 网络包详细信息
其中,网络包的详细信息取决于协议,不一样协议展现的格式也不一样。因此,更详细的使用方法,仍是须要你去查询 tcpdump 的 man 手册(执行 man tcpdump 也能够获得)。
不过,讲了这么多,你应该也发现了。tcpdump 虽然功能强大,但是输出格式却并不直观。特别是,当系统中网络包数比较多(好比 PPS 超过几千)的时候,你想从 tcpdump
抓取的网络包中分析问题,实在不容易。
对比之下,Wireshark 则经过图形界面,以及一系列的汇总分析工具,提供了更友好的使用界面,让你能够用更快的速度,摆平网络性能问题。接下来,咱们就详细来看看它。
Wireshark 也是最流行的一个网络分析工具,它最大的好处就是提供了跨平台的图形界面。跟 tcpdump 相似,Wireshark 也提供了强大的过滤规则表达式,同时,还内置了一
系列的汇总分析工具。
好比,拿刚刚的 ping 案例来讲,你能够执行下面的命令,把抓取的网络包保存到ping.pcap 文件中:
tcpdump -nn udp port 53 or host 35.190.27.188 -w ping.pcap
接着,把它拷贝到你安装有 Wireshark 的机器中,好比你能够用 scp 把它拷贝到本地来:
scp host-ip/path/ping.pcap .
而后,再用 Wireshark 打开它。打开后,你就能够看到下面这个界面:
实际测试截图:
从 Wireshark 的界面里,你能够发现,它不只以更规整的格式,展现了各个网络包的头部信息;还用了不一样颜色,展现 DNS 和 ICMP 这两种不一样的协议。你也能够一眼看出,中
间的两条 PTR 查询并无响应包。
接着,在网络包列表中选择某一个网络包后,在其下方的网络包详情中,你还能够看到,这个包在协议栈各层的详细信息。好比,以编号为 5 的 PTR 包为例:
实际测试截图:
你能够看到,IP 层(Internet Protocol)的源地址和目的地址、传输层的 UDP 协议(Uder Datagram Protocol)、应用层的 DNS 协议(Domain Name System)的概要信息。
继续点击每层左边的箭头,就能够看到该层协议头的全部信息。好比点击 DNS 后,就能够看到 Transaction ID、Flags、Queries 等 DNS 协议各个字段的数值以及含义。
固然,Wireshark 的功能远不止如此。接下来我再带你一块儿,看一个 HTTP 的例子,并理解 TCP 三次握手和四次挥手的工做原理。
这个案例咱们将要访问的是 http://example.com/ 。进入终端一,执行下面的命令,首先查出 example.com 的 IP。而后,执行 tcpdump 命令,过滤获得的 IP 地址,并将结果
保存到 web.pcap 中。
dig +short example.com 93.184.216.34 $ tcpdump -nn host 93.184.216.34 -w web.pcap
接下来,切换到终端二,执行下面的 curl 命令,访问 http://example.com:
curl http://example.com
实际上,你能够在 host 表达式中,直接使用域名,即 tcpdump -nn hostexample.com -w web.pcap
最后,再回到终端一,按下 Ctrl+C 中止 tcpdump,并把获得的 web.pcap 拷贝出来。使用 Wireshark 打开 web.pcap 后,你就能够在 Wireshark 中,看到以下的界面:
实际测试截图:
因为 HTTP 基于 TCP ,因此你最早看到的三个包,分别是 TCP 三次握手的包。接下来,中间的才是 HTTP 请求和响应包,而最后的三个包,则是 TCP 链接断开时的三次挥手包。
从菜单栏中,点击 Statistics -> Flow Graph,而后,在弹出的界面中的 Flow type 选择TCP Flows,你能够更清晰的看到,整个过程当中 TCP 流的执行过程:
实际测试截图:
这其实跟各类教程上讲到的,TCP 三次握手和四次挥手很相似,做为对比, 你一般看到的TCP 三次握手和四次挥手的流程,基本是这样的:
不过,对比这两张图,你会发现,这里抓到的包跟上面的四次挥手,并不彻底同样,实际挥手过程只有三个包,而不是四个。
其实,之因此有三个包,是由于服务器端收到客户端的 FIN 后,服务器端同时也要关闭链接,这样就能够把 ACK 和 FIN 合并到一块儿发送,节省了一个包,变成了“三次挥手”。
而一般状况下,服务器端收到客户端的 FIN 后,极可能还没发送完数据,因此就会先回复客户端一个 ACK 包。稍等一下子,完成全部数据包的发送后,才会发送 FIN 包。这也就
是四次挥手了。
抓包后, Wireshark 中就会显示下面这个界面(原始网络包来自 Wireshark TCP 4-timesclose 示例,你能够点击 这里 下载):
固然,Wireshark 的使用方法毫不只有这些,更多的使用方法,一样能够参考 官方文档 以及 WIKI。
今天,咱们一块儿学了 tcpdump 和 Wireshark 的使用方法,并经过几个案例,学会了如何运用这两个工具来分析网络的收发过程,并找出潜在的性能问题。
当你发现针对相同的网络服务,使用 IP 地址快而换成域名却慢不少时,就要想到,有多是 DNS 在捣鬼。DNS 的解析,不只包括从域名解析出 IP 地址的 A 记录请求,还包括性
能工具帮你,“聪明”地从 IP 地址反查域名的 PTR 请求。
实际上,根据 IP 地址反查域名、根据端口号反查协议名称,是不少网络工具默认的行为,而这每每会致使性能工具的工做缓慢。因此,一般,网络性能工具都会提供一个选项(比
如 -n 或者 -nn),来禁止名称解析。
在工做中,当你碰到网络性能问题时,不要忘记 tcpdump 和 Wireshark 这两个大杀器。你能够用它们抓取实际传输的网络包,再排查是否有潜在的性能问题。