在日常工作中我們經(jīng)常會(huì)遇到一些線上異常的情況唱蒸,而且有些問(wèn)題只有在線上才會(huì)出現(xiàn),由于環(huán)境和數(shù)據(jù)不一樣在本地和測(cè)試環(huán)境根本沒(méi)辦法復(fù)現(xiàn)灸叼,而且線上也沒(méi)有輸出日志神汹,那么遇到這種情況我們往往要怎么去解決呢?
常規(guī)做法
如果實(shí)在遇到上面的情況古今,在本地和測(cè)試都無(wú)法復(fù)現(xiàn)屁魏,那最常規(guī)的做法就是拉個(gè)線上分支的版本,增加一些調(diào)試日志捉腥,然后再重新發(fā)布版本進(jìn)行調(diào)試氓拼。運(yùn)氣好加一次日志就可以找到問(wèn)題,運(yùn)氣不好的話可能還要發(fā)布好幾次才能定位到問(wèn)題抵碟。
高級(jí)做法
下載安裝 arthas
Arthas 是阿里開(kāi)源的一款線上監(jiān)控診斷產(chǎn)品桃漾,通過(guò)全局視角實(shí)時(shí)查看應(yīng)用 load、內(nèi)存立磁、gc呈队、線程的狀態(tài)信息,并能在不修改應(yīng)用代碼的情況下唱歧,對(duì)業(yè)務(wù)問(wèn)題進(jìn)行診斷宪摧,包括查看方法調(diào)用的出入?yún)ⅰ惓B溃O(jiān)測(cè)方法執(zhí)行耗時(shí)几于,類加載信息等,大大提升線上問(wèn)題排查效率沿后。
上面的 Arthas 這款工具的官方介紹沿彭,從中我們可以看到這個(gè)工具可以查看方法的出入?yún)ⅲ惓R约氨O(jiān)測(cè)方法的耗時(shí)尖滚,我們排查問(wèn)題的時(shí)候最重要的就是想知道一些方法的入?yún)⒑头祷睾砹酰辛巳雲(yún)⒑头祷氐臄?shù)據(jù)我們就可以模擬出具體的場(chǎng)景從而解決線上的問(wèn)題瞧柔。
注意這里說(shuō)的方法不單單是外層的接口方法,任何 Service 層或者 RPC 層的方法都是可以的睦裳。之所以提出這一點(diǎn)是因?yàn)楹芏鄷r(shí)候線上的接口都會(huì)有請(qǐng)求和結(jié)果的日志記錄造锅,但是并沒(méi)有內(nèi)部某個(gè)具體方法的入?yún)⒑头祷兀ㄟ^(guò) Arthas 我們可以監(jiān)控任何方法的入?yún)⒑头祷刂怠?/p>
我們可以在
https://github.com/alibaba/arthas/releases 這個(gè)地址上下載具體的版本廉邑,下載下來(lái)就可以用哥蔚,沒(méi)什么難度。接下來(lái)阿粉通過(guò)一個(gè)案例來(lái)帶大家使用一下 Arthas蛛蒙。
測(cè)試
首先我們啟動(dòng)一個(gè) Spring Boot 應(yīng)用糙箍,并且對(duì)外一個(gè) http 的接口,具體的 Controller 和 Service 代碼實(shí)現(xiàn)如下牵祟。
package com.example.demo.controller;import com.example.demo.service.HelloService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController { @Autowired private HelloService helloService; @GetMapping(value = "/hello") public String hello(@RequestParam("name") String name) { return helloService.sayHello(name); }}
package com.example.demo.service;import org.springframework.stereotype.Service;@Servicepublic class HelloService { public String sayHello(String name) { String result = doSomething(name); return "hello: " + result; } private String doSomething(String name) { return name + " 歡迎關(guān)注 Java 極客技術(shù)"; }}
上面的代碼非常簡(jiǎn)單深夯,對(duì)外暴露了一個(gè) hello 接口,接收一個(gè) name 參數(shù)课舍,Service 中通過(guò) sayHello 方法塌西,調(diào)用了一個(gè)內(nèi)部的 doSomething 方法。其中過(guò)后我們?cè)L問(wèn)
http://127.0.0.1:8080/hello?name=ziyou 可以看到如下的內(nèi)容筝尾。
到這里都沒(méi)什么問(wèn)題捡需,但是我們想象一下,如果在某些 case doSomething 的方法比較復(fù)雜筹淫,我們想知道在執(zhí)行 doSomething 方法的時(shí)候具體的入?yún)⒑头祷刂凳鞘裁凑净裕@個(gè)時(shí)候我們要怎么辦呢?
當(dāng)然如果采用上面的常規(guī)做法损姜,增加一些日志饰剥,當(dāng)然是可以,不過(guò)我們這里就來(lái)演示一下如何使用 Arthas 來(lái)實(shí)現(xiàn)這個(gè)效果摧阅。前面我們已經(jīng)下載了 Arthas 了汰蓉,下載完成后是一個(gè)壓縮包,解壓過(guò)后棒卷,可以通過(guò)命令java -jar arthas-boot.jar 來(lái)啟動(dòng) Arthas顾孽。效果如下
可以看到啟動(dòng)過(guò)后 Arthas 會(huì)找到目前系統(tǒng)當(dāng)中在運(yùn)行的 Java 進(jìn)程,我這里有四個(gè)進(jìn)程比规,然后輸入我們要監(jiān)控的進(jìn)程編號(hào)若厚,這里是 4,然后回車蜒什,接下來(lái)我們就進(jìn)入了 Arthas 的界面测秸。
接下來(lái)我們使用 Arthas 的 watch 命令來(lái)監(jiān)控入?yún)⒑头祷刂担暾拿钊缦拢簑atch
com.example.demo.service.HelloService doSomething '{params,returnObj}
接下來(lái)我們?cè)偃ピL問(wèn)一下剛剛的接口,可以看到在終端上面有對(duì)應(yīng)的數(shù)據(jù)輸出霎冯。
簡(jiǎn)單解釋一下對(duì)應(yīng)的命令和輸出的信息铃拇,watch 是 Arthas 提供的命令,后面根據(jù)第一個(gè)參數(shù)是完整的類路徑肃晚,第二個(gè)參數(shù)是我們要監(jiān)控的方法名锚贱,第三個(gè)參數(shù)是一個(gè)表達(dá)是這里我們可以獲取入?yún)⒁约胺祷刂祷蛘弋惓5刃畔ⅲ瑢?duì)應(yīng)的取值有 params 數(shù)組形式关串,可以通過(guò) params[0] 來(lái)獲取對(duì)應(yīng)的屬性,returnObj 表示返回值监徘,并且這兩個(gè)都是可以通過(guò) .的形式晋修,獲取下面屬性的值的。
watch 命令后面的第三個(gè)參數(shù)其實(shí)是一個(gè) ognl 表達(dá)式凰盔,如下所示我們是可以做一些計(jì)算和邏輯處理的墓卦,這就帶來(lái)了很多高級(jí)的用法。Arthas的一些特殊用法文檔說(shuō)明
https://github.com/alibaba/arthas/issues/71
總結(jié)
Arthas 除了 watch 之外還有很多其他的命令可以使用户敬,比如 trace 可以統(tǒng)計(jì)每個(gè)方法執(zhí)行的耗時(shí)落剪,對(duì)于我們做一些性能優(yōu)化有很大的幫助,還有比如支持熱部署的功能等尿庐。完整的命令和使用方式大家可以在這個(gè)網(wǎng)址找到
https://arthas.aliyun.com/doc/忠怖,并且這里還提供了一套在線演示的功能,可以在在線教程中通過(guò)終端依次親手執(zhí)行每個(gè)命令來(lái)學(xué)習(xí)抄瑟。官方提供了一個(gè)應(yīng)用程序 math-game.jar 可以讓我們?cè)诰€調(diào)試凡泣,感興趣的小伙伴可以去試一試。