JMH + Arthas 性能監(jiān)控

為了能夠讓實例能夠貫穿這兩個工具的使用,首先簡單描述下在開發(fā)中遇到的實際的性能問題。然后再引出這兩個性能工具的實際使用,看如何使用這兩個工具成功定位到性能瓶頸的。

問題如下:為了能夠支持丟失率,我們將原先log4j2 的Async+自定義Appender的方式進(jìn)行了修正,把異步的邏輯放到了自己改版后的Appender中。但我們發(fā)現(xiàn)修改后日志性能要比之前Async+自定義Appender的方式下降不少。這里由于隱私原因我并沒有用實際公司中的實例,這里我用了一種其他同樣能夠體現(xiàn)問題的方式。我們暫時先不給出具體的配置文件,先給出性能測試代碼和結(jié)果

代碼邏輯及其簡單,就是調(diào)用logger.info每次打印10000條日志,然后記錄耗時。兩者的對比如下

從這兩張圖片中我們能夠看到同樣的邏輯,兩個程序的耗時差距相差了數(shù)十倍,但看圖片,貌似僅僅是logger的名稱不一樣。對上面的實驗結(jié)果進(jìn)行分析,我們可能會有兩個疑問

上面的代碼測試是否標(biāo)準(zhǔn),規(guī)范

如果真的是性能問題,那么這兩個代碼到底在哪個方法上有了這么大的差距導(dǎo)致了最終的性能差異

下面這兩個工具就分別來回答這兩個問題

JMH簡介

第一個問題就是,測試的方法是否標(biāo)準(zhǔn)。我們在編寫代碼時用的是死循環(huán)+前后“掐秒表”的方式。假如我們要再加個多線程的測試,我們還需要搞一個線程池,除了代碼本身的邏輯還要關(guān)心測試的邏輯。我們會想,有沒有一款工具能夠?qū)⑽覀儚臏y試邏輯中徹底解放出來,只需要關(guān)心我們需要測試的代碼邏輯。JMH就是這樣一款Java的測試框架。下面是JMH的官方定義

這里面我們需要注意的是,JMH所測試的方法約簡單越好,依賴越少越好,最適合的場景就是,測試兩個集合put,get性能,例如ArrayList與LinkedList的對比等,這里我們需要測試的是批量打一批日志所需要的時間,也基本符合使用JMH的測試場景。下面是測試代碼,bench框架代碼以及主函數(shù)。

待測試方法

可以看到待測試方法非常簡單,就是單批次一次性打印10000條日志的操作,所以并沒有需要額外說明的部分。下面我們再來看benchmark部分。

在這段代碼中,我們就會發(fā)現(xiàn)有了一些JMH中特有的東西,我下面進(jìn)行簡要介紹。

在上面的代碼中,我定義了4個待測試的方法,方法的Fork,BenchmarkMode均為測試單次OPS的平均時間,但4個方法的線程數(shù)不同。除了這幾個參數(shù),還有幾個參數(shù),我會在main函數(shù)里面來講,main代碼如下所示

我們可以看到,在main函數(shù)中,我們就是要設(shè)置JMH的基礎(chǔ)配置,這里面的幾個配置參數(shù)含義如下:

我分別用兩種logger運行一下測試,查看性能測試報告對比

使用普通logger

使用了INCLUDE_LOCATION的logger

這里我們看到,性能差距立現(xiàn)。使用INCLUDE_LOCATION的性能要明顯低于使用普通logger的性能。這是我們一定很好奇,并且問一句“到底慢在哪”?。?/p>

Arthas 我的代碼在運行時到底做了什么

Arthas是阿里開源的一款java調(diào)試神器,與greys類似,不過有著比greys更加強(qiáng)大的功能,例如,可以直接繪制java方法調(diào)用的火焰圖等。這兩個工具的原理都是使用了Java強(qiáng)大的字節(jié)碼技術(shù)。畢竟我也不是JVM大佬,所以具體的實現(xiàn)細(xì)節(jié)沒法展開,我們要做的就是站在巨人的肩膀上,接受并用熟練的使用好這些好用的性能監(jiān)控工具。

實際操作

talk is cheap, show me your code,既然是工具,我們直接進(jìn)行實際操作。我們在本機(jī)運行我們一開始的程序,然后講解arthas的使用方法。

我們首先通過jps找到程序的進(jìn)程號,然后直接通過arthas給到的as.sh對我們運行的程序進(jìn)行字節(jié)碼增強(qiáng),然后啟動arthas,命令如下

可以看到,arthas支持查看當(dāng)前jvm的狀態(tài),查看當(dāng)前的線程狀態(tài),監(jiān)控某些方法的調(diào)用時間,trace,profile生成火焰圖等,功能一應(yīng)俱全 我們這里也只將幾個比較常用的命令,其他的命令如果大家感興趣可以詳見官網(wǎng)arthas官網(wǎng)。這篇文章主要介紹下面幾個功能

1,反編譯代碼

2,監(jiān)控某個方法的調(diào)用

3,查看某個方法的調(diào)用和返回值

4,trace某個方法

監(jiān)控方法調(diào)用

這個主要的命令為monitor,根據(jù)官網(wǎng)的介紹,常用的使用方法為

其中duration代表每隔幾秒展示一次統(tǒng)計結(jié)果,即單次的統(tǒng)計周期,className就是類的全限定名,methodname就是方法的名字,這里面我們查看的方法是Logger類的info方法,我們分別對使用兩種不同logger的info方法。這里面的類是org.slf4j.Logger,方法時info,我們的監(jiān)控語句為

監(jiān)控結(jié)果如下

使用普通appender

我們可以看到,使用include appeder的打印日志方法要比普通的appender高出了3倍,這就不禁讓我們有了疑問,究竟這兩個方法各個步驟耗時如何呢。下面我們就介紹第二條命令,trace方法。

trace命令 & jad命令

這兩個程序的log4j2配置文件如下




我們都是用了一個AsyncAppender套用了一個FileAppender。查看fileAppender,發(fā)現(xiàn)二者相同完全沒區(qū)別,只有asyncAppender中的一個選項有區(qū)別,這就是includeLocation,一個是false,另一個是true。至于這個參數(shù)的含義,我們暫時不討論,我們現(xiàn)在知道問題可能出在AsyncAppender里面,但是我們該如何驗證呢。trace命令就有了大用場。

trace命令的基本用法與monitor類似,其中主要的一個參數(shù)是-n則是代表trace多少次的意思

我在之前Log4j2的相關(guān)博客里面講到過,任何一個appender,最核心的方法就是他的append方法。所以我們分別trace兩個程序的append方法。

trace結(jié)果如下

使用普通appender

我們立刻可以發(fā)現(xiàn),兩個trace的熱點方法不一樣,在使用include的appender中,耗時最長的方法時org.apache.logging.log4j.core.impl.Log4jLogEvent類中的createMemento方法,那么怎么才能知道這個方法到底做了啥呢,那就請出我們下一個常用命令jad,這個命令能夠反編譯出對應(yīng)方法的代碼。這里我們jad一下上面說的那個createMemento方法,命令很簡單

結(jié)果如下

watch命令

watch命令能夠觀察到某個特定方法的入?yún)ⅲ祷刂档刃畔?,我們使用這個命令查看一下這個createMemento方法的入?yún)ⅲ绻麅蓚€程序的入?yún)⒉煌?,那基本可以斷定是這個原因引起命令如下

這里面的參數(shù)含義如下

-x?參數(shù)展開層次

-n?執(zhí)行次數(shù)

-b?查看方法調(diào)用前狀態(tài)

-f?方法調(diào)用后

其中的param代表查看方法的調(diào)用參數(shù)列表,還有其他的監(jiān)控項詳見官網(wǎng)官網(wǎng)

最終watch結(jié)果如下

使用普通logger

果不其然,這兩個參數(shù)果然是一個true一個false,我們簡單看下這個參數(shù)是如何傳進(jìn)來的,我們jad一下AsyncAppender的append方法

不過為了一探究竟,我還是靜態(tài)跟了一下這段代碼

這個includeLocation會在event的createMemento中被用到,在序列化生成對象時會創(chuàng)建一個LogEventProxy,代碼如下

如果includeLocation為true,那么就會調(diào)用getSource函數(shù),跟進(jìn)去查看,代碼如下

我們看到他會從整個的調(diào)用棧中去尋找調(diào)用這個方法的代碼行,其性能可想而知。我們用arthas監(jiān)控一下,驗證一下。

首先我們trace crateMemento方法

至此通過結(jié)合JMH和arthas共同定位出了一個線上的性能問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容