自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

線上又OOM,我太難了......

開(kāi)發(fā) 架構(gòu)
這里給大家說(shuō)說(shuō)當(dāng)時(shí)我們是怎么進(jìn)行排查的,首先,遇到這種內(nèi)存突然飆升然后導(dǎo)致 oom 的情況,先看看是不是外部對(duì)你的請(qǐng)求流量過(guò)大導(dǎo)致的。

本文轉(zhuǎn)載自微信公眾號(hào)「石杉的架構(gòu)筆記」,作者中華石杉。轉(zhuǎn)載本文請(qǐng)聯(lián)系石杉的架構(gòu)筆記公眾號(hào)。

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

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

事故背景

先給大家簡(jiǎn)單說(shuō)一下這個(gè)問(wèn)題的發(fā)生背景,線上生產(chǎn)環(huán)境部署了兩個(gè)系統(tǒng),我們可以認(rèn)為是系統(tǒng) A 和系統(tǒng) B,同時(shí)系統(tǒng) B 因?yàn)槭谴罅髁亢诵南到y(tǒng),所以部署了幾十臺(tái)機(jī)器,定位就是集群部署要抗每秒幾萬(wàn)的 TPS 的,兩臺(tái)系統(tǒng)之間是基于 dubbo 作為 rpc 調(diào)用框架,注冊(cè)中心用的是 zookeeper。

如下圖所示:

在這個(gè)背景之下,某一天系統(tǒng) B 因?yàn)楦铝舜a,因此發(fā)起了一次幾十臺(tái)機(jī)器的全量滾動(dòng)更新和部署。

也就是說(shuō),系統(tǒng) B 的開(kāi)發(fā)團(tuán)隊(duì)基于最新的代碼把幾十臺(tái)機(jī)器依次用最新代碼重新部署了一遍,也就是每臺(tái)機(jī)器都會(huì)有一次系統(tǒng)停止和重啟的過(guò)程。

如下圖所示:

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

如下圖所示:

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

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

排查思路

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

因?yàn)橥@種突發(fā)性的問(wèn)題,都是外部流量突然飆升導(dǎo)致的,這里先給分析一種外部流量突然飆升導(dǎo)致系統(tǒng) oom 的場(chǎng)景。

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

如下圖所示:

那么正常情況下,你的 jvm 年輕代里肯定對(duì)象會(huì)越來(lái)越多是不是?但是其實(shí)一般到了一定時(shí)候,年輕代里的存活對(duì)象基本很少,因?yàn)榇蟛糠值膶?duì)象都是之前已經(jīng)處理完畢的請(qǐng)求創(chuàng)建的對(duì)象,他們其實(shí)都是一些沒(méi)用的垃圾對(duì)象。

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

如下圖:

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

這個(gè)時(shí)候就不好說(shuō)了,因?yàn)楹芸赡茉诙虝r(shí)間內(nèi)突然涌入大量的請(qǐng)求,這些請(qǐng)求創(chuàng)建了大量的對(duì)象,瞬間就填滿了年輕代,然后這個(gè)時(shí)候觸發(fā)年輕代 gc 后,發(fā)現(xiàn)大量的對(duì)象是沒(méi)法回收的,此時(shí)只能怎么辦?

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

那么這個(gè)時(shí)候年輕代里的大量存活對(duì)象都轉(zhuǎn)移到老年代里去了,老年代里幾乎也被填滿了,然后此時(shí)年輕代里因?yàn)榱髁刻笏矔r(shí)再次被填滿,此時(shí)年輕代里大量的存活對(duì)象該何去何從?這個(gè)時(shí)候你去老年代嗎?

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

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

而且這些對(duì)象都是存活的都沒(méi)法回收,此時(shí)再要?jiǎng)?chuàng)建新的對(duì)象,就沒(méi)地方創(chuàng)建了,接著就會(huì)報(bào)出 oom 內(nèi)存溢出異常來(lái)了。

如下圖:

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

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

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

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

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

如下圖:

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

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

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

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

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

所以在這里給大家說(shuō)一下我們當(dāng)時(shí)遇到的一個(gè)問(wèn)題,大家重點(diǎn)吸收排查思路,下面的具體 case by case 的個(gè)別案例可以作為一個(gè)例子看一下。

排查案例

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

如下圖:

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

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

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

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

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

如下圖:

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

如下圖所示:

其實(shí)本來(lái) dubbo 創(chuàng)建幾千次 rpc 調(diào)用對(duì)象也沒(méi)什么,但是問(wèn)題就出在了一個(gè)特殊的 case 上了。

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

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

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

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

如下圖:

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

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

總結(jié)

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

責(zé)任編輯:武曉燕 來(lái)源: 石杉的架構(gòu)筆記
相關(guān)推薦

2022-04-27 10:14:43

進(jìn)程調(diào)度LinuxCPU

2020-03-26 15:10:34

蘋(píng)果iPhone手機(jī)

2023-03-10 08:24:27

OOMdump線程

2021-12-08 23:42:37

iPhone 13手機(jī)停產(chǎn)

2022-04-15 19:48:49

上海疫情居家辦公

2019-10-14 09:41:08

游戲Google接口

2022-04-05 11:29:40

Linux安裝操作系統(tǒng)

2023-10-30 22:23:12

Cacherkube版本

2022-10-10 08:05:34

線程池OOM問(wèn)題

2020-08-19 09:03:57

微信微信支付移動(dòng)應(yīng)用

2021-09-18 07:19:54

400G5GIP網(wǎng)絡(luò)

2020-01-07 10:17:59

微軟Windows 10操作系統(tǒng)

2022-09-19 16:31:14

游戲益智游戲機(jī)

2021-12-04 23:01:33

程序員開(kāi)發(fā)互聯(lián)網(wǎng)

2022-02-16 10:07:26

谷歌計(jì)算機(jī)離職

2020-01-15 09:35:00

Linux瀏覽器Java

2021-03-18 09:17:00

LinuxM1 Mac蘋(píng)果

2023-09-07 06:44:49

Intel 4Ultra

2024-10-10 15:32:51

2022-02-16 16:36:55

阿里面試面試流程背景
點(diǎn)贊
收藏

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