www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]每日雞湯,好喝 01 案發(fā)現(xiàn)場 通常來說,一個(gè)系統(tǒng)在上線之前應(yīng)該經(jīng)過多輪的調(diào)試,在測試服務(wù)器上穩(wěn)定的運(yùn)行過一段時(shí)間。我們知道 Full GC 會(huì)導(dǎo)致 Stop The World 情況的出現(xiàn),嚴(yán)重影響性能,所以一個(gè)性能良好的 JVM,應(yīng)該幾天才會(huì)發(fā)生一次 Full GC,或者最多一

每日雞湯,好喝

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?


01 案發(fā)現(xiàn)場

通常來說,一個(gè)系統(tǒng)在上線之前應(yīng)該經(jīng)過多輪的調(diào)試,在測試服務(wù)器上穩(wěn)定的運(yùn)行過一段時(shí)間。我們知道 Full GC 會(huì)導(dǎo)致 Stop The World 情況的出現(xiàn),嚴(yán)重影響性能,所以一個(gè)性能良好的 JVM,應(yīng)該幾天才會(huì)發(fā)生一次 Full GC,或者最多一天幾次而已。


但是昨天晚上突然收到短信通知,顯示線上部署的四臺機(jī)器全部卡死,服務(wù)全部不可用,趕緊查看問題!


涉及到類似的錯(cuò)誤,最開始三板斧肯定是查看 JVM 的情況。很多中小型公司沒有建立可視化的監(jiān)控平臺,比如Zabbix、Ganglia、Open-Falcon、Prometheus等等,沒辦法直接可視化看到JVM各個(gè)區(qū)域的內(nèi)存變化,GC次數(shù)和GC耗時(shí)。


不過不用怕,咱們用 jstat 這種工具也可以。言歸正傳,排查了線上問題之后,發(fā)現(xiàn)竟然是服務(wù)器上面,JVM 這段時(shí)間瘋狂 Full GC,一天搞了幾十次,直接把系統(tǒng)卡死了!

02 排查現(xiàn)場

破案之前,我們先來要保護(hù)下案發(fā)現(xiàn)場并進(jìn)行排查。


重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?


機(jī)器 2核 4G 
JVM堆內(nèi)存大小 2G??
系統(tǒng)運(yùn)行時(shí)間
1天
Full GC出現(xiàn)次數(shù)和單次耗時(shí) 48次,300ms左右
Young GC出現(xiàn)次數(shù)和單次耗時(shí) 4000多次,50ms


這樣看起來,系統(tǒng)的性能是相當(dāng)差了,一分鐘三次 Young GC,每半小時(shí)就一次 Full GC,接下來我們再看看 JVM 的參數(shù)??赡苡械耐瑢W(xué)每次見到這么多參數(shù)都會(huì)頭大,但其實(shí)每一個(gè)參數(shù)的背后都會(huì)透漏著蛛絲馬跡。我這里摘取關(guān)鍵參數(shù)如下:


CMSInitiatingOccupancyFraction 62
SurvivorRatio 5??
Xmx
1536M
Xmx 1536M

簡單解讀一下,根據(jù)參數(shù)可以看出來,這臺 4G 的機(jī)器上為 JVM 的堆內(nèi)存是設(shè)置了 1.5G 左右的大小。新生代和老年代默認(rèn)會(huì)按照 1:2 的比例進(jìn)行劃分,分別對應(yīng) 512M 和 1G。


一個(gè)重要的參數(shù) XXiSurvivorRatio 設(shè)置為5,它所代表的是新生代中Eden:Survivor1 :Survivor2的比例是 5:1:1。所以此時(shí)Eden區(qū)域大致為365M,每個(gè)Survivor區(qū)域大致為70MB。


還有一個(gè)非常關(guān)鍵的參數(shù),那就是 CMSInitiatingOccupancyFraction 設(shè)置為了62。它意味著一旦老年代內(nèi)存占用達(dá)到 62%,也就是存在 620MB 左右對象時(shí),就會(huì)觸發(fā)一次 Full GC。此時(shí)整個(gè)系統(tǒng)的內(nèi)存模型圖如下所示:

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

03 還原現(xiàn)場

根據(jù)對案發(fā)現(xiàn)場的排查,我們可以還原線上系統(tǒng)的 GC 運(yùn)行情況了,分析一下線上的 JVM 到底出現(xiàn)了什么狀況。


首先我們知道每分鐘會(huì)發(fā)生 3 次 Young GC,說明系統(tǒng)運(yùn)行 20 秒后就會(huì)把 Eden 區(qū)塞滿,Eden 區(qū)一共有 356MB 的空間,因此平均下來系統(tǒng)每秒鐘會(huì)產(chǎn)生 20MB 左右大小的對象。


接著我們根據(jù)每半小時(shí)觸發(fā)一次 Full GC 的推斷,以及 “-XX:CMSmitiatingOccupancyFraction=62” 參數(shù)的設(shè)置,老年代有 1G 的空間,所以應(yīng)該是在老年代有 600多MB 左右的對象時(shí)就會(huì)觸發(fā)一次 Full GC。


看到這里,有的同學(xué)可能立刻下結(jié)論,覺得肯定是因?yàn)?Survivor 區(qū)域太小了,導(dǎo)致 Young GC 后的存活對象太多放不下,就一直有對象流入老年代,進(jìn)而導(dǎo)致后來觸發(fā)的 Full GC ?


實(shí)際上分析到這里,絕對不能草率下這個(gè)判斷。


因?yàn)槔夏甏餅槭裁从心敲炊嗟膶ο??確實(shí)有可能是因?yàn)槊看?Young GC后的存活對象較多,Survivor區(qū)域太小,放不下了。


但也有可能是長時(shí)間存活的對象太多了,都積累在老年代里,始終回收不掉,進(jìn)而導(dǎo)致老年代很容易就達(dá)到 62% 的占比觸發(fā) Full GC,所以我們還要有更多的證據(jù)去驗(yàn)證我們的判斷。

04 破案開始

老年代里到底為什么會(huì)有那么多的對象?


面對這個(gè)問題,說句實(shí)話,僅僅根據(jù)可視化監(jiān)控和推論是絕對沒法往下分析了,因?yàn)槲覀儾⒉恢屠夏甏锏降诪槭裁磿?huì)有那么多的對象。這個(gè)時(shí)候就有必要讓線上系統(tǒng)重新運(yùn)行,借助 jstat 工具實(shí)時(shí)去觀察 JVM 實(shí)際的運(yùn)行情況。這個(gè)過程非常類似警察叔叔在破案時(shí),會(huì)假設(shè)自己是兇手,嘗試再現(xiàn)當(dāng)時(shí)的場景。


這里省略具體的 jstat 工具操作過程,如果大家沒有接觸過百度下即可,非常簡單。通過 jstat 的觀察,我們當(dāng)時(shí)可以看到,每次 Young GC 過后升入老年代里的對象其實(shí)很少。


看到這個(gè)現(xiàn)象,我起初也很奇怪。因?yàn)橥ㄟ^ jstat 的追蹤觀察,并不是每次Young GC 后都有 幾十MB 對象進(jìn)入老年代的,而是偶爾一次 Young GC 才會(huì)有 幾十MB 對象進(jìn)入老年代!

所以正常來說,既然沒有對象從新生代過渡到老年代,那么老年代就不至于快速的到達(dá) 62% 的占有率,從而導(dǎo)致 Full GC。那么老年代觸發(fā) Full GC 時(shí)候的幾百 MB 對象到底從哪里來的?


重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

仔細(xì)一想,其實(shí)答案已經(jīng)呼之欲出了,那就是大對象!


一定是系統(tǒng)運(yùn)行的時(shí)候,每隔一段時(shí)間就會(huì)突然產(chǎn)生幾百 MB 的大對象,由于新生代放不下,所以會(huì)直接進(jìn)入老年代,而不會(huì)走 Eden 區(qū)域。然后再配合上年輕代還偶爾會(huì)有 Young GC 后幾十 MB 對象進(jìn)入老年代,所以不停地觸發(fā)Full GC !

05 抓捕真兇

分析到這里,后面的過程就很簡單了,我們可以通過 jmap 工具,dump 出內(nèi)存快照,然后再用 jhat 或者 Visual VM 之類的可視化工具來分析就可以了。


通過內(nèi)存快照的分析,直接定位出來那個(gè)幾百M(fèi)B的大對象,發(fā)現(xiàn)竟然是個(gè)Map之類的數(shù)據(jù)結(jié)構(gòu),這是什么鬼?


返回頭去開始擼代碼,發(fā)現(xiàn)是從數(shù)據(jù)庫里查出來的數(shù)據(jù)存放在了這個(gè)Map里,沒有好辦法,再繼續(xù)地毯式排查。


最后發(fā)現(xiàn)竟然是有條坑爹的 SQL 語句沒加 where條件??!不知道是手滑還是忘了,測試的時(shí)候這個(gè)分支也沒走到(畫外音:這段代碼的開發(fā)和測試都不是我重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?


沒有 where 條件,每次查詢肯定會(huì)有超出預(yù)期的大量數(shù)據(jù),導(dǎo)致了每隔一段時(shí)間就會(huì)搞出幾個(gè)上百 MB 的大對象,這些對象全部直接進(jìn)入老年代,然后觸發(fā) Full GC !

06 善后處理

破案定位嫌疑人最困難,在知道兇手后,靠著滿大街的攝像頭,抓人就是分分鐘的事情。所以我們排查到這里,這個(gè)案例如何解決已經(jīng)非常簡單了。


(1)解決代碼中的 bug,把錯(cuò)誤的 SQL 修復(fù),一勞永逸徹底解決這幾百 MB 大對象進(jìn)入老年代的問題。


(2)以防萬一,對堆內(nèi)存空間進(jìn)行擴(kuò)容,然后再把-XX:CMSInitiatingOccupancyFraction 參數(shù)從 62 調(diào)高,使得老年代的使用率更高時(shí)才會(huì)觸發(fā) Full GC。

這兩個(gè)步驟優(yōu)化完畢之后,線上系統(tǒng)基本上表現(xiàn)就非常好了。

07 總結(jié)

本文通過一個(gè)線上系統(tǒng)卡死的現(xiàn)象,詳細(xì)地定位并剖析了產(chǎn)生問題的原因。也證明了要成為一個(gè)優(yōu)秀的程序員,不光對語言本身要有所了解,還要對 JVM 調(diào)優(yōu)這樣偏底層的知識有所涉獵,這對排查問題會(huì)有非常大的幫助。同時(shí)完善的監(jiān)控非常重要,通過提前告警,可以將問題扼殺在搖籃里!


特別推薦一個(gè)分享架構(gòu)+算法的優(yōu)質(zhì)內(nèi)容,還沒關(guān)注的小伙伴,可以長按關(guān)注一下:

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

長按訂閱更多精彩▼

重大事故!線上系統(tǒng)頻繁卡死,兇手竟然是 Full GC ?

如有收獲,點(diǎn)個(gè)在看,誠摯感謝


免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
關(guān)閉
關(guān)閉