Java診斷利器Arthas優雅排查生產環境

arthas

前言

Arthas 是Alibaba開源的Java診斷工具。在線排查問題,無需重啓;動態跟蹤Java代碼;實時監控JVM狀態。對分秒必爭的線上異常,Arthas可幫助咱們快速診斷相關問題。java

下載安裝

下載Arthasarthas-boot.jargit

wget https://alibaba.github.io/arthas/arthas-boot.jar

下載arthas以後,先來了解幫助信息,能夠經過java -jar arthas-boot.jar -h命令查看,這裏給出了一些例子和參數說明github

[root@izwz94a0v1sz0gk4rezdcbz arthas]# java -jar arthas-boot.jar -h
[INFO] arthas-boot version: 3.1.4
Usage: arthas-boot [-h] [--target-ip <value>] [--telnet-port <value>]
       [--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
       [--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
       [--attach-only] [-c <value>] [-f <value>] [--height <value>] [--width
       <value>] [-v] [--tunnel-server <value>] [--agent-id <value>] [--stat-url
       <value>] [pid]

Bootstrap Arthas

EXAMPLES:
  java -jar arthas-boot.jar <pid>
  java -jar arthas-boot.jar --target-ip 0.0.0.0
  java -jar arthas-boot.jar --telnet-port 9999 --http-port -1
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
  java -jar arthas-boot.jar --tunnel-server 'ws://192.168.10.11:7777/ws'
--agent-id bvDOe8XbTM2pQWjF4cfw
  java -jar arthas-boot.jar --stat-url 'http://192.168.10.11:8080/api/stat'
  java -jar arthas-boot.jar -c 'sysprop; thread' <pid>
  java -jar arthas-boot.jar -f batch.as <pid>
  java -jar arthas-boot.jar --use-version 3.1.4
  java -jar arthas-boot.jar --versions
  java -jar arthas-boot.jar --session-timeout 3600
  java -jar arthas-boot.jar --attach-only
  java -jar arthas-boot.jar --repo-mirror aliyun --use-http
WIKI:
  https://alibaba.github.io/arthas

Options and Arguments:
 -h,--help                      Print usage
    --target-ip <value>         The target jvm listen ip, default 127.0.0.1
    --telnet-port <value>       The target jvm listen telnet port, default 3658
    --http-port <value>         The target jvm listen http port, default 8563
    --session-timeout <value>   The session timeout seconds, default 1800
                                (30min)
    --arthas-home <value>       The arthas home
    --use-version <value>       Use special version arthas
    --repo-mirror <value>       Use special maven repository mirror, value is
                                center/aliyun or http repo url.
    --versions                  List local and remote arthas versions
    --use-http                  Enforce use http to download, default use https
    --attach-only               Attach target process only, do not connect
 -c,--command <value>           Command to execute, multiple commands separated
                                by ;
 -f,--batch-file <value>        The batch file to execute
    --height <value>            arthas-client terminal height
    --width <value>             arthas-client terminal width
 -v,--verbose                   Verbose, print debug info.
    --tunnel-server <value>     The tunnel server url
    --agent-id <value>          The agent id register to tunnel server
    --stat-url <value>          The report stat url
 <pid>                          Target pid

啓動

啓動arthas以前,先啓動一個springboot的應用。該demo在地址https://github.com/yangtao...正則表達式

java -jar ytao-springboot-demo.jar

啓動arthas-boot.jar命令spring

java -jar arthas-boot.jar

這裏注意須要啓動demoarthas使用同一權限用戶,不然使用attach機制獲取不到進程信息(這裏剛使用時沒注意,遇到過這個問題)。
例:root用戶啓動 demou1用戶啓動arthas時,打印信息Can not find java process. Try to pass <pid> in command line.express

使用另外一user啓動

查看源碼,在獲取進程以後,添加日誌輸出。結果爲空,返回-1,判斷結果小於0時,直接退出。api

日誌輸出

啓動類Bootstrap#main的代碼springboot

Bootstrap#main

進程工具類ProcessUtils#select的代碼bash

ProcessUtils#select

經過上面也分析到,咱們啓動arthas以前,必需要先啓動咱們的目標進程,不然arthas可能沒法啓動。session

使用root用戶啓動成功界面

arthas啓動成功

選擇java進程,這裏咱們的ytao-springboot-demo是 1,選擇後會有鏈接信息

[INFO] arthas home: /root/.arthas/lib/3.1.4/arthas
[INFO] Try to attach process 22005
[INFO] Attach process 22005 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                                

wiki      https://alibaba.github.io/arthas                                      
tutorials https://alibaba.github.io/arthas/arthas-tutorials                     
version   3.1.4                                                                 
pid       17339  
time      2019-10-17 02:29:06

dashboard 數據面板

使用dashboard命令,能夠查看線程,內存,GC,以及Runtime信息
dashboard

jad 反編譯

有時咱們會遇到線上代碼運行結果不是咱們指望的結果,有種狀況就是線上代碼不是咱們想要的版本,可是要查看的話,須要下載後再進行反編譯。
這時arthasjad能夠幫助咱們線上進行即時反編譯,確認代碼是否符合咱們的版本。

jad com.ytao.service.UserServiceImpl

jad反編譯

watch 函數執行信息

使用watch命令能夠查看函數的執行信息。watch的參數列表(來自官網)

參數 參數說明
class-pattern 類名錶達式匹配
method-pattern 方法名錶達式匹配
express 觀察表達式
condition-express 條件表達式
[b] 在方法調用以前觀察
[e] 在方法異常以後觀察
[s] 在方法返回以後觀察
[f] 在方法結束以後(正常返回和異常返回)觀察
[E] 開啓正則表達式匹配,默認爲通配符匹配
[x:] 指定輸出結果的屬性遍歷深度,默認爲 1

當咱們遇到線上數據bug時,咱們通常處理的手段就是開發環境模擬線上數據,從生產日誌中查找線索,再或者遠程debug。以上無論哪一種排查手段,相對都是比較麻煩。
這時Arthas的watch能夠幫助咱們查看實時的代碼執行狀況。使用觀察表達式能夠查看函數的參數,返回值,異常信息。觀察表達式主要由OGNL表達式組成,因此能夠編寫OGNL表達式來執行。

觀察表達式的變量

變量 變量說明
params 函數的入參
returnObj 函數的返回值
throwExp 異常信息
target 當前對象

查看一個函數的入參和返回值

watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}"

watch命令的參數和返回值信息

打印信息isEmpty=false;size=1能夠看到參數爲非空,參數數量爲一個。查看具體入參信息

watch com.ytao.service.UserServiceImpl getUser "{params[0],returnObj}"

watch命令的具體的入參信息

查看異常信息

watch com.ytao.service.UserServiceImpl getUser "throwExp"

當咱們傳入一個參數爲-1時,打印出咱們定義的非法參數異常
watch查看異常信息

watch除了觀察表達式外,還能使用條件表達式,以及觀察事件點
注意使用觀察事件點時,有些觀察表達式的變量不必定存在,好比使用-b時,返回值和異常信息都爲空。
watch的-b參數

有時咱們排查某個函數,不能立刻獲取到函數的信息,arthas給提供的後臺異步任務能夠幫助咱們記錄日誌。使用方式和Linux的相似。

watch com.ytao.service.UserServiceImpl getUser "{params,returnObj}" > /log/w.log &

查看異步保存的日誌
日誌

tt 定位異常調用

上面所介紹的watch能夠排查函數的調用狀況,比較適用在已知當次調用可能存在的狀況後,查看信息。若是一個函數調用n次後,有幾回爲執行異常,咱們要去找出這些異常的調用,在watch中排查就不怎麼方便了。
使用tt命令能夠較方便查看異常的調用及信息。對com.ytao.service.UserServiceImpl#getUser的函數查看,-t是每次調用該函數都會記錄

tt -t com.ytao.service.UserServiceImpl getUser

記錄信息
tt信息輸出

查看全部記錄

tt -l

查看指定函數記錄

tt -s 'method.name=="getUser"'

輸出信息說明

表格字段 字段解釋
INDEX 時間片斷記錄編號,每個編號表明着一次調用,後續tt還有不少命令都是基於此編號指定記錄操做,很是重要。
TIMESTAMP 方法執行的本機時間,記錄了這個時間片斷所發生的本機時間
COST(ms) 方法執行的耗時
IS-RET 方法是否以正常返回的形式結束
IS-EXP 方法是否以拋異常的形式結束
OBJECT 執行對象的hashCode(),注意,曾經有人誤認爲是對象在JVM中的內存地址,但很遺憾他不是。但他能幫助你簡單的標記當前執行方法的類實體
CLASS 執行的類名
METHOD 執行的方法名

從上面參數中咱們看到1003調用是以拋異常的形式結束,由於tt會記錄每次調用的信息,因此咱們能夠查看1003的詳細信息

tt -i 1003

tt調用詳細

trace 查看調用鏈路

咱們常會遇到調用某個api時rt過長,咱們就要找出調用鏈上的某個或幾個函數進行優化,咱們一般定位幾個可能的錨點,打印各個錨點間的rt。或者從日誌中找出日誌打印的時間點計算出時間差,無論使用哪一種方法都比較繁瑣。當使用arthastrace命令能夠輕鬆的完成咱們的需求。
trace參數說明

參數 參數說明
class-pattern 類名錶達式匹配
method-pattern 方法名錶達式匹配
condition-express 條件表達式
[E] 開啓正則表達式匹配,默認爲通配符匹配
[n:] 命令執行次數
#cost 方法執行耗時

使用trace輸出com.ytao.controller.UserController#getUser的信息

trace com.ytao.service.UserServiceImpl getUser

輸出結果
trace輸出信息

在實際使用使用排查過程當中,爲了減小無用信息的輸出,咱們通常會使用#cost過濾耗時不長和jdk自帶的函數,能夠忽略的調用,減小信息的輸出。例如:過濾掉小於1ms的調用

trace com.ytao.service.UserServiceImpl getUser  '#cost > 1'

redefine 實現熱部署

當咱們查找出bug,想要快速上線拯救蒼生的時候,Arthas爲咱們準備了redefine命令來實現熱更新。
儘管如今都在倡導jad/mc/redefine熱更一條龍,可是線上代碼建議本地編譯好後再進行替換,避免手誤操做。
首先先在UserServiceImpl中添加一行代碼
新增代碼

獲取classLoaderHash,經過sc命令獲取類的信息

sc -d *UserServiceImpl

classLoaderHash

執行redefine修改的類

redefine -c 1d56ce6a /usr/local/jar/UserServiceImpl.class

經過打印的信息驗證是否更新UserServiceImpl

Arthas的使用,除了上文中所講解到的,還有一些其餘的診斷功能,這只是我我的使用的方法。可是使用該類工具必定要有套組合拳,對排查問題過程當中,遇到問題有對應的排查手段,並不是盲目排查。




我的博客: https://ytao.top
個人公衆號 ytao
個人公衆號

相關文章
相關標籤/搜索