大家好,我是蘇三,又跟大家見面了。
前言
我經(jīng)歷過凌晨3點(diǎn)被報(bào)警叫醒的慌亂,也體會(huì)過定位難題的煎熬。
90%的線上問題都源于"三個(gè)不知道":不知道哪慢、不知道誰卡、不知道為何錯(cuò)。
這篇文章跟大家一起聊聊如何用Arthas快速定位線上問題,希望對(duì)你會(huì)有所幫助。
一、為什么常規(guī)工具在線上束手無策?
線上環(huán)境的三大特殊性:

傳統(tǒng)工具困局:
- 日志失效:未打印關(guān)鍵參數(shù),事后無法復(fù)現(xiàn)
- 監(jiān)控滯后:1分鐘顆粒度丟失瞬時(shí)異常
- JProfiler癱瘓:CPU飆高時(shí)根本打不開
Arthas的降維打擊優(yōu)勢(shì):
# 1秒接入生產(chǎn)環(huán)境
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar # 自動(dòng)識(shí)別Java進(jìn)程
二、五大問題定位場(chǎng)景
場(chǎng)景1:慢接口定位
現(xiàn)象:訂單查詢接口99%請(qǐng)求200ms,1%突增到5秒
傳統(tǒng)方案:
// 盲目加日志
log.info("查詢開始:{}", System.currentTimeMillis()); // 污染日志且低效
Arthas精準(zhǔn)打擊:
# 1. 追蹤方法內(nèi)部調(diào)用路徑
trace com.example.OrderService getOrderById '#cost>1000' -n 5
輸出火焰圖:

根因定位:風(fēng)控服務(wù)偶發(fā)TCP連接超時(shí)
解決方案:
# 調(diào)整連接超時(shí)時(shí)間
risk:
client:
connection-timeout: 500
read-timeout: 1000
場(chǎng)景2:線程阻塞之謎
現(xiàn)象:支付回調(diào)接口凌晨卡死
傳統(tǒng)方案:
jstack > thread.log # 但阻塞已結(jié)束
Arthas破局:
# 1. 查看線程狀態(tài)分布
thread -b # 顯示阻塞線程
# 2. 監(jiān)控鎖競(jìng)爭(zhēng)情況
watch java.util.concurrent.locks.ReentrantLock getQueueLength
輸出診斷報(bào)告:

根因定位:Logback同步寫日志阻塞業(yè)務(wù)線程
解決方案:
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>1024</queueSize>
<appender-ref ref="FILE"/>
</appender>
場(chǎng)景3:內(nèi)存泄漏精準(zhǔn)捕獲
現(xiàn)象:容器每天重啟一次
傳統(tǒng)方案:
jmap -histo:live pid # 觸發(fā)Full GC破壞現(xiàn)場(chǎng)
Arthas神操作:
# 1. 監(jiān)控堆內(nèi)存對(duì)象
dashboard -i 5000 # 5秒刷新一次
# 2. 追蹤對(duì)象創(chuàng)建路徑
vmtool --action getInstances --className LoginDTO --limit 10
發(fā)現(xiàn)異常:
[LoginDTO] instances: 245,680 (增長(zhǎng)0.5%/min)
源碼定位:
// 錯(cuò)誤代碼:ThreadLocal未清理
public class UserHolder {
private static ThreadLocal<LoginDTO> cache = new ThreadLocal<>();
public static void set(LoginDTO dto) {
cache.set(dto); // 線程復(fù)用導(dǎo)致堆積
}
}
解決方案:
try {
// 業(yè)務(wù)代碼
} finally {
UserHolder.remove(); // 強(qiáng)制清理
}
場(chǎng)景4:熱修復(fù)代碼拯救崩潰
現(xiàn)象:新上線分頁查詢OOM,回滾需1小時(shí)
傳統(tǒng)方案:
Arthas力挽狂瀾:
# 1. 反編譯問題方法
jad com.example.UserService listUsers
# 2. 修改本地文件
vi UserService.java # 修復(fù)內(nèi)存泄漏代碼
# 3. 熱更新類
redefine -c 327a3b4 /tmp/UserService.class
熱更新原理:

場(chǎng)景5:數(shù)據(jù)不一致玄學(xué)案
現(xiàn)象:訂單狀態(tài)顯示已支付,但數(shù)據(jù)庫未更新
Arthas破案:
# 1. 監(jiān)控方法入?yún)?返回值
watch com.service.OrderService updateStatus
"{params,returnObj}" -x 3
# 2. 觀察調(diào)用鏈路
stack com.service.OrderService updateStatus
捕獲異常調(diào)用鏈:
updateStatus(OrderStatus.PAID) // 正確調(diào)用
|- 線程1:支付回調(diào)
updateStatus(OrderStatus.CREATED) // 異常調(diào)用
|- 線程2:訂單查詢補(bǔ)償任務(wù)
根因定位:補(bǔ)償任務(wù)錯(cuò)誤覆蓋狀態(tài)
解決方案:
// 增加狀態(tài)機(jī)校驗(yàn)
if (currentStatus != CREATED) {
throw new IllegalStateException("狀態(tài)禁止回退");
}
三、Arthas底層原理揭秘
為什么能無侵入診斷?

關(guān)鍵技術(shù)突破:
- Attach機(jī)制:通過
VirtualMachine.attach注入Agent - 字節(jié)碼織入:利用ASM修改方法體添加監(jiān)控邏輯
- 類隔離:自定義ClassLoader防止污染業(yè)務(wù)代碼
診斷命令執(zhí)行流程:

四、Arthas高級(jí)組合技能
性能分析黃金組合:
# 1. 宏觀概覽
dashboard -i 5000
# 2. 定位CPU熱點(diǎn)
profiler start # 開始采樣
profiler stop --format html # 生成火焰圖
# 3. 追蹤慢方法
trace *StringUtils substring '#cost>100'
復(fù)雜問題排查框架:

五、避坑指南
必須遵守的三條軍規(guī):
# 錯(cuò)誤示范:監(jiān)控所有方法
watch * *
# 正確操作:精準(zhǔn)定位
watch com.example.service.* *
# 禁止生產(chǎn)環(huán)境執(zhí)行高危操作
reset * # 清除增強(qiáng)類
stop # 關(guān)閉Arthas
# 限制內(nèi)存占用
options save-result false
options batch-size 50
總結(jié)
Arthas能力矩陣:
| 問題類型 | 核心命令 | 效果 |
|---|
| trace | |
| thread | |
| heapdump | |
| jad | |
架構(gòu)師的三層境界:
- 看本質(zhì):線程阻塞→優(yōu)化鎖(進(jìn)階)
真正的高手不是解決問題,而是讓問題無處遁形。
當(dāng)你握緊Arthas這把手術(shù)刀,每一次線上危機(jī)都是展示技術(shù)深度的舞臺(tái)。