偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

線上生產(chǎn)環(huán)境JVM內(nèi)存泄露,我熬夜處理一通宵總結(jié)了一下經(jīng)驗

開發(fā) 前端
今天給大家分享一個我們之前基于 dubbo 開發(fā)一個線上系統(tǒng)時候遇到的內(nèi)存泄漏生產(chǎn)問題的排查與優(yōu)化實踐經(jīng)驗。

相信對于大家多看一些類似的案例,以后對于大家自己在線上系統(tǒng)遇到各種生產(chǎn)問題的時候,進行排查和優(yōu)化的思路會有很大的啟發(fā)。

事故背景

先給大家簡單說一下這個問題的發(fā)生背景,線上生產(chǎn)環(huán)境部署了兩個系統(tǒng),我們可以認為是系統(tǒng) A 和系統(tǒng) B,同時系統(tǒng) B 因為是大流量核心系統(tǒng),所以部署了幾十臺機器,定位就是集群部署要抗每秒幾萬的 TPS 的,兩臺系統(tǒng)之間是基于 dubbo 作為 rpc 調(diào)用框架,注冊中心用的是 zookeeper。

如下圖所示:

在這個背景之下,某一天系統(tǒng) B 因為更新了代碼,因此發(fā)起了一次幾十臺機器的全量滾動更新和部署。

也就是說,系統(tǒng) B 的開發(fā)團隊基于最新的代碼把幾十臺機器依次用最新代碼重新部署了一遍,也就是每臺機器都會有一次系統(tǒng)停止和重啟的過程。

如下圖所示:

沒想到生產(chǎn)環(huán)境的災(zāi)難性故障就這么突然發(fā)生了,在系統(tǒng) B 的幾十臺機器依次重新部署之后,結(jié)果系統(tǒng) A 的開發(fā)團隊驚訝的發(fā)現(xiàn)自己的系統(tǒng)居然過了一會就發(fā)送了 jvm 內(nèi)存使用率飆升超過 90% 的告警,而且很快系統(tǒng) A 居然就直接 OOM 內(nèi)存溢出崩潰了。

如下圖所示:

于是系統(tǒng) B 的開發(fā)團隊順利的把一個大版本更新了幾十臺機器之后,心滿意足的欣賞自己的成果呢,系統(tǒng) A 的開發(fā)團隊突然開始一臉懵逼的手忙腳亂進行了生產(chǎn)故障的排查。

那么大家可以想想,這個時候,如果是你負責(zé)的線上系統(tǒng)突然給你發(fā)送內(nèi)存使用率飆升超過 90%,而且很快就 oom 內(nèi)存溢出,你會怎么排查?

排查思路

這里給大家說說當時我們是怎么進行排查的,首先,遇到這種內(nèi)存突然飆升然后導(dǎo)致 oom 的情況,先看看是不是外部對你的請求流量過大導(dǎo)致的。

因為往往這種突發(fā)性的問題,都是外部流量突然飆升導(dǎo)致的,這里先給分析一種外部流量突然飆升導(dǎo)致系統(tǒng) oom 的場景。

假設(shè)你平時常規(guī)化運作的時候,每次一批請求過來會在你的 jvm 年輕代里創(chuàng)建一批對象,接著這批請求處理完畢了,之前創(chuàng)建的那批對象就會成為垃圾對象了,然后下一批請求過來,又在 jvm 年輕代里創(chuàng)建了一批對象。

如下圖所示:

那么正常情況下,你的 jvm 年輕代里肯定對象會越來越多是不是?但是其實一般到了一定時候,年輕代里的存活對象基本很少,因為大部分的對象都是之前已經(jīng)處理完畢的請求創(chuàng)建的對象,他們其實都是一些沒用的垃圾對象。

所以其實正常情況下跑一段時間后,會觸發(fā)一下 jvm 年輕代的垃圾回收,把垃圾對象都回收掉就行了。

如下圖:

所以正常情況下,是不會出現(xiàn)什么問題的,但是如果是突發(fā)性的大流量來襲呢?

這個時候就不好說了,因為很可能在短時間內(nèi)突然涌入大量的請求,這些請求創(chuàng)建了大量的對象,瞬間就填滿了年輕代,然后這個時候觸發(fā)年輕代 gc 后,發(fā)現(xiàn)大量的對象是沒法回收的,此時只能怎么辦?

只能把這些對象轉(zhuǎn)移到老年代里去了,如下圖:

那么這個時候年輕代里的大量存活對象都轉(zhuǎn)移到老年代里去了,老年代里幾乎也被填滿了,然后此時年輕代里因為流量太大瞬時再次被填滿,此時年輕代里大量的存活對象該何去何從?這個時候你去老年代嗎?

老年代都塞滿了存活對象,即使觸發(fā)了老年代 gc 也沒法回收他們,年輕代也沒地方放這些存活對象了,這個時候會如何?

很簡單,由于瞬時并發(fā)流量太大,同時創(chuàng)建了太多的存活對象,塞滿了老年代和年輕代,我們很可能會收到報警說 jvm 年輕代和老年代內(nèi)存使用率都超過了 90%。

而且這些對象都是存活的都沒法回收,此時再要創(chuàng)建新的對象,就沒地方創(chuàng)建了,接著就會報出 oom 內(nèi)存溢出異常來了。

如下圖:

所以說瞬時流量激增可能會導(dǎo)致系統(tǒng) A 發(fā)送內(nèi)存使用率超過 90%,而且很快就 oom 的問題,但是到底是不是這個問題導(dǎo)致的呢?

雖然我們可以思路順暢的推演出上述場景,但是我們這個時候趕緊看一下系統(tǒng) A 的線上 QPS 指標監(jiān)控,結(jié)果一臉懵逼的發(fā)現(xiàn),系統(tǒng) A 根本就沒有流量激增,人家的流量一切都很平穩(wěn),所以根本不是這個原因?qū)е碌膯栴}。

那既然不是這個問題,那還有什么問題會導(dǎo)致這個現(xiàn)象呢?

很簡單,第二種問題就是內(nèi)存泄漏,也就是說,在某種特殊條件下,觸發(fā)了一個內(nèi)存泄漏的行為,就是你的系統(tǒng)不停的產(chǎn)生某一類對象,這一類對象明明都不用了,結(jié)果還一直放在內(nèi)存里,而且根本回收不掉。

就這么不停的積累這類對象,就會導(dǎo)致內(nèi)存使用率不停的攀升,最后導(dǎo)致 oom 內(nèi)存溢出。

如下圖:

那么針對這個內(nèi)存泄漏的問題,這個時候我們到底應(yīng)該怎么排查呢?很簡單,這個時候你到底是真程序員還是假程序員,得亮亮真功夫了。

往往這種內(nèi)存類的問題,過段的用 jmap 這個命令,去對線上運行的系統(tǒng) jvm 進程生成一個內(nèi)存 dump 快照出來,然后把 dump 快照下載到本地,用 MAT 這個工具就可以分析這個內(nèi)存快照。

在 MAT 工具中我們會看到你的 jvm 里到底是什么破對象占用了那么大的空間,才導(dǎo)致了你的內(nèi)存使用率飆升到 90%+ 的。

這個時候其實導(dǎo)致內(nèi)存泄漏的原因有很多種,比如說你們自己代碼寫的不好,就是每次請求都創(chuàng)建某一類對象,這類對象給扔到某個 class 的靜態(tài) map 里一直放著,從來不回收,也沒法回收,導(dǎo)致這類無用對象一直增長,最后導(dǎo)致了 oom。

另外還有一種比較常見的現(xiàn)象,就是我們的系統(tǒng)使用了一些開源框架,這些開源框架在某種特殊場景下創(chuàng)建了一堆的對象,沒法回收,他自己也從來不回收,導(dǎo)致了開源框架悄咪咪創(chuàng)建的這批對象占用了大量內(nèi)存,導(dǎo)致了內(nèi)存泄漏。

所以在這里給大家說一下我們當時遇到的一個問題,大家重點吸收排查思路,下面的具體 case by case 的個別案例可以作為一個例子看一下。

排查案例

就我們當時的 case 來說,經(jīng)過 MAT 一通排查,發(fā)現(xiàn)占用了大量內(nèi)存的對象是 dubbo 框架創(chuàng)建的,dubbo 框架創(chuàng)建了一種用于進行 rpc 調(diào)用的大對象,這類對象一直創(chuàng)建一直增長,然后從來不回收,最后導(dǎo)致了內(nèi)存泄漏和內(nèi)存溢出。

如下圖:

那么 dubbo 框架為什么會不停的創(chuàng)建一類用于進行 rpc 調(diào)用的對象呢?

這就得分析 dubbo 框架的源碼了,當時經(jīng)過 dubbo 框架源碼的分析,我們得出了以下的問題發(fā)生流程:

當系統(tǒng) B 在線上進行幾十臺機器的滾動發(fā)布的時候,每一臺機器被發(fā)布,都會導(dǎo)致注冊中心感知到服務(wù)變動,然后注冊中心會把這幾十臺機器的地址列表都給系統(tǒng) A 推送過去。

也就是說,連續(xù)發(fā)布幾十臺機器,就會導(dǎo)致注冊中心推送幾十次最新地址列表,每一次推送都包含了幾十臺機器的地址。

因此,假設(shè)系統(tǒng) B 部署了 50 臺機器,等于隨著 50 臺機器依次重新發(fā)布,會導(dǎo)致注冊中心一共給系統(tǒng) A 推送 50*50=2500 條機器地址。

如下圖:

而系統(tǒng) A 的 dubbo 框架等于會收到短時間內(nèi)頻繁推送的幾千條機器地址,然后對每條機器地址,其實 dubbo 框架都會去創(chuàng)建一個對應(yīng)的 rpc 調(diào)用類的對象。

如下圖所示:

其實本來 dubbo 創(chuàng)建幾千次 rpc 調(diào)用對象也沒什么,但是問題就出在了一個特殊的 case 上了。

那就是系統(tǒng) B 那邊并沒有去設(shè)置對外提供的是什么 rpc 協(xié)議,因為 dubbo 是支持多種不同的 rpc 協(xié)議的,比如說 dubbo 協(xié)議、http 協(xié)議,等等。

所以在當時的那個較老的 dubbo 版本中,就出現(xiàn)了一個隱藏的問題,就是如果系統(tǒng) B 沒設(shè)置具體對外提供的協(xié)議版本,就會導(dǎo)致系統(tǒng) A 收到幾千條機器地址后,除了創(chuàng)建 dubbo 協(xié)議的對象,還會創(chuàng)建幾千個基于 http rest 類協(xié)議的 rpc 調(diào)用對象。

可是系統(tǒng) B 又沒提供 http rest 接口,因此創(chuàng)建會全部失敗,但是背后創(chuàng)建的大量對象又會放著,沒法回收。

這就導(dǎo)致了 dubbo 框架不停的創(chuàng)建出來大量的對象,占用了 90% 的內(nèi)存,最后導(dǎo)致了內(nèi)存溢出。

如下圖:

那么這個問題是如何解決的呢?其實問題的核心在于排查思路和背后的原理,最后問題的解決往往是 case by case 的。

比如我們這個case里,其實就很簡單,就是要讓系統(tǒng) B 設(shè)置好對外提供的 dubbo protocol 協(xié)議,避免上面那種因為 protocol 協(xié)議沒設(shè)置導(dǎo)致創(chuàng)建了大量的無用對象沒法回收。

總結(jié)

最后希望大家看完今天的生產(chǎn)排查與優(yōu)化案例后,未來在自己工作中遇到了類似的問題,能給大家提供一種問題排查的思路幫助大家。

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2018-04-11 08:25:11

Linux內(nèi)存方法

2021-04-27 10:02:40

股票數(shù)組代碼

2012-10-18 13:48:31

統(tǒng)一通信UC

2009-04-01 08:19:41

IT白領(lǐng)猝死加班

2020-07-23 07:26:49

JVM類加載器

2010-05-14 10:03:30

部署統(tǒng)一通信

2010-05-13 23:30:46

統(tǒng)一通信系統(tǒng)

2010-05-13 23:34:39

統(tǒng)一通信環(huán)境

2009-06-09 10:42:12

統(tǒng)一通信效率運營成本

2010-05-14 15:54:15

統(tǒng)一通信服務(wù)

2023-01-04 18:32:31

線上服務(wù)代碼

2017-02-17 11:19:00

Android內(nèi)存泄露分析總結(jié)

2010-05-14 10:07:38

統(tǒng)一通信平臺

2010-05-12 15:05:43

2012-03-20 14:06:54

統(tǒng)一通訊電子郵件即時通訊

2021-04-14 10:14:34

JVM生產(chǎn)問題定位內(nèi)存泄露

2009-06-29 14:11:00

企業(yè)統(tǒng)一通信

2012-05-24 10:09:06

統(tǒng)一通信

2022-09-12 18:29:49

kafka緩存數(shù)據(jù)

2023-03-03 12:37:50

JavaJVM內(nèi)存溢出
點贊
收藏

51CTO技術(shù)棧公眾號