線上問題排查,一不小心踩到了一個Arthas的坑
最近幫新來的校招同學(xué)排查一個線上問題,問題本身不是很難,但是過程中踩到了一個arthas的坑,挺有意思的。
同時,也分享下在排查過程中使用的一些比較實用的工具,包括tcpdump、arthas、simpleHTTPServer等。
希望能對大家有所幫助。
1.問題描述
新開發(fā)的一個功能,簡單來說,就是讀取數(shù)據(jù)庫的數(shù)據(jù)展示在前臺。
本地啟動服務(wù)調(diào)試,用postman調(diào)用api,返回數(shù)據(jù)顯示正常,數(shù)據(jù)中的中文也正常。
但是部署到線上環(huán)境后,通過chrome瀏覽器調(diào)用和postman調(diào)用接口,返回的非中文數(shù)據(jù)正常,但是中文顯示亂碼。
2.排查思路
這個問題的第一反應(yīng)是請求的content-type有問題。
不過在chrome瀏覽器中確認(rèn)了請求的request和response的content-type都是application/json;charset=UTF-8,沒有問題。
然后又google了一番亂碼問題,基本上都是說的spring的HttpMessageConverter問題或者content-type,都無法解決。
只能深入排查一番了。
排查的主要思路就是先確定亂碼是哪一步產(chǎn)生的。
一個就是數(shù)據(jù)庫里查出來地方,需要用抓個包確認(rèn)下,不過我們本地服務(wù)調(diào)用是正確的,那么這一步應(yīng)該沒有問題。
一個是應(yīng)用服務(wù)返回的地方,需要用抓個包確認(rèn)下。在線上部署環(huán)境里,用tcpdump把對應(yīng)的應(yīng)用服務(wù)返回數(shù)據(jù)時抓個包。
一個就是代碼邏輯中存在數(shù)據(jù)轉(zhuǎn)換,這個需要通過arthas看看線上應(yīng)用的運行時數(shù)據(jù)情況。
3.用tcpdump抓包看服務(wù)端響應(yīng)
3.1 什么是tcpdump呢?
tcpdump是linux下的網(wǎng)絡(luò)數(shù)據(jù)包截獲分析工具。在linux的日常網(wǎng)絡(luò)管理中,tcpdump的使用頻率很高,熟練掌握對提高工作效率很有幫助。
3.2 報文抓取
為了獲取對應(yīng)服務(wù)的請求報文,需要登錄對應(yīng)的服務(wù)器(或者k8s的pod)使用tcpdump進行抓取。
作為一個暖男,我把從安裝到使用都一步步記下來給你 :)
1)安裝工具
如果你的服務(wù)器上沒有安裝過tcpdump,可以先執(zhí)行以下命令安裝
- yum -y install net-tools
2)查看網(wǎng)絡(luò)狀態(tài)
如果服務(wù)上有多個網(wǎng)卡,可以通過以下命令查看
- Netstat -i
3)部署抓包
- tcpdump -i eth0 tcp -w xxx.cap
- en0表示監(jiān)聽的網(wǎng)卡
- tcp表示報文類型
- -w 指定輸出文件名
還有很多其他選項可以過濾使用,大家可以網(wǎng)上搜一下,這里就不展開了。
4)調(diào)用請求
部署了tcpdump后,對服務(wù)器發(fā)起api請求。這時候相關(guān)的tcp報文都會被輸出到 xxx.cap文件中了。
3.3 報文解析
1)把xxx.cap文件發(fā)送本地
一般可以使用scp命令,直接發(fā)送
- scp xxxx.cap admin@10.xxx.xxx.xxx:/path
在傳輸服務(wù)器的文件到本地時,如果scp不方便使用,比如一些防火墻限制。
也可以使用 python 在服務(wù)器上開啟一個 web 服務(wù)(端口可自定義)。
- python -m SimpleHTTPServer 18888 &
然后在本地使用 wget 下載文件即可。
2)解析cap文件
本地得到cap文件后,可以通過wireshark軟件對cap文件進行解析,得到如下結(jié)果。
對api的報文進行解析后,發(fā)現(xiàn)返回對中文已經(jīng)是亂碼了,確認(rèn)了在服務(wù)端發(fā)出的響應(yīng)內(nèi)容中,已經(jīng)是亂碼了。
所以,只能繼續(xù)排查應(yīng)用本身的問題。
4.用arthas排查線上運行代碼
Arthas 是Alibaba開源的Java診斷工具,當(dāng)你遇到以下類似問題而束手無策時,都可以嘗試使用Arthas(更詳細(xì)的用法參考官方文檔:https://arthas.aliyun.com/doc/quick-start.html):
- 這個類從哪個 jar 包加載的?為什么會報各種類相關(guān)的 Exception?
- 遇到問題無法在線上 debug,又不想頻繁加日志再重新發(fā)布
- 線上遇到某個用戶的數(shù)據(jù)處理有問題,但線上同樣無法 debug,線下無法重現(xiàn)!
4.1 快速安裝、啟動
- curl -O https://arthas.aliyun.com/arthas-boot.jar
- java -jar arthas-boot.jar
4.2 運行代碼返回排查
本次排查,就使用了arthas的watch功能(更詳細(xì)的用法參考官方文檔:https://arthas.aliyun.com/doc/watch.html),能方便的觀察到指定方法的調(diào)用情況。能觀察到的范圍為:返回值、拋出異常、入?yún)ⅰ?/p>
我們先看看線上運行應(yīng)用controller層對于請求的響應(yīng),無需添加日志重新部署,我們馬上就能看到線上代碼的返回結(jié)果。
- watch xxx.xxx.controller method "{params,returnObj}" -x 2
然后發(fā)起api調(diào)用,在arthas中顯示結(jié)果如下:
我們可以看到,這個controller方法返回的內(nèi)容就是亂碼了。
因此,說明是代碼邏輯中存在轉(zhuǎn)換的問題了。
5.問題定位
根據(jù)業(yè)務(wù)邏輯,基本能猜測是從業(yè)務(wù)中的 byte[] 轉(zhuǎn)string的時候出現(xiàn)問題了。
找到對應(yīng)代碼如下,new string()時沒有指定字符集:
因此會在轉(zhuǎn)換過程中,默認(rèn)讀取系統(tǒng)變量的file.encoding作為字符集。
然后我們用arthas直接查看系統(tǒng)變量,果然不是utf8。
所以,解決方案有兩個。
第一種是在new string(bytes) 時指定字符集。
第二種就是設(shè)置系統(tǒng)變量file.encoding=utf-8。
5.進一步踩坑
我們一開始選擇了代碼修復(fù),在代碼中轉(zhuǎn)換時指定字符集。
重新發(fā)布后,再用arthas觀察一下,發(fā)現(xiàn)竟然還是亂碼??。?/p>
然后重新回頭在代碼中看了很久,一直找不到原因,陷入了僵局。。。
突然,隨手看了下線上,發(fā)現(xiàn)線上已經(jīng)顯示正常了,納尼?是arthas有問題?
然后google了一下,發(fā)現(xiàn)很多人碰到arthas顯示中文亂碼的問題。。。
解決方式也比較簡單,啟動arthas的時候,也指定一下字符集。
java -jar -Dfile.encoding=UTF-8 arthas-boot.jar
然后問題解決了。。。呵呵。。。
這時候再觀察arthas的結(jié)果已經(jīng)顯示正常。
這說明了什么??。。。?/p>
Arthas輸出界面的時候,肯定在字符串轉(zhuǎn)換的時候,也沒有指定字符集。。。。
一腳踩了個連環(huán)坑。。。
6.總結(jié)
其實整個問題是比較粗淺的,就是最后這個arthas的中文亂碼讓人有點腦殼疼。
當(dāng)然,最主要還是簡單分享下tcpdump、arthas、simpleHTTPServer這些小工具,希望能有所幫助吧。