1. 程式人生 > >線上問題排查,一不小心踩到阿里的 arthas坑了

線上問題排查,一不小心踩到阿里的 arthas坑了

最近幫新來的校招同學排查一個線上問題,問題本身不是很難,但是過程中踩到了一個arthas的坑,挺有意思的。

同時,也分享下在排查過程中使用的一些比較實用的工具,包括tcpdump、arthas、simpleHTTPServer等,希望能對大家有所幫助。

1.問題描述

新開發的一個功能,簡單來說,就是讀取資料庫的資料展示在前臺。

本地啟動服務除錯,用postman呼叫api,返回資料顯示正常,資料中的中文也正常。

但是部署到線上環境後,通過chrome瀏覽器呼叫和postman呼叫介面,返回的非中文資料正常,但是中文顯示亂碼。

2.排查思路

這個問題的第一反應是請求的content-type有問題。

不過在chrome瀏覽器中確認了請求的request和response的content-type都是application/json;charset=UTF-8,沒有問題。

然後又google了一番亂碼問題,基本上都是說的spring的HttpMessageConverter問題或者content-type,都無法解決。

只能深入排查一番了。

排查的主要思路就是先確定亂碼是哪一步產生的。

  • 一個就是資料庫裡查出來地方,需要用抓個包確認下,不過我們本地服務呼叫是正確的,那麼這一步應該沒有問題。
  • 一個是應用服務返回的地方,需要用抓個包確認下。在線上部署環境裡,用tcpdump把對應的應用服務返回資料是抓個包。
  • 一個就是程式碼邏輯中存在資料轉換,這個需要通過arthas看看線上應用的執行時資料情況。

3.用tcpdump抓包看服務端響應

3.1 什麼是tcpdump呢?

tcpdump是linux下的網路資料包截獲分析工具。在linux的日常網路管理中,tcpdump的使用頻率很高,熟練掌握對提高工作效率很有幫助。

 

3.2 報文抓取

為了獲取對應服務的請求報文,需要登入對應的伺服器(或者k8s的pod)使用tcpdump進行抓取。

作為一個暖男,我把從安裝到使用都一步步記下來給你 :)

1)安裝工具

如果你的伺服器上沒有安裝過tcpdump,可以先執行以下命令安裝

yum -y install net-tools

2)檢視網路狀態

如果服務上有多個網絡卡,可以通過以下命令檢視

Netstat -i

 

3)部署抓包

tcpdump -i eth0 tcp -w xxx.cap
  • en0表示監聽的網絡卡
  • tcp表示報文型別
  • -w 指定輸出檔名

還有很多其他選項可以過濾使用,大家可以網上搜一下,這裡就不展開了。

4)呼叫請求

部署了tcpdump後,對伺服器發起api請求。這時候相關的tcp報文都會被輸出到 xxx.cap檔案中了。

3.3 報文解析

1)把xxx.cap檔案傳送本地

一般可以使用scp命令,直接傳送

scp xxxx.cap [email protected]:/path

在傳輸伺服器的檔案到本地時,如果scp不方便使用,比如一些防火牆限制。

也可以使用 python 在伺服器上開啟一個 web 服務(埠可自定義)。

 

python -m SimpleHTTPServer 18888 &

然後在本地使用 wget 下載檔案即可。

2)解析cap檔案

本地得到cap檔案後,可以通過wireshark軟體對cap檔案進行解析,得到如下結果。

 

 

 

對api的報文進行解析後,發現返回對中文已經是亂碼了,確認了在服務端發出的響應內容中,已經是亂碼了。

所以,只能繼續排查應用本身的問題。

4.用arthas排查線上執行程式碼

Arthas 是Alibaba開源的Java診斷工具,當你遇到以下類似問題而束手無策時,都可以嘗試使用Arthas(更詳細的用法參考官方文件:https://arthas.aliyun.com/doc/quick-start.html):

  • 這個類從哪個 jar 包載入的?為什麼會報各種類相關的 Exception?
  • 遇到問題無法在線上 debug,又不想頻繁加日誌再重新發布
  • 線上遇到某個使用者的資料處理有問題,但線上同樣無法 debug,線下無法重現!

4.1快速安裝、啟動

curl -O https://arthas.aliyun.com/arthas-boot.jar

java -jar arthas-boot.jar

4.2 執行程式碼返回排查

本次排查,就使用了arthas的watch功能(更詳細的用法參考官方文件:https://arthas.aliyun.com/doc/watch.html),能方便的觀察到指定方法的呼叫情況。能觀察到的範圍為:返回值、丟擲異常、入參。

我們先看看線上執行應用controller層對於請求的響應,無需新增日誌重新部署,我們馬上就能看到線上程式碼的返回結果。

watch xxx.xxx.controller method "{params,returnObj}" -x 2

然後發起api呼叫,在arthas中顯示結果如下:

 


我們可以看到,這個controller方法返回的內容就是亂碼了。

因此,說明是程式碼邏輯中存在轉換的問題了。

5.問題定位

根據業務邏輯,基本能猜測是從業務中的 byte[] 轉string的時候出現問題了。

找到對應程式碼如下,new string()時沒有指定字符集:

 

因此會在轉換過程中,預設讀取系統變數的file.encoding作為字符集。

 

 

 

然後我們用arthas直接檢視系統變數,果然不是utf8。

 

所以,解決方案有兩個。

第一種是在new string(bytes) 時指定字符集。

第二種就是設定系統變數file.encoding=utf-8。

 

6.進一步踩坑

我們一開始選擇了程式碼修復,在程式碼中轉換時指定字符集。

 

重新發布後,再用arthas觀察一下,發現竟然還是亂碼?!!

然後重新回頭在程式碼中看了很久,一直找不到原因,陷入了僵局。。。

 

突然,隨手看了下線上,發現線上已經顯示正常了,納尼?是arthas有問題?

然後google了一下,發現很多人碰到arthas顯示中文亂碼的問題。。。

解決方式也比較簡單,啟動arthas的時候,也指定一下字符集。

java -jar -Dfile.encoding=UTF-8 arthas-boot.jar

然後問題解決了。。。呵呵。。。

這時候再觀察arthas的結果已經顯示正常。

這說明了什麼?!!!!

Arthas輸出介面的時候,肯定在字串轉換的時候,也沒有指定字符集。。。。

一腳踩了個連環坑。。。

 

7.總結

其實整個問題是比較粗淺的,就是最後這個arthas的中文亂碼讓人有點腦殼疼。。。

當然,最主要還是簡單分享下tcpdump、arthas、simpleHTTPServer這些小工具,希望能有所幫助吧。

 

都看到最後了,原創不易,點個關注,點個贊吧~
文章持續更新,可以微信搜尋「阿丸筆記 」第一時間閱讀,回覆關鍵字【學習】有我準備的一線大廠面試資料。
知識碎片重新梳理,構建Java知識圖譜:github.com/saigu/JavaK…(歷史文章查閱非常方便)