排障實(shí)戰(zhàn):Wireshark抓包定位服務(wù)發(fā)現(xiàn)與通信故障)
干了這么些年汽車以太網(wǎng)和SOA中間件我越來越覺得SOME/IP這個(gè)協(xié)議本身其實(shí)不算復(fù)雜真正折磨人的是它在實(shí)際項(xiàng)目里出現(xiàn)的各種“玄學(xué)”問題。很多時(shí)候節(jié)點(diǎn)連上了網(wǎng)絡(luò)也通了但服務(wù)就是發(fā)現(xiàn)不了或者調(diào)用到一半就超時(shí)最后查來查去發(fā)現(xiàn)根因往往不是代碼邏輯多高深而是一些非?;A(chǔ)的細(xì)節(jié)沒對(duì)上——IP配錯(cuò)了一位、端口被復(fù)用、報(bào)文長(zhǎng)度算錯(cuò)、字節(jié)序搞反。這篇文章我就想把這些典型的“翻車”現(xiàn)場(chǎng)捋一捋聊聊癥狀、根因以及我是怎么用抓包一步步定位的。無論你是剛接觸SOME/IP的新手還是已經(jīng)踩過不少坑的工程師希望這些經(jīng)驗(yàn)?zāi)茏屇闵僮唿c(diǎn)彎路。前陣子項(xiàng)目聯(lián)調(diào)我盯著Wireshark里的SOME/IP報(bào)文一邊追一邊罵娘。排查到最后問題居然出在一個(gè)看起來人畜無害的“端口中繼”上——服務(wù)端廣播OfferService用的是30490但實(shí)際訂閱時(shí)報(bào)文卻發(fā)到了另一個(gè)端口客戶端壓根沒監(jiān)聽那個(gè)端口把包全丟了。這種問題如果不抓包光靠翻代碼你可能翻三天也翻不出來。所以我一直有個(gè)習(xí)慣遇到SOME/IP相關(guān)的問題先別急著改代碼先抓包用數(shù)據(jù)說話。下面我就從“癥狀—根因—抓包定位”這條線把幾類典型現(xiàn)場(chǎng)完整復(fù)盤一下重點(diǎn)分享我的分析思路和實(shí)戰(zhàn)操作希望能幫你建立起一套自己的排查體系。1. 先把“翻車”癥狀分個(gè)類別像個(gè)無頭蒼蠅SOME/IP的故障表象千奇百怪但總結(jié)下來無非落在三個(gè)大階段里服務(wù)發(fā)現(xiàn)Service Discovery階段、事件訂閱Subscribe/Notify階段、遠(yuǎn)程調(diào)用Request/Response階段。我遇到的絕大多數(shù)問題都可以歸到這三類里。1.1 服務(wù)發(fā)現(xiàn)階段服務(wù)老是“找不到”這是最讓人抓狂的一類??蛻舳薋indService報(bào)文發(fā)得勤勤懇懇服務(wù)端也有響應(yīng)但客戶端就是認(rèn)為“服務(wù)不可用”。典型癥狀包括客戶端日志里一直刷“Service not available”但抓包看服務(wù)端明明已經(jīng)回復(fù)了OfferService。服務(wù)端周期性廣播OfferService但客戶端像是“瞎了”一樣完全無感。偶爾能通偶爾又?jǐn)喾?wù)狀態(tài)在那跳來跳去極不穩(wěn)定。1.2 事件訂閱階段要么不推要么推了收不到這類問題往往表現(xiàn)為“靜態(tài)數(shù)據(jù)正常動(dòng)態(tài)數(shù)據(jù)不更新”。客戶端已經(jīng)成功調(diào)用了服務(wù)但服務(wù)端的事件Event/Field就是不能主動(dòng)推過來。常見現(xiàn)象SubscribeEventgroup發(fā)出去了服務(wù)端也回了SubscribeAck但之后客戶端收不到任何Notification。客戶端能收到Notification但過一會(huì)兒就斷了既不重發(fā)訂閱也不報(bào)錯(cuò)。多個(gè)客戶端訂閱同一個(gè)事件組其中一個(gè)收到數(shù)據(jù)另一個(gè)死活收不到。1.3 遠(yuǎn)程調(diào)用階段超時(shí)、錯(cuò)亂、響應(yīng)張冠李戴這是最像“日常開發(fā)調(diào)試”的場(chǎng)景癥狀也更直接請(qǐng)求發(fā)出去后客戶端等待Response超時(shí)但服務(wù)端日志顯示已經(jīng)處理并回復(fù)了。收到了Response的SOME/IP消息但反序列化報(bào)錯(cuò)字段錯(cuò)亂或結(jié)構(gòu)體解析失敗。Response的Request ID和客戶端發(fā)出去的Request ID對(duì)不上導(dǎo)致調(diào)用方壓根識(shí)別不了這是自己的響應(yīng)。大報(bào)文被TCP分包接收方組包失敗數(shù)據(jù)直接丟棄。把癥狀歸好類之后排查方向就清晰了。你不需要在同一時(shí)間懷疑所有人而是可以按照“階段”去過濾嫌疑對(duì)象。2. 三個(gè)典型“翻車”現(xiàn)場(chǎng)復(fù)盤從現(xiàn)象到根因下面我挑三個(gè)我印象特別深的案例從癥狀、排查過程到根因完整還原一遍。這三個(gè)案例分別對(duì)應(yīng)上面說的三個(gè)階段而且都有很強(qiáng)的代表性你會(huì)看到最后定位出來的根因往往都“出乎意料卻又在情理之中”。2.1 現(xiàn)場(chǎng)一OfferService漫天飛客戶端就是“不領(lǐng)情”癥狀非常清晰服務(wù)端按照配置周期性地發(fā)送OfferService報(bào)文Wireshark里看得清清楚楚源IP、源端口30490、目的IP為組播地址報(bào)文層層的SOME/IP頭解析也正常。但客戶端那邊無論怎么刷新服務(wù)狀態(tài)始終是“未發(fā)現(xiàn)”。我的排查習(xí)慣是先對(duì)齊雙方視圖。Wireshark過濾SOME/IP確認(rèn)客戶端有沒有發(fā)出FindService。結(jié)果很有意思客戶端壓根沒往外發(fā)FindService也沒有主動(dòng)去發(fā)任何SOME/IP消息。那問題就變成了“客戶端為什么不起服務(wù)發(fā)現(xiàn)流程”而不是“為什么發(fā)現(xiàn)不了”。然后我去翻客戶端配置文件。果然客戶端配置里把服務(wù)端實(shí)例的IP地址寫錯(cuò)了。開發(fā)者把上位機(jī)也就是調(diào)試電腦的IP填進(jìn)去了而服務(wù)端實(shí)際IP是另外一段。SOME/IP的服務(wù)發(fā)現(xiàn)沿用了傳統(tǒng)的組播機(jī)制客戶端要能收到OfferService網(wǎng)卡必須加入了對(duì)應(yīng)的組播組并且服務(wù)端實(shí)例的配置與服務(wù)的宣告信息要能夠匹配上。你IP配不對(duì)客戶端根本不會(huì)處理這些OfferService。根因客戶端配置的服務(wù)端實(shí)例IP錯(cuò)誤導(dǎo)致客戶端側(cè)對(duì)不上服務(wù)宣告的EndPoint服務(wù)發(fā)現(xiàn)流程直接沒起來。這個(gè)案例給我最大的教訓(xùn)是排查SOME/IP第一步永遠(yuǎn)是“確認(rèn)雙方視角里的IP、端口、協(xié)議版本是一致的”。別一上來就懷疑協(xié)議棧有bug。2.2 現(xiàn)場(chǎng)二事件訂閱成功Notification卻“人間蒸發(fā)”這個(gè)案例更隱蔽??蛻舳薃和客戶端B訂閱同一個(gè)事件組客戶端A能收到數(shù)據(jù)客戶端B收不到。當(dāng)時(shí)現(xiàn)場(chǎng)用的是vSomeIP協(xié)議棧服務(wù)端配置了多個(gè)訂閱端點(diǎn)負(fù)載均衡看起來也沒問題。抓包對(duì)比發(fā)現(xiàn)客戶端A發(fā)出的SubscribeEventgroup服務(wù)端回了SubscribeAck并且之后的數(shù)據(jù)Notification都發(fā)到了A的某個(gè)端口上A確實(shí)也收到了??蛻舳薆發(fā)出的SubscribeEventgroup報(bào)文服務(wù)端也處理了也回了SubscribeAck但后續(xù)的Notification報(bào)文Wireshark里根本沒有出現(xiàn)發(fā)往B的包。這就很奇怪了服務(wù)端既然已經(jīng)應(yīng)答了Ack說明它認(rèn)為訂閱已經(jīng)建立成功為什么不往B發(fā)數(shù)據(jù)呢我仔細(xì)對(duì)比了A和B的SubscribeEventgroup報(bào)文內(nèi)容終于發(fā)現(xiàn)了端倪兩個(gè)報(bào)文的Message ID一樣Eventgroup ID一樣但客戶端B報(bào)文里的Endpoint選項(xiàng)Endpoint Option中填寫的IP和端口竟然是網(wǎng)關(guān)上另一個(gè)網(wǎng)卡的地址不是B自己的實(shí)際通信端點(diǎn)。根因客戶端B配置的“事件上報(bào)端點(diǎn)”錯(cuò)誤上報(bào)到一個(gè)不存在的地址去了。服務(wù)端按照訂閱報(bào)文里的Endpoint Option把Notification發(fā)過去自然就“人間蒸發(fā)”了。這個(gè)案例告訴我一個(gè)關(guān)鍵點(diǎn)SOME/IP的事件訂閱本質(zhì)上就是客戶端告訴服務(wù)端“你之后就往我這個(gè)IP和端口推數(shù)據(jù)”。這個(gè)IP和端口如果配錯(cuò)后面全是無用功。2.3 現(xiàn)場(chǎng)三Response正常發(fā)出客戶端卻永久超時(shí)這個(gè)案例是典型的“響應(yīng)丟了”。服務(wù)端日志顯示收到請(qǐng)求處理完成Response已發(fā)出。但客戶端一直在等最后拋超時(shí)異常。抓包也看到了服務(wù)端發(fā)的Response報(bào)文Wireshark解析正常源端口、目的端口都對(duì)。但問題恰恰就藏在“端口對(duì)”這個(gè)表象之下。我再仔細(xì)看了一眼服務(wù)端發(fā)出的Response目的IP是客戶端的IP但目的端口是一個(gè)和客戶端監(jiān)聽端口完全不同的端口。也就是說SOME/IP Response報(bào)文的目的端口不是SOME/IP協(xié)議默認(rèn)的端口極有可能是服務(wù)端在發(fā)送時(shí)錯(cuò)誤地使用了請(qǐng)求報(bào)文里的源端口字段或者配置里的客戶端端口而實(shí)際客戶端SOME/IP的接收端口是另外一個(gè)固定的端口??蛻舳说膮f(xié)議棧只在自己的監(jiān)聽端口上收包看到這個(gè)目的端口不對(duì)直接就忽略了。在TCP層面這個(gè)包可能還會(huì)因?yàn)槎丝诓豢蛇_(dá)而觸發(fā)RST但在UDP上它就這樣悄無聲息地被丟棄了。根因服務(wù)端回復(fù)Response時(shí)目的端口和客戶端實(shí)際監(jiān)聽端口不一致導(dǎo)致響應(yīng)報(bào)文被客戶端協(xié)議棧丟棄。針對(duì)這類問題我在后續(xù)項(xiàng)目里定了規(guī)矩SOME/IP通信的端口映射必須統(tǒng)一管理特別是使用網(wǎng)絡(luò)地址轉(zhuǎn)換或網(wǎng)關(guān)轉(zhuǎn)發(fā)時(shí)端口不能想當(dāng)然。3. 用Wireshark“破案”的實(shí)操手法從抓到看懂再到定位癥狀和根因講完了接下來是干貨部分。很多朋友跟我說“我抓包了但還是看不懂不知道接下來該干嘛?!蔽矣X得問題的核心在于你只是“抓到”了沒有“看懂”。看懂報(bào)文是一層功夫看懂之后能倒推出根因是更高一層的功夫。3.1 Wireshark下SOME/IP的過濾和識(shí)別技巧Wireshark對(duì)SOME/IP的解析支持得不錯(cuò)。在較新版本中安裝了相應(yīng)的協(xié)議解析插件或使用內(nèi)置解析器后你直接在過濾欄輸入someip就能過濾出所有SOME/IP報(bào)文。如果你想更細(xì)粒度地過濾可以配合IP和端口一起用比如someip ip.addr 192.168.0.10另外我還習(xí)慣用tcpdump在車載設(shè)備上抓原始包再拿回Wireshark分析。命令行抓包有幾個(gè)好處一是目標(biāo)機(jī)上沒有圖形界面也可以抓二是可以精確控制抓包時(shí)間避免長(zhǎng)時(shí)間抓包產(chǎn)生超大文件。注意抓包的時(shí)候文件別太大否則Wireshark打開會(huì)卡到懷疑人生。3.2 通用排查五步法先看握手再看往返最后看數(shù)據(jù)這里我總結(jié)了一套在SOME/IP調(diào)試中特別管用的排查流程你可以直接拿去做模板步驟操作目標(biāo)1過濾SOME/IP確認(rèn)有沒有完整的FindService/OfferService交互確定服務(wù)發(fā)現(xiàn)鏈路是否通2檢查服務(wù)發(fā)現(xiàn)報(bào)文中的Endpoint Option和IP/端口確認(rèn)訂閱/調(diào)用要使用的實(shí)際通信端點(diǎn)3篩選特定的Message ID或Service ID定位到具體服務(wù)聚焦業(yè)務(wù)層排除其他報(bào)文干擾4對(duì)比Request和Response中的Request ID、Session ID判斷響應(yīng)是否與請(qǐng)求一一對(duì)應(yīng)5檢查SOME/IP頭中的Length字段和負(fù)載內(nèi)容確認(rèn)報(bào)文長(zhǎng)度、序列化是否正確這套流程我用了很多年每次都能快速把問題圈定在一個(gè)很小的范圍內(nèi)。本質(zhì)思路是“由遠(yuǎn)及近、由宏觀到微觀、由協(xié)議到業(yè)務(wù)”。你先把整個(gè)通信鏈路看明白了再深入到具體的報(bào)文字段去挑毛病效率會(huì)高很多。3.3 那些你必須刻在腦子里的SOME/IP報(bào)文字段看懂報(bào)文的前提是熟悉報(bào)文里每個(gè)字段的含義。我挑幾個(gè)在排查時(shí)最常用的字段講一講這些字段是抓包定位的基礎(chǔ)Message IDService ID Method ID這是服務(wù)標(biāo)識(shí)和方法的組合。定位是哪個(gè)服務(wù)的哪個(gè)方法時(shí)先看它。比如0x1234對(duì)應(yīng)一個(gè)服務(wù)后面0x8001可能表示一個(gè)事件通知0x0001表示一個(gè)遠(yuǎn)程調(diào)用方法。Request ID / Session ID用于匹配請(qǐng)求和響應(yīng)。客戶端每發(fā)一個(gè)請(qǐng)求都會(huì)帶一個(gè)唯一的Request ID服務(wù)端回復(fù)Response時(shí)必須原樣返回這個(gè)ID。Session ID在SOME/IP中通常用于區(qū)分同一請(qǐng)求的多次嘗試或者分段消息。如果Response里的Request ID和請(qǐng)求對(duì)不上客戶端就會(huì)丟棄該響應(yīng)這是典型的“張冠李戴”問題。Protocol Version / Interface Version協(xié)議版本和接口版本。通信雙方這兩個(gè)值要匹配否則可能出現(xiàn)不兼容的行為。Message Type表示消息類型如REQUEST0x00RESPONSE0x80NOTIFICATION0x02還有用于錯(cuò)誤處理的REQUEST_ACCEPTED等。排查時(shí)如果看到類型不符合預(yù)期比如該是Response卻來了個(gè)Request說明對(duì)端邏輯有問題。Return Code返回碼是排查老中醫(yī)的“脈搏”很多疑難雜癥你一看Return Code就明白了。常見的如E_OK0x00、E_NOT_OK0x01、E_UNKNOWN_SERVICE0x02等。比如服務(wù)端回了E_NOT_OK客戶端還傻等響應(yīng)那問題就在服務(wù)端邏輯上。Length字段這個(gè)字段太重要了。SOME/IP的Length是從Request ID之后開始計(jì)算的到負(fù)載結(jié)束。很多序列化錯(cuò)位最后查下來都是Length填寫錯(cuò)誤。你可以用Wireshark的“Length”列和協(xié)議解析出來的長(zhǎng)度對(duì)比如果兩者不一致基本可以斷定是打包/解包邏輯有問題。4. 問題排查實(shí)戰(zhàn)那些年我們一起踩過的“大坑”說完了方法論我再把那些年我在實(shí)際項(xiàng)目中踩過的“大坑”集中曬一曬。這些坑不親自踩一遍大概率是不會(huì)長(zhǎng)記性的。4.1 “抓不到包”不等于“沒有包”很多朋友抓完包發(fā)現(xiàn)Wireshark里空蕩蕩的就開始懷疑是不是網(wǎng)卡選錯(cuò)了。其實(shí)“抓不到包”至少有三層含義第一你要抓的流量可能根本沒經(jīng)過當(dāng)前網(wǎng)卡。你插著USB轉(zhuǎn)以太網(wǎng)抓包數(shù)據(jù)卻從另一個(gè)板載網(wǎng)卡走了那當(dāng)然抓不到。第二防火墻或交換機(jī)配置把組播報(bào)文過濾了。SOME/IP的服務(wù)發(fā)現(xiàn)大量使用組播如果交換機(jī)開啟了IGMP Snooping但沒有正確維護(hù)組成員關(guān)系組播包就可能被丟棄。第三抓包時(shí)間太短你只在業(yè)務(wù)空閑期抓了幾秒而服務(wù)發(fā)現(xiàn)是周期性或觸發(fā)式的自然抓不到關(guān)鍵交互。所以遇到“抓不到”先逐層排查網(wǎng)卡選對(duì)了嗎鏈路是Hub還是交換機(jī)交換機(jī)的組播策略是什么抓包時(shí)長(zhǎng)夠不夠我曾在VLAN隔離的測(cè)試環(huán)境里折騰了一個(gè)多小時(shí)最后發(fā)現(xiàn)抓包電腦根本不在那個(gè)VLAN里白干。4.2 端口沖突與“隱形”的NAT轉(zhuǎn)換SOME/IP的調(diào)試環(huán)境往往很復(fù)雜有開發(fā)板、有網(wǎng)關(guān)、有上位機(jī)。網(wǎng)關(guān)設(shè)備通常會(huì)做網(wǎng)絡(luò)地址轉(zhuǎn)換或端口映射特別是在跨網(wǎng)段通信的場(chǎng)景下。我在前東家做跨域控制器聯(lián)調(diào)時(shí)遇到過類似的情況服務(wù)端在域控A客戶端在域控B中間隔著一個(gè)網(wǎng)關(guān)??蛻舳税l(fā)不起訂閱、收不到數(shù)據(jù)抓包看報(bào)文完全沒問題IP、端口、方向都對(duì)。后來查了網(wǎng)關(guān)上的NAT表發(fā)現(xiàn)它只映射了特定端口客戶端發(fā)給服務(wù)的請(qǐng)求從網(wǎng)關(guān)出去后源端口被改了服務(wù)端回復(fù)時(shí)不知道該回給誰導(dǎo)致通信徹底斷裂。這類問題抓包很難直接看出來因?yàn)榫W(wǎng)關(guān)兩側(cè)的報(bào)文“各自正確”但連起來看就穿幫了。我當(dāng)時(shí)的排查方法是在網(wǎng)關(guān)兩側(cè)同時(shí)抓包做時(shí)間同步對(duì)比定位到NAT表配置異常。注意跨網(wǎng)段SOME/IP通信時(shí)一定要確認(rèn)網(wǎng)關(guān)的NAT/路由策略確實(shí)支持雙向的UDP端口映射并保留好端口轉(zhuǎn)換日志。4.3 TTL、多網(wǎng)卡和“半路出家”的協(xié)議棧最后說個(gè)容易讓新人崩潰的坑網(wǎng)絡(luò)報(bào)文在傳輸過程中源IP和目的IP都可能被中間的設(shè)備修改但SOME/IP的應(yīng)用層字段比如Endpoint Option里寫的地址是死的不會(huì)跟著變。如果應(yīng)用層配置的地址和實(shí)際網(wǎng)絡(luò)拓?fù)洳灰恢戮蜁?huì)出現(xiàn)“報(bào)文到了但應(yīng)用不認(rèn)”的情況。比如說車載以太網(wǎng)的多個(gè)域控制器之間經(jīng)常用VLAN隔開。如果SOME/IP應(yīng)用層仍然使用未打標(biāo)簽的IP地址和端口進(jìn)行通信那么在VLAN環(huán)境下就很容易出問題。抓包時(shí)帶上vlan過濾條件多看看是不是VLAN ID對(duì)不上。另外多網(wǎng)卡設(shè)備上如果客戶端有多個(gè)IP服務(wù)端回復(fù)時(shí)選擇了錯(cuò)誤的源IP就可能導(dǎo)致客戶端校驗(yàn)失敗。我之前就碰到過一臺(tái)設(shè)備上裝了好幾個(gè)虛擬網(wǎng)卡結(jié)果協(xié)議棧默認(rèn)走了錯(cuò)誤的網(wǎng)卡出口報(bào)文源IP不是對(duì)方期望的那個(gè)導(dǎo)致通信失敗。5. 定位神器長(zhǎng)期抓包與自動(dòng)化分析環(huán)境搭建前面講的都是“一次性”抓包但在實(shí)際項(xiàng)目里問題往往不是復(fù)現(xiàn)一次就能找到的。很多時(shí)候Bug是偶發(fā)的比如每二十分鐘丟一個(gè)包或者跑完一整晚才出現(xiàn)一次異常。這時(shí)候你需要一套“長(zhǎng)期抓包自動(dòng)化分析”的環(huán)境而不是一直人工盯著Wireshark。5.1 tcpdump與環(huán)形緩沖長(zhǎng)期抓包的保命手段在目標(biāo)設(shè)備上跑tcpdump是做長(zhǎng)時(shí)間抓包的標(biāo)配。但要注意持續(xù)抓包會(huì)占用大量磁盤空間而且最終的分析文件會(huì)非常巨大。我常用的辦法是啟用環(huán)形緩沖tcpdump -i eth0 -s 0 -w /data/capture.pcap -C 200 -W 20這條命令的意思是以200MB為單位抓包最多保留20個(gè)文件也就是大約4GB的循環(huán)存儲(chǔ)空間。超過之后新的包會(huì)覆蓋最舊的文件保證不會(huì)把磁盤寫爆。不過要注意環(huán)形緩沖是有風(fēng)險(xiǎn)的——如果問題發(fā)生后你沒有及時(shí)把現(xiàn)場(chǎng)文件拷走關(guān)鍵報(bào)文可能就被后續(xù)的流量覆蓋掉了。所以我一般會(huì)在問題可能復(fù)現(xiàn)的階段手動(dòng)禁用環(huán)形覆蓋或者盡快轉(zhuǎn)存現(xiàn)場(chǎng)數(shù)據(jù)。5.2 用Python pyshark做自動(dòng)化報(bào)文分析等抓到的包足夠多了靠肉眼一個(gè)個(gè)看是不現(xiàn)實(shí)的。我習(xí)慣用Python的pyshark庫(kù)寫點(diǎn)小腳本快速?gòu)膒cap里提取特定字段輸出成表格或日志。這里特別提醒一句Python版本和pyshark版本容易打架。網(wǎng)上很多教程用的是Python 2.7現(xiàn)在用了新的Python版本之后pyshark可能會(huì)存在兼容性問題最常見的就是“無法抓包”或“tshark路徑找不到”。排查思路一般是確認(rèn)tshark是否獨(dú)立安裝、環(huán)境變量是否配置好、Wireshark主程序和pyshark版本是否匹配。用一個(gè)簡(jiǎn)單例子說明用法。下面的腳本遍歷抓包文件輸出所有SOME/IP報(bào)文的Message ID、源IP和目的IPimport pyshark cap pyshark.FileCapture(capture.pcap, display_filtersomeip) for pkt in cap: try: msg_id pkt.someip.msg_id src_ip pkt.ip.src dst_ip pkt.ip.dst print(f{src_ip} - {dst_ip} | Message ID: {msg_id}) except AttributeError: pass注意這里pkt.someip能解析的前提是Wireshark的SOME/IP解析器已正確安裝且pcap中的端口被識(shí)別為SOME/IP端口。如果不確定可以先用Wireshark打開文件確認(rèn)一下協(xié)議是否被正確識(shí)別。用腳本批量過濾你會(huì)發(fā)現(xiàn)很多肉眼難以發(fā)現(xiàn)的規(guī)律比如某個(gè)Request ID出現(xiàn)頻率異?;蛘吣硞€(gè)端口上意外出現(xiàn)了非SOME/IP流量。5.3 時(shí)間戳對(duì)齊多端抓包的“破案關(guān)鍵”多端同時(shí)抓包時(shí)時(shí)間戳對(duì)齊比什么都重要。剛開始做聯(lián)調(diào)時(shí)我在服務(wù)端抓一份、客戶端抓一份、中間網(wǎng)關(guān)上又抓一份三份包的時(shí)間基準(zhǔn)各不相同結(jié)果根本無法對(duì)照。后來學(xué)乖了所有抓包設(shè)備統(tǒng)一用PTP或者NTP同步時(shí)間實(shí)在不行在抓包開始時(shí)發(fā)一個(gè)大家都認(rèn)的同步報(bào)文比如同時(shí)ping一個(gè)網(wǎng)關(guān)用這個(gè)ICMP報(bào)文作為時(shí)間錨點(diǎn)。6. 事后復(fù)盤SOME/IP排障要從“玄學(xué)”到“科學(xué)”我發(fā)現(xiàn)很多人對(duì)SOME/IP的排障停留在“試錯(cuò)”階段——改個(gè)配置試試不行再改回來再不行重啟一下。這種“程序員式”的調(diào)試法在復(fù)雜多節(jié)點(diǎn)環(huán)境下效率極低而且容易引入新的問題。我的心得是一定要把排障過程“科學(xué)化”。什么意思就是要形成一套“假設(shè)—驗(yàn)證—修正”的閉環(huán)。發(fā)現(xiàn)現(xiàn)象后先根據(jù)已有信息提出一個(gè)或多個(gè)假設(shè)然后用抓包數(shù)據(jù)去驗(yàn)證或推翻假設(shè)最后找到真正根因再去做修改。修改完后要做回歸驗(yàn)證確保問題真的消失。如果你每次都靠“重啟”來恢復(fù)那你永遠(yuǎn)不知道問題的真正原因是什么也不知道它什么時(shí)候會(huì)再來。6.1 建立一套“報(bào)文日志關(guān)聯(lián)”機(jī)制在車上做HIL測(cè)試時(shí)經(jīng)常是SOME/IP通信和診斷、以太網(wǎng)刷寫同時(shí)進(jìn)行問題定位難上加難。我的做法是讓SOME/IP日志和應(yīng)用層日志打上同樣的時(shí)間戳和會(huì)話ID這樣排查時(shí)可以把應(yīng)用層日志里的錯(cuò)誤信息和抓包里的某個(gè)具體報(bào)文關(guān)聯(lián)起來。具體操作就是在打印日志時(shí)把SOME/IP消息的Message ID、Request ID、Session ID一起帶上。這樣無論是看代碼還是看抓包都有共同語言溝通成本直線下降。6.2 快速自查清單最后把我平常遇到SOME/IP問題時(shí)的第一反應(yīng)清單分享給你大概率能幫你省掉幾個(gè)小時(shí)通信雙方的服務(wù)實(shí)例ID、接口版本、協(xié)議版本是否一致服務(wù)發(fā)現(xiàn)的組播IP和端口對(duì)不對(duì)IP_ADD_MEMBERSHIP有沒有設(shè)置服務(wù)實(shí)例的通信EndpointIP、端口是否正確特別是跨網(wǎng)段情況下。客戶端有沒有加入事件組的訂閱請(qǐng)求服務(wù)端有沒有回SubscribeAckNotification的實(shí)際目的地IP和端口是否和客戶端填寫的Endpoint一致報(bào)文里的Length字段是不是和實(shí)際載荷長(zhǎng)度一致Request ID和Session ID是否亂序或重復(fù)這張清單看起來簡(jiǎn)單但每一行背后都有真實(shí)事故支持。尤其是“Length字段”這一項(xiàng)我至少見過不下五次因?yàn)槭謱懶蛄谢ぞ咚沐e(cuò)長(zhǎng)度導(dǎo)致整個(gè)SOC上SOME/IP通信癱瘓的情況。7. 抓包定位的常用工具組合與心得講到這里我再把常用工具組合做個(gè)簡(jiǎn)單的橫向?qū)Ρ葞椭蠹腋鶕?jù)場(chǎng)景選擇合適的方案場(chǎng)景推薦工具優(yōu)勢(shì)注意事項(xiàng)單節(jié)點(diǎn)快速抓包Wireshark直觀支持協(xié)議解析、過濾大文件卡頓需注意過濾條件無圖形界面/遠(yuǎn)程tcpdump Wireshark輕量可長(zhǎng)時(shí)間抓包靈活需要注意文件循環(huán)覆蓋和權(quán)限問題自動(dòng)化批量分析Python pyshark可腳本化提取任意字段注意Python/pyshark/tshark版本兼容性多節(jié)點(diǎn)同步對(duì)比多端口抓包 時(shí)間同步可以定位跨節(jié)點(diǎn)問題必須做好時(shí)間基準(zhǔn)統(tǒng)一現(xiàn)場(chǎng)快速診斷上位機(jī)的SOME/IP自檢工具可以主動(dòng)發(fā)FindService試探部分工具對(duì)協(xié)議版本支持有限工具不在多順手就行。但有一點(diǎn)值得強(qiáng)調(diào)真正讓你快速定位的不是工具本身而是你對(duì)SOME/IP協(xié)議字段和交互流程的熟悉程度。工具只是把你的眼力延伸到了網(wǎng)絡(luò)包層面。個(gè)人而言我還是最喜歡WiresharkTShark的組合前者負(fù)責(zé)可視化分析后者負(fù)責(zé)腳本化二次處理。配合一點(diǎn)Python腳本基本上能覆蓋我日常排障中90%以上的場(chǎng)景。至于Fiddler這些工具更多是應(yīng)用層調(diào)試用的在SOME/IP這種車用以太網(wǎng)協(xié)議棧下不太適用如果你在做的是基于HTTP的API調(diào)試那另說。8. 最后再分享一點(diǎn)個(gè)人經(jīng)驗(yàn)回頭再看看這些年的SOME/IP“翻車”經(jīng)歷其實(shí)很多問題都不是技術(shù)多高深而是輸在“對(duì)基礎(chǔ)配置的敬畏心”上。IP端口配對(duì)錯(cuò)、服務(wù)實(shí)例ID抄錯(cuò)、Endpoint配置遺漏這些聽起來特別低級(jí)但在繁重的聯(lián)調(diào)任務(wù)面前恰恰是最容易犯的錯(cuò)。我自己現(xiàn)在的習(xí)慣是在寫代碼之前先畫一張節(jié)點(diǎn)通信矩陣圖把每個(gè)服務(wù)、每個(gè)實(shí)例、每個(gè)Method/Event的ID、端口、IP全部列出來然后和配置表一一核對(duì)。聽起來繁瑣但省下來的是聯(lián)調(diào)現(xiàn)場(chǎng)的大把時(shí)間。另外我也開始強(qiáng)制自己在每次抓包后無論有沒有定位到問題都把抓包文件、分析結(jié)論和修改記錄歸檔起來。時(shí)間久了這就是一套非常寶貴的排障知識(shí)庫(kù)。希望這篇分享能幫你少踩幾個(gè)坑。如果后續(xù)有空我還會(huì)聊聊SOME/IP的序列化細(xì)節(jié)、基于SOME/IP的服務(wù)集成就與測(cè)試以及和DDS等其他通信中間件的對(duì)比選型。咱們下次再聊。