記一次線上機器CPU飆高的排查過程

? ? ? ? 公司如今把小貸機器都整理回收了祟昭,訪問量不大,基本都是用戶來查看賬戶進行還款操作。

? ? ? ? 現在情況是冈钦,我們把很多服務都放在了一臺服務器上,那天線上環(huán)境改了auth的salt李请,本地這邊是寫死的瞧筛,自動上線已經關閉了通道,沒轍导盅,手動替包手動上線较幌,結果沒多久運維就喊了,表示cpu飆高到300%白翻。

? ? ? ? 難得的機會乍炉,先用top找出cpu占用最多進程

ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head

如果想細看進程信息可以使用ll proc

其實運行完這里的時候,我比較吃驚的是滤馍,真正占CPU的并不是部署的幾個服務岛琼,而是resin容器本身,飚到了99%巢株,從這個角度來講槐瑞,其實大部分性能問題都是垃圾回收的鍋。

然后利用ps查看到的進程pid找cpu最高線程

top -H -p [pid]

然后拿著線程tid在jstack找阁苞,結果在里面找不到随珠,然后上網查JAVA線程無法在jstack里找到的原因

Java thread has no Java stack trace, when

The thread is about to start, and is running pre-start initialization or JVM TI ThreadStart handler.

The thread is about to terminate, and is running post-exit cleanup or JVM TI ThreadEnd handler.

The thread is a JVM TI agent thread, which is running native code.

To find out what these threads are doing, it's not enough to get Java stack trace - you'd need to get native stack traces as well.

On JDK 8 run

jstack -m <pid>

On JDK 11 and later

jhsdb jstack --mixed --pid <pid>

以上大概意思是沒找到線程的跟蹤棧有三種情況灭袁,就是線程啟動前的預啟動,以及線程退出后的cleanup窗看,第三種就是茸歧,利用JVM TI agent運行的線程,這個線程是用來跑本地code的显沈。

******這里面都提到了JVM TI技術软瞎,這個技術主要是用來提供虛擬機調用本地方法的接口,可以獲取jvm運行情況和提供本地方法的后門一樣的接口工具拉讯,一些調試和診斷工具都是基于JVM TI來實現的涤浇,很多JVM都有自己的TI實現。

當然魔慷,這個Stack Over Flow的答案針對的Java線程只锭,我所知道的是,如果導致我們CPU飆高的并不是java線程院尔,那么jstack -F就打不出來蜻展。

而這個jstack -m模式,在官方文檔里是說邀摆,可以打印出所有Java線程和native frames的所有線程纵顾。其實到這里是不是隱隱感覺到什么了~~沒錯,最后真的是垃圾回收的鍋栋盹。

然后jdk8利用jstack -m找到了施逾,發(fā)現里面使用的方法是CMS垃圾回收器的方法

0x00007f0958095152 _ZNK24CompactibleFreeListSpace12block_is_objEPK8HeapWord + 0x32

0x00007f0958099554 _ZN24CompactibleFreeListSpace22prepare_for_compactionEP12CompactPoint + 0xf4

0x00007f09582063ef _ZN10Generation22prepare_for_compactionEP12CompactPoint + 0x2f

0x00007f09581f5d15 _ZN16GenCollectedHeap22prepare_for_compactionEv + 0x45

0x00007f09581f94ca _ZN12GenMarkSweep19invoke_at_safepointEiP18ReferenceProcessorb + 0x20a

0x00007f09580f2249 _ZN12CMSCollector18do_compaction_workEb + 0x229

0x00007f09580f266c _ZN12CMSCollector27acquire_control_and_collectEbb + 0x14c

0x00007f09580f2a4e _ZN29ConcurrentMarkSweepGeneration7collectEbbmb + 0x8e

0x00007f09581f80ba _ZN16GenCollectedHeap13do_collectionEbbmbi + 0x54a

0x00007f09581f88a7 _ZN16GenCollectedHeap18do_full_collectionEbi + 0x47

0x00007f09580902d4 _ZN13CollectedHeap20collect_as_vm_threadEN7GCCause5CauseE + 0x114

0x00007f09586d54b1 _ZN31VM_CollectForMetadataAllocation4doitEv + 0x161

0x00007f09586dd535 _ZN12VM_Operation8evaluateEv + 0x55

0x00007f09586db90a _ZN8VMThread18evaluate_operationEP12VM_Operation + 0xba

0x00007f09586dbc8e _ZN8VMThread4loopEv + 0x1ce

0x00007f09586dc100 _ZN8VMThread3runEv + 0x70

0x00007f0958533268 _ZL10java_startP6Thread + 0x108


講真,平時只負責上下線例获,JVM配置只要不出問題很少留意汉额,這個年代了,還在使用CMS嗎榨汤?嗯蠕搜,jmap看了下,是CMS件余。而占用大多CPU也是CMS的特性之一:最小化GC中斷讥脐,付出的代價便是高CPU負荷。

既然定位到了垃圾回收啼器,那就接著排查垃圾回收吧旬渠,pid是18637

就去jstat -gc 18637 5000


圖1

jstat -gcold 18637

jstat -gcoldcapacity 18637

發(fā)現full gc非常頻繁(每五秒輸出,發(fā)現觸發(fā)fullGC13次)

(復盤這次的排查問題端壳,發(fā)現圖片保存少之又少告丢。。)

如此頻繁损谦,順帶gccause一下看看最近一次回收的原因

jstat -gccause 18637

結果長這樣


圖2

從這個結果來看最近一次是Metadata的GC岖免,而觸發(fā)原因是因為達到了閾值岳颇。再細看當前元空間使用率已經接近98%。

到這里不能等了颅湘,找運維拿來了jvm參數话侧,有三個參數很亮眼

-XX:MaxMetaspaceSize=128M

-XX:MetaspaceSize=128M

-XX:CMSInitiatingOccupancyFraction=80

老年代的配置屬于默認配置,占整個堆內存的2/3闯参,CMS回收要達到80%才會觸發(fā)瞻鹏,我們還沒有達到這個值。

那么根據圖1中的顯示鹿寨,metaspace我們已經達到了閾值新博。

這種情況產生也沒毛病,想想一臺機器部署了5個web服務和5個微服務的場景吧脚草,雖然沒什么人訪問赫悄,但加載的class信息也足夠多了。

主要就是metadata的配置馏慨,而有關metadata的配置并沒有oracle的官方指導埂淮,官方指導上的意思是說metaspace的配置,主要是避免首次啟動時對加載的類信息做回收熏纯,取決于應用本身同诫,夠用就行了粤策,不要太頻繁觸發(fā)full gc就好

Specify a higher value for the option -XX:MetaspaceSize to avoid early garbage collections induced for class metadata. The amount of class metadata allocated for an application is application-dependent and general guidelines do not exist for the selection of -XX:MetaspaceSize. The default size of -XX:MetaspaceSize is platform-dependent and ranges from 12 MB to about 20 MB.

其實調大這metaspace的配置能夠大概解決問題樟澜,但是最終我選擇了切換為G1垃圾回收。

官方文檔是這樣寫的

Applications running today with either the CMS or the ParallelOld garbage collector would benefit switching to G1 if the application has one or more of the following traits.

More than 50% of the Java heap is occupied with live data.The rate of object allocation rate or promotion varies significantly.Undesired long garbage collection or compaction pauses (longer than 0.5 to 1 second)

G1 is planned as the long term replacement for the Concurrent Mark-Sweep Collector (CMS).

? ? ? ? 首先戳我的點的主要原因是g1最終的目的是要取代cms垃圾回收器叮盘,它的回收范圍是整個堆秩贰,緊跟潮流總不會錯的。其次g1取代cms的情況官方也建議了以下幾點:

1. 一個是要管理的堆內存大于6g

2. 一個是服務已使用的堆內存超過了50%

3. 一個是對象分配率過高或對象從新生代晉升到老年代速率過快(這里我查了一下資料柔吼,意思是對象分配率過高的話其實會導致Minor GC頻繁毒费,而這種情況會使對象更快地晉升到老年代,而老年代如果過快地被填充愈魏,又會觸發(fā)FullGC觅玻。從設計角度來講,之所以分代回收培漏,是為了應對對象存活時間而使用不同的回收策略溪厘,老年代可不是為了頻繁回收而產生的)

4. 垃圾回收導致服務中斷時長超過0.5-1s。

這種時候官方就建議把cms換成g1了牌柄。

? ? ? ? 最終cpu驟降畸悬,從99%降至一般運行狀態(tài)下的2%左右。好了珊佣。就這樣吧蹋宦,雖然不希望線上出現這種問題披粟,但一旦出問題了,搞一遍還蠻帶感的冷冗。期待下一次的摸排:DDDDD


后記:

? ? ? ? 最近在復盤這次垃圾回收守屉,因為這次jvm排查的經歷讓我對垃圾回收機制和分代回收這一塊加深了印象。復盤的時候發(fā)現自己思考地還欠缺深入蒿辙。這次的問題有兩個地方值得深思胸梆,一個是為什么metaspace會超?如果正常進行GC须板,為何會超出閾值碰镜?其次是沒有調大metaspace的前提下,換成G1為什么就沒有再頻繁FullGC過习瑰?

? ? ? ? 為什么metaspace會超绪颖,我經過比對當時留下CMS的jstat數據和G1當前的數據,發(fā)現新生代CMS劃分區(qū)域非常大甜奄,是現在G1的十倍柠横。G1是不建議設定新老年代比例的,這樣它就可以動態(tài)調整新老年代比例课兄,達到最優(yōu)實踐牍氛。首先說明metaspace是存儲類描述信息的,當堆上分配了對象烟阐,就會關聯到metaspace里面的類信息搬俊,如果堆上的對象不回收,那么metaspace里面的類信息也不會回收蜒茄。

? ? ? ? 在配置cms時唉擂,我們會設置新生代老年代比例,新生代空間是固定的檀葛,如果新生代的空間比較大玩祟,回收間隔時間長,那就會導致metaspace里的class信息無法被釋放屿聋,最終導致未進行youngGC而率先因為metaspace超了跑了FullGC空扎。但G1的新生代空間是根據使用情況動態(tài)分配的,它的算法會去回收最有回收價值的region润讥。

? ? ? ? 就這次修改參數而言转锈,使用G1比CMS時間短很多,就已經執(zhí)行了717次youngGC象对,而CMS用了那么久黑忱,才52次,側面也能佐證這個猜測的正確性,解釋了為何在相同metaspace的配置下甫煞,G1沒有產生頻繁FullGC的原因:新生代對象回收加快菇曲,metaspace空間得到了盡快釋放,沒有達到閾值抚吠,于是不會觸發(fā)FullGC常潮。


參考文獻:

* https://www.oracle.com/java/technologies/javase/hotspot-garbage-collection.html

* https://www.oracle.com/java/technologies/javase/gc-tuning-6.html

* https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/sizing.html

* https://plumbr.io/blog/garbage-collection/what-is-allocation-rate

* https://plumbr.io/blog/garbage-collection/what-is-promotion-rate

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市楷力,隨后出現的幾起案子,更是在濱河造成了極大的恐慌岔留,老刑警劉巖检柬,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件何址,死亡現場離奇詭異,居然都是意外死亡原押,警方通過查閱死者的電腦和手機偎血,發(fā)現死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門烁巫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亚隙,“玉大人违崇,你說我怎么就攤上這事羞延。” “怎么了伴箩?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長棺蛛。 經常有香客問我,道長桦踊,這世上最難降的妖魔是什么终畅? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮离福,結果婚禮上,老公的妹妹穿的比我還像新娘本刽。我一直安慰自己子寓,他們只是感情好笋除,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布垃它。 她就那樣靜靜地躺著国拇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪也殖。 梳的紋絲不亂的頭發(fā)上忆嗜,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天崎岂,我揣著相機與錄音冲甘,去河邊找鬼绩卤。 笑死途样,一個胖子當著我的面吹牛,可吹牛的內容都是我干的濒憋。 我是一名探鬼主播娘纷,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跋炕,長吁一口氣:“原來是場噩夢啊……” “哼赖晶!你這毒婦竟也來了辐烂?” 一聲冷哼從身側響起遏插,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纠修,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體扣草,經...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡了牛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年辰妙,在試婚紗的時候發(fā)現自己被綠了鹰祸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖尔破,靈堂內的尸體忽然破棺而出餐济,到底是詐尸還是另有隱情胆剧,我是刑警寧澤絮姆,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站前域,受9級特大地震影響,放射性物質發(fā)生泄漏韵吨。R本人自食惡果不足惜匿垄,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧椿疗,春花似錦漏峰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铝条,卻和暖如春靖苇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背班缰。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工贤壁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人埠忘。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓脾拆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親莹妒。 傳聞我的和親對象是個殘疾皇子名船,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內容