指南:從網(wǎng)絡(luò)排查到故障定位的必備技能)
兄弟們干運維和網(wǎng)絡(luò)這行的甭管你平時吹得多天花亂墜最后都得落到排查問題這根鋼絲繩上。你跟我說你網(wǎng)絡(luò)架構(gòu)玩得花我信但你說你鏈路抖動、應(yīng)用卡頓、用戶那邊嗷嗷叫的時候你連個包都沒抓明白那我只能說兄弟你還得練。排查網(wǎng)絡(luò)問題咱們不靠猜全靠看證據(jù)。而抓包這個動作tcpdump就是那個最趁手、最不起眼、但最關(guān)鍵的工具。今天這篇不整虛的就聊聊tcpdump最普通的玩法。不是那種把man手冊給你抄一遍的教程而是從一個老運維的實際工作角度把它當成一把螺絲刀告訴你什么時候擰哪顆螺絲怎么擰不滑絲擰完之后怎么判斷螺絲到底緊沒緊。看完這篇你至少能對付掉工作里八成以上的網(wǎng)絡(luò)排查場景不用再遇到問題就先重啟或者對著屏幕發(fā)呆。1. 為什么偏偏是它tcpdump的核心思路拆解先把心態(tài)擺正。tcpdump不是萬能的它就是一個命令行下的抓包分析器原理簡單得嚇人——把網(wǎng)卡上跑過的數(shù)據(jù)包按你的規(guī)則截獲一份副本然后要么打印到屏幕上要么存成文件給你慢慢分析。它的優(yōu)勢從來不是分析得有多深而是貼近底層、輕巧、靈活在服務(wù)器上一條命令就能跑起來不依賴任何花哨的圖形界面。很多人一上來就被各種各樣的參數(shù)嚇住了其實你只需要抓住三個核心點抓什么、抓多久、抓完怎么辦。抓什么這就是BPF過濾規(guī)則也就是伯克利包過濾語法。它是tcpdump的靈魂決定了你是把所有流量都撈上來還是只撈你關(guān)心的那部分。抓多久抓包不是錄監(jiān)控視頻不能無限錄。你需要明確時間窗口和包數(shù)量上限否則生成的文件能把你的磁盤撐爆。抓完怎么辦是直接在屏幕上實時滾動看還是落盤保存成.pcap文件然后用Wireshark等工具去細看。這是兩種完全不同的工作模式一個適合臨時瞄一眼一個適合深挖慢查。這三個問題想清楚了你已經(jīng)比百分之八十的初級使用者強。剩下的就是語法熟練度的問題。記住我們是在有目的地取證而不是在海里撈針。2. 上場之前先拿最基本的幾個命令熱熱身上手別整那些花活先保證你能看到東西。2.1 抓包前的三件事先想明白第一你當前要監(jiān)控哪塊網(wǎng)卡。用ip addr或者老的ifconfig看一眼找到你關(guān)心流量的那塊物理網(wǎng)卡名稱常見的比如eth0、ens192、em1。你要是連網(wǎng)卡都搞錯了抓半天抓了個寂寞流量根本不過這塊卡純屬浪費時間。第二你有沒有權(quán)限。tcpdump需要root權(quán)限才能抓包所以別老想著用普通用戶去執(zhí)行然后報錯說找不到設(shè)備先sudo -i或者檢查一下你的用戶是否在sudo組里。在有的生產(chǎn)環(huán)境里甚至得看看你的系統(tǒng)是不是SELinux或者AppArmor攔著你到時候報Operation not permitted都不知道是哪兒出了問題。第三確定你要不要開混雜模式。網(wǎng)卡默認只把發(fā)給自己MAC地址的包交給內(nèi)核處理但抓包工具通常會讓網(wǎng)卡進入混雜模式把經(jīng)過這塊網(wǎng)卡的所有包都接收一份。所以我們經(jīng)??吹絫cpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes這行提示其中promiscuous mode開沒開就說明這件事。默認情況下像在交換機鏡像口這種場景我們必須依賴混雜模式才能抓到別人的流量這個開關(guān)非常關(guān)鍵。2.2 從一個最樸素的抓包命令說起比如說我現(xiàn)在懷疑我這臺服務(wù)器訪問某個數(shù)據(jù)庫有問題最簡單的我就想先看看連接能不能建立TCP握手能不能完成。直接在機器上敲tcpdump -i eth0 tcp port 3306這條命令的意思是在eth0這塊網(wǎng)卡上抓取TCP協(xié)議且目標或源端口是3306的包。屏幕上開始一行行刷數(shù)據(jù)你會看到類似下面這樣的東西05:03:02.123456 IP 10.0.1.10.54321 10.0.1.20.3306: Flags [S], seq 123456789, win 64240, options [mss 1460,sackOK,TS val 123 ecr 0,nop,wscale 7], length 0 05:03:02.124002 IP 10.0.1.20.3306 10.0.1.10.54321: Flags [S.], seq 987654321, ack 123456790, win 65160, options [mss 1460,sackOK,TS val 456 ecr 123,nop,wscale 7], length 0 05:03:02.125001 IP 10.0.1.10.54321 10.0.1.20.3306: Flags [.], ack 987654322, win 512, length 0看到這個你就知道TCP三次握手是正常完成的。S是SYN包S.是SYN-ACK包.就是純ACK包。如果后面還有一串P開頭的包那就是攜帶了應(yīng)用層數(shù)據(jù)的PUSH包。這里有個小技巧Flags字母如果出現(xiàn)[F.]那就是正常四次揮手[R.]就是連接被重置了這往往是排查問題的重要信號。如果我就想把這個過程實時看完那直接-n參數(shù)把域名和端口翻譯關(guān)掉讓輸出更快更干凈tcpdump -n -i eth0 tcp port 3306加了-n之后屏幕上就不會去做IP到域名的反解析也不會把3306顯示成mysql輸出速度更快也更純粹。特別是當你抓的是公網(wǎng)流量反查DNS這個過程非常拖慢速度甚至?xí)驗镈NS解析超時導(dǎo)致輸出卡頓所以-n是我在任何抓包場景里幾乎必帶的一個參數(shù)。2.3 不只會抓還要會看基本輸出很多新手看到tcpdump輸出的原始行就像看天書一樣其實拆開看很簡單。我也順手給你解讀一下標準輸出格式的幾段信息時間戳是第一個字段精確到微秒級是判斷延遲的重要依據(jù)。然后是協(xié)議層頭信息比如IP表示這個包是裸的IP包如果是ARP那就會顯式寫出來。再往后是源地址源端口 目的地址目的端口這個指向關(guān)系可以讓你快速判斷數(shù)據(jù)流向。然后是很關(guān)鍵的Flags也就是TCP控制位。S建連、F斷開、R重置、P推送數(shù)據(jù)、E顯式擁塞混合標志位用點號分隔。seq和ack則是TCP序號和確認號專門用來分析重傳和亂序。最后面的win是接收窗口大小可用來辨別接收方緩存壓力。把這些字段拼在一起你就能在屏幕世界里看見兩臺機器之間到底發(fā)生了什么。熟練之后很多網(wǎng)絡(luò)故障從表面現(xiàn)象到根因方向在你腦子里一瞬間就能拉出一條線來。3. 進階玩法像篩金子一樣用過濾表達式基礎(chǔ)命令會了接下來得學(xué)會“挑食”。電腦網(wǎng)絡(luò)上的數(shù)據(jù)包就像嘈雜集市里的人群你得學(xué)會只盯著你想找的那個目標而不是把所有人都喊到你面前來一個一個看。3.1 過濾主機只關(guān)心源或目的IP排查問題時最常用的就是限定主機。比如我懷疑后端服務(wù)器10.0.2.5返回數(shù)據(jù)有問題那我只抓跟它相關(guān)的流量tcpdump -nn -i eth0 host 10.0.2.5這里用了兩個n既不做域名反解也不翻譯端口號純純的數(shù)字化輸出速度最極致。如果你還想精確到是我本機發(fā)給它還是它發(fā)給我那就再加方向限定詞tcpdump -nn -i eth0 src host 10.0.2.5 tcpdump -nn -i eth0 dst host 10.0.2.5src和dst這兩個詞非常直觀組合使用能精準鎖定單向流量。還有更靈活的src or dst組合比如我要看所有從10.0.2.5來或者去往10.0.2.6的流量tcpdump -nn -i eth0 src host 10.0.2.5 or dst host 10.0.2.6單引號包起來很重要因為or、and這些關(guān)鍵字會被shell解釋成管道或者邏輯符號別看小看這層單引號少了它很多命令執(zhí)行結(jié)果會直接崩掉或者行為大變。3.2 過濾端口直擊服務(wù)的咽喉端口過濾是跟具體應(yīng)用排查綁定的。比如排查web服務(wù)直接抓80或443端口tcpdump -nn -i eth0 tcp port 443但我個人更推薦你直接寫全五元組邏輯源端口目的端口分開寫因為有時候你想?yún)^(qū)分是外部請求進來還是內(nèi)部向外請求。比如我只想看本機eth0上對外發(fā)起的連接那目的端口一定是遠程的443tcpdump -nn -i eth0 dst port 443反過來像收集內(nèi)部服務(wù)日志或觀測出網(wǎng)流量那就看源端口tcpdump -nn -i eth0 src port 53這里的邏輯還可以用portrange來抓端口段。比如某個游戲服務(wù)器開了一大片UDP端口從20000到30000寫起來就是tcpdump -nn -i eth0 udp portrange 20000-30000這種連續(xù)端口的匹配在排查P2P或者RPC類服務(wù)的時候特別給力不然一條條端口寫進去手都能給你寫酸。3.3 協(xié)議與多條件組合把網(wǎng)撒得剛剛好最后來點真正有實戰(zhàn)感的組合。比如你要定位是不是有人在你內(nèi)網(wǎng)里搞ARP欺騙那就直接只抓ARP協(xié)議tcpdump -nn -i eth0 arp比如你要排查DNS解析慢的問題又不想抓太多無關(guān)流量可以限定UDP端口53tcpdump -nn -i eth0 udp port 53遇到那種既有TCP又有UDP的服務(wù)比如某些基于QUIC/HTTP3的應(yīng)用想一把梭全抓下來tcpdump -nn -i eth0 (tcp or udp) and port 8443這行表達式里的括號也同樣需要單引號保護。另外有個更實在的建議你真的特別明確就要某一種類型比如排除掉SSH的22端口干擾那你可以直接tcpdump -nn -i eth0 port not 22 and host 10.0.2.5活了。這一套組合拳打下來你要的流量就像從沙子里淘出來的金子其余無關(guān)數(shù)據(jù)全都安靜地躺在內(nèi)核緩沖區(qū)之外。這里多插一句經(jīng)驗過濾器并不是越復(fù)雜越好規(guī)則寫得越寬內(nèi)核拷貝到用戶態(tài)的數(shù)據(jù)越多丟包概率越大。所以先寬后窄先抓到方向、再細摳顆粒度是實戰(zhàn)里效率最高的節(jié)奏。4. 落盤為王生產(chǎn)環(huán)境必會的抓包姿勢實時滾動看幾眼適合臨時驗證但遇到那種老大看了半天才說“好像有點不對勁”的疑難雜癥我們就得把包保存下來拿回去慢慢分析。4.1 寫出文件與循環(huán)切割保存成.pcap文件的命令很常規(guī)tcpdump -i eth0 -w /tmp/capture.pcap tcp port 8080這里有個極其重要的點寫文件模式下屏幕上不會打印每一行抓包信息因為你告訴它把原始包寫到文件里它就不做實時翻譯了。很多人第一次用半天沒輸出以為卡死了其實它是默默在后臺干活。如果需要一邊抓一邊確保文件數(shù)量可控可以用-C參數(shù)按大小分割文件單位是MBtcpdump -i eth0 -w /tmp/capture.pcap -C 100 tcp port 8080這行命令表示單個文件超過100MB就自動新建下一個文件后面會跟著生成capture.pcap、capture.pcap1、capture.pcap2這樣的序列文件。也可以按時間切片-G 60表示每60秒切一個文件適合長時間無人值守。這種循環(huán)切文件的方式在生產(chǎn)排查里就是神器既能防止單個文件過大拖垮后期分析也能讓回傳文件時間點更精確。4.2 控制抓包時長和包數(shù)量抓包不能無限期抓下去要給個極限約束。比如我就是想抓3分鐘看看情況timeout 180 tcpdump -i eth0 -w /tmp/capture.pcap -n host 10.0.2.5用timeout命令來限時這是一個很可靠的做法比后臺掛PID然后手動殺要優(yōu)雅得多。另外也可以用-c數(shù)量控制抓到一定包數(shù)自動退出tcpdump -i eth0 -c 2000 -w /tmp/capture.pcap這里-c 2000意思就是抓滿2000個包就自己停了適合你只想快速采樣幾個包驗證協(xié)議特征時用。要知道有時候你并不需要全程錄屏前幾秒的特征足以說明問題。結(jié)合-c加上-w這個組合是典型的快速取證姿勢比如你接到報警說某臺機器瘋狂發(fā)包抓2000個包看看包長跟目標往往幾秒就能鎖到具體進程的特征。4.3 落盤抓包的緩沖區(qū)大小調(diào)節(jié)生產(chǎn)環(huán)境流量稍微大一點你會碰到一個很頭疼的坑抓包丟包。這個時候就需要調(diào)整內(nèi)核抓包緩沖區(qū)大小參數(shù)是-B單位是KB。默認值往往只有幾MB高并發(fā)下瞬間就被打滿新到的包只能丟棄。常見做法是拉高到幾十甚至幾百MBtcpdump -i eth0 -B 4096 -w /tmp/huge_capture.pcap-B 4096意思是緩沖區(qū)設(shè)為4MB注意這個單位默認KB。這能顯著降低高流量場景下的丟包率。雖然tcpdump在退出時會打印一條包含dropped kernel的統(tǒng)計信息但你要是看完包再發(fā)現(xiàn)丟包嚴重再回頭重新抓可就麻煩多了。所以流量很大的場景開局就先把緩沖區(qū)拉高別省著用。還有一個很有用的參數(shù)是-s控制每個包抓取的長度也就是snaplen。默認是262144字節(jié)256KB但絕大多數(shù)常見協(xié)議我們只看頭部和部分載荷就行了。為了減小文件體積可以設(shè)成tcpdump -i eth0 -s 128 -w /tmp/small.pcap這樣每個包就只保留前128字節(jié)足以看到TCP/UDP頭以及部分應(yīng)用層信息。這在無線網(wǎng)卡或者流量大的環(huán)境里非常節(jié)省空間代價是你可能看不到完整的應(yīng)用載荷需要根據(jù)實際需求權(quán)衡。有一點提醒有些協(xié)議比如TLS證書、某些文件傳輸要看全證書或全載荷這時候-s 0才代表完整抓取整個包別到時候抓完發(fā)現(xiàn)里面只有一截數(shù)據(jù)悔到腸子都青了。4.4 直取出可讀的十六進制和ASCII內(nèi)容有時候你不想開Wireshark就是想快速看看包里的實際內(nèi)容。這時候可以用-X或者-A。-A把包以純ASCII形式打印出來適合看HTTP明文請求和響應(yīng)-X則同時輸出十六進制和ASCII適合檢查二進制協(xié)議細節(jié)或加密流量的特征。tcpdump -nn -i eth0 -A -s 0 tcp port 80這條命令會把80端口的所有TCP載荷以可讀字符形式刷出來排查HTTP接口調(diào)試時特別直觀。你會直接看到GET / HTTP/1.1、Host:之類的請求行限流了、亂碼了、參數(shù)丟了一眼就能判斷。5. 真實排障演練一次假性超時的血淚實錄理論講了一大堆不發(fā)點實戰(zhàn)總覺得心里不踏實。跟大家分享一個我親身經(jīng)歷過的排查案例讓我們把前面這些參數(shù)串起來用一遍。某個周五下午業(yè)務(wù)方那邊反饋說調(diào)用一個內(nèi)部接口經(jīng)常超時但又不是每次必現(xiàn)大概兩三次里有一次要等好幾秒。監(jiān)控看CPU、內(nèi)存都沒啥壓力數(shù)據(jù)庫負載也不高。這種間歇性超時最折磨人因為無從下手。我決定在應(yīng)用服務(wù)器網(wǎng)卡上落盤抓包。先確認網(wǎng)卡名是eth0然后用了這么一條命令tcpdump -nn -i eth0 -B 2048 -s 128 -w /tmp/app_timeout.pcap tcp port 8080 and host 10.10.20.15抓了大概十分鐘等到業(yè)務(wù)方又反饋一次超時之后我把包拿了回來。直接用Wireshark打開先看TCP流。結(jié)果發(fā)現(xiàn)一個很有意思的現(xiàn)象客戶端發(fā)出的請求包帶P標志數(shù)據(jù)段已經(jīng)到達服務(wù)器IP但服務(wù)器這邊遲遲沒回ACK然后客戶端就開始瘋狂重傳。重傳了好幾輪服務(wù)器終于是回了一個S.不對是回了一個R也就是連接重置??雌饋砭拖袷菢I(yè)務(wù)層把連接關(guān)了。順著這個方向去查發(fā)現(xiàn)后端Tomcat的線程池配置有問題活躍線程數(shù)上限設(shè)得太低請求一多連接就被pending最終觸發(fā)超時重置??蛻舳丝吹降氖菐资氤瑫r實際上瓶頸根本不在網(wǎng)絡(luò)鏈路而在于服務(wù)端應(yīng)用線程池滿。這個結(jié)論可以說完全是依靠抓包鎖定到端口的如果不是看到TCP層面的重傳和RST時間點我們可能還在傻乎乎查中間交換機丟包和防火墻策略。這里的經(jīng)驗總結(jié)就是抓到包后別急著看亂七八糟的幾百兆數(shù)據(jù)先按照時間順序過濾出幾個關(guān)鍵節(jié)點找TCP重傳TCP Retransmission、找RST、找零窗口Zero Window這三個信號基本能覆蓋大部分“網(wǎng)絡(luò)慢”的根因方向。6. 那些年我們踩過的坑tcpdump使用常見問題速查玩的時間久了總會有些小坑反反復(fù)復(fù)出現(xiàn)。我把它們整理成表格方便你對著查。問題現(xiàn)象大概率原因解決/排查方向屏幕上什么都看不到過濾規(guī)則寫錯、網(wǎng)卡選錯、流量確實沒走這塊網(wǎng)卡先用-i any抓所有網(wǎng)卡拿掉過濾條件試試確認抓包機器是否在流量路徑上提示Permission denied非root用戶執(zhí)行sudo執(zhí)行或者給普通用戶配置CAP_NET_RAW能力抓包過程中丟包嚴重緩沖區(qū)太小或CPU不夠用-B調(diào)大緩沖區(qū)減少無關(guān)抓包范圍用-s限制抓包長度文件寫入特別巨大抓包范圍太寬或snaplen太大嚴格限定host/port組合使用-s 128限制載荷用-C/-G自動切割文件tcpdump: syntax error過濾表達式引號沒加或?qū)戝e檢查是否用了單引號檢查語法中and、or的優(yōu)先級用括號包裹條件時務(wù)必加引號抓到包但Wireshark打不開文件未正常結(jié)束或抓包過程中被強殺用-w落盤務(wù)必用timeout或者-c限制別用kill -9強殺進程只看到請求沒看到ACK負載均衡器做了代理或者本機防火墻攔了確認流量路徑上是否有四層負載設(shè)備檢查本機iptables規(guī)則想抓但機器帶寬已被打滿抓包本身成為最后一根稻草改用硬件鏡像旁觀抓包或先做流量限速及時止損別硬抓最后再給大家一個殺手锏級別的提醒如果你要在生產(chǎn)環(huán)境長期蹲點千萬別忘了-Z root參數(shù)。默認tcpdump在打開抓包設(shè)備后會把自己降權(quán)到tcpdump用戶來執(zhí)行以防止安全問題。但有些環(huán)境下這個降權(quán)反而導(dǎo)致無法寫文件。如果你遇到這種詭異問題加個-Z root操作就能解決。當然這是個雙刃劍自己評估風(fēng)險再上別亂用。再分享一個我自己的習(xí)慣抓完包之后不管有沒有發(fā)現(xiàn)問題我都會寫一行小字記錄在案的命令行。這樣一個月后看到這個文件還能回憶起當初抓包時的范圍和意圖而不是對著幾百兆的二進制文件發(fā)愁我已經(jīng)忘了自己在驗證什么。如果你從頭看到這里恭喜你至少已經(jīng)從“會用tcpdump”進階到“知道為什么這么用tcpdump”的階段了。工具永遠是死的能靈活組合思路去抽絲剝繭才是這行真正值錢的地方。下次線上出故障別慌先深吸一口氣把上面這些招數(shù)從頭到尾過一遍多半就能摸到一點門道。