上一節,咱們學習了 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 這兩個大殺器。你能夠用它們抓取實際傳輸的網絡包,再排查是否有潛在的性能問題。