012、案例實(shí)戰(zhàn):每日百萬交易的支付系統(tǒng),JVM棧內(nèi)存與永久代大小又該如何設(shè)置?

案例實(shí)戰(zhàn)
每日百萬交易的支付系統(tǒng),JVM棧內(nèi)存與永久代大小又該如何設(shè)置?
目錄:
前文回顧
基于案例,說說不合理設(shè)置內(nèi)存的反面示例
大促期間,瞬時訪問量增加十倍
少數(shù)請求需要幾十秒處理,導(dǎo)致老年代內(nèi)存占用變大
老年代對象越來越多導(dǎo)致頻繁垃圾回收
反面案例總結(jié)
如何合理設(shè)置永久代大???
如何合理設(shè)置棧內(nèi)存大小
昨日思考題分析
今日思考題
1、前文回顧
昨天的文章給大家基于案例分析了一下,如果我們準(zhǔn)備上線一個新的系統(tǒng),如何根據(jù)這個系統(tǒng)未來預(yù)估的業(yè)務(wù)量,訪問量,去推算這個系統(tǒng)每秒種的并發(fā)量,然后推算每秒鐘的請求對內(nèi)存空間的占用,進(jìn)而推算出整個系統(tǒng)運(yùn)行期間的JVM內(nèi)存運(yùn)轉(zhuǎn)模型。
然后基于這個推算出來的JVM內(nèi)存運(yùn)轉(zhuǎn)模型,再接著去在系統(tǒng)上線前就選擇一個合理的機(jī)器配置,要多大內(nèi)存的機(jī)器,另外給JVM堆內(nèi)存空間一個合理的大小。
其實(shí)這是一項(xiàng)非常基礎(chǔ)的技能,因?yàn)閷τ诖髲S工程師,每次上線一個新的系統(tǒng),他可能上線就會面臨很大的訪問壓力
所以必須要學(xué)會合理預(yù)估內(nèi)存壓力,然后選擇對應(yīng)的機(jī)器配置,并且給出合理的內(nèi)存大小,希望大家好好掌握。
2、基于案例,說說不合理設(shè)置內(nèi)存的反面示例
昨天說的是一個正面的例子,即如何合理的設(shè)置內(nèi)存大小。
今天來說一個反面的不合理設(shè)置內(nèi)存大小導(dǎo)致的問題,也是我們之前線上生產(chǎn)系統(tǒng)真實(shí)經(jīng)歷過的一次故障,但是當(dāng)時不是發(fā)生在支付系統(tǒng)中的,是另外一個系統(tǒng)。
不過為了便于大家理解,咱們還是以支付系統(tǒng)作為案例來說明好了,其實(shí)思路是一樣的。
比如現(xiàn)在我們假設(shè)一個前提,就是支付系統(tǒng)因?yàn)闆]有經(jīng)過合理的內(nèi)存預(yù)估,所以直接選用了1臺2核4G的虛擬機(jī)來部署了線上系統(tǒng),而且就只用了一臺機(jī)器
然后線上JVM給的堆內(nèi)存大小,僅僅就只有1G,扣除老年代之后,新生代其實(shí)就幾百M(fèi)B的內(nèi)存空間,大家看下圖。

好了,接著我們還是用昨天的那個業(yè)務(wù)壓力,就是每天100萬交易,高峰期每秒大概100筆支付交易,對應(yīng)核心的支付訂單對象有100個創(chuàng)建出來,每個支付訂單對象占據(jù)500左右的字節(jié)大小,總共就是50kb左右。
然后一筆交易要1秒來處理,所以這100個對象在新生代中存在1秒的期間會被人引用,是無法被回收的。
而且我們之前說過一個全局預(yù)估的思路,從核心的支付訂單對象擴(kuò)展開來,拓展到系統(tǒng)里其他的對象中去,起碼可以把內(nèi)存占用擴(kuò)大了10倍~20倍
比如我們就擴(kuò)大個20倍好了,那么說明1秒之內(nèi),總共會創(chuàng)建出來大概1MB左右的對象,無法被回收。
3、大促期間,瞬時訪問量增加十倍
其實(shí)按照估算出來的內(nèi)存壓力,你這么小的新生代在系統(tǒng)正常運(yùn)行的情況下,其實(shí)還不算什么大問題
因?yàn)槊棵胄略?MB對象,然后幾百秒過后,新生代快滿了,自然就會觸發(fā)Minor GC,回收掉里面99%的垃圾對象。
你要是內(nèi)存那么小,最多就是發(fā)現(xiàn)系統(tǒng)每隔幾分鐘略微卡頓一下,因?yàn)檫@個時候在進(jìn)行垃圾回收,會影響系統(tǒng)性能
至于為什么影響系統(tǒng)性能,下周垃圾回收的主題里會分析的。
但是現(xiàn)在我們假設(shè),如果你的電商系統(tǒng)搞大促活動呢?
一般搞大促活動,很可能導(dǎo)致你的壓力瞬間增大10倍,因?yàn)槠綍r不來你網(wǎng)站的人,今天都來了。
此時可能會發(fā)現(xiàn),每秒鐘你的支付系統(tǒng)不是100筆訂單了,可能是每秒鐘上千筆訂單。
這個時候你的系統(tǒng)壓力本身就會很大了,不光是內(nèi)存,尤其是線程資源、CPU資源,都會幾乎打滿。內(nèi)存就更是岌岌可危了。
4、少數(shù)請求需要幾十秒處理,導(dǎo)致老年代內(nèi)存占用變大
咱們就針對內(nèi)存來分析一下。
現(xiàn)在假設(shè)你每秒1000筆交易,那么每秒鐘系統(tǒng)對內(nèi)存的占用增加到10MB以上
我們甚至可以再大膽一點(diǎn),預(yù)估每秒對內(nèi)存占用達(dá)到幾十MB,甚至上百M(fèi)B也可以,因?yàn)楫吘勾蟠贂r流量激增,就一切圍繞這來預(yù)估。
而且最可怕的一點(diǎn)是,可能你每秒過來的1000筆交易,不再是1秒就可以處理完畢了,因?yàn)閴毫E增,會導(dǎo)致你的系統(tǒng)性能下降,可能偶爾會出現(xiàn)每個請求處理完畢需要幾秒鐘,甚至幾十秒的時間。
此時我們看下圖可能出現(xiàn)什么問題,假設(shè)你的新生代里已經(jīng)積壓了很多的數(shù)據(jù),都快滿了。

然后呢,此時內(nèi)存里有比如幾十MB的對象都被人引用著,因?yàn)樯贁?shù)請求突然處理的特別慢。
為什么會處理特別慢?因?yàn)閴毫μ?,?dǎo)致系統(tǒng)性能太差了,如下圖。

這個時候,如果你要再次在新生代里分配對象,那么是不是會導(dǎo)致一次Minor GC去回收新生代?
沒錯,但是可能回收掉大量的對象之后,那少數(shù)幾十MB的對象還在,因?yàn)樯贁?shù)請求特別的慢。
然后很快新生代繼續(xù)被填滿,再次觸發(fā)Minor GC,然后少數(shù)幾十MB的對象還在,此時多次之后后,就會被轉(zhuǎn)移到老年代去,如下圖。

5、老年代對象越來越多導(dǎo)致頻繁垃圾回收
那么大家思考一下,上述流程如果反復(fù)來多次,就是時不時有少數(shù)請求特別慢,創(chuàng)建的對象在新生代反復(fù)多次沒法被回收,然后就會被弄到老年代去
然后后續(xù)處理完之后,老年代里的對象就沒人引用了,成為了垃圾對象。
經(jīng)常重復(fù)這個流程,老年代里的垃圾對象,是不是就會越來越多?
一旦老年代的垃圾對象越來越多,遲早會滿,然后就會觸發(fā)老年代的垃圾回收,而且這個老年代被占滿的頻率還很快,可能就會頻繁觸發(fā)老年代的垃圾回收。
大家要知道,老年代的垃圾回收速度是很慢的,這個為什么慢,下周會給大家講
但是在上述場景下,我們基本可以分析出來,如果你不合理的設(shè)置內(nèi)存,就會導(dǎo)致新生代內(nèi)存不充足,然后導(dǎo)致很多對象不停的遷移到老年代去,最后導(dǎo)致老年代也要不停的進(jìn)行垃圾回收。
最后這頻繁的垃圾回收,就會極大的影響系統(tǒng)的性能。
6、反面案例總結(jié)
本文就通過一個支付系統(tǒng)內(nèi)存設(shè)置過小,然后突發(fā)巨大的流量壓力,突發(fā)的性能抖動,最后導(dǎo)致很多對象長期在新生代被人引用,無法被回收,最后持續(xù)進(jìn)入老年代,最后觸發(fā)老年代內(nèi)存都頻繁占滿,然后老年代都頻繁被垃圾回收。
這是我們之前另外一個線上系統(tǒng)真實(shí)發(fā)生的場景,只不過用支付系統(tǒng)作為案例給大家解釋了一遍,所以大家更能從反面體會到,不合理的預(yù)估 業(yè)務(wù)系統(tǒng)壓力,不合理的設(shè)置內(nèi)存大小,就可能會導(dǎo)致很大的問題。
7、如何合理設(shè)置永久代大?。?/p>
話說回來,如何合理設(shè)置永久代大小呢?
其實(shí)一般永久代剛開始上線一個系統(tǒng),沒太多可以參考的規(guī)范,但是一般你設(shè)置個幾百M(fèi)B,大體上都是夠用的
因?yàn)槔锩嬷饕褪谴娣乓恍╊惖男畔?,后面也會用專門的案例給大家分析,什么樣的系統(tǒng)容易出現(xiàn)永久代內(nèi)存溢出。
8、如何合理設(shè)置棧內(nèi)存大小
其實(shí)這個棧內(nèi)存大小設(shè)置,一般也不會特別的去預(yù)估和設(shè)置的,一般默認(rèn)就是比如512KB到1MB,就差不多夠了。
這就是每個線程自己的棧內(nèi)存空間,用來存放線程執(zhí)行方法期間的各種布局變量的。后面也會用專門的案例演示,棧內(nèi)存什么時候會發(fā)生內(nèi)存溢出。
9、昨日思考題分析
昨天讓大家去思考自己平時負(fù)責(zé)的系統(tǒng),有沒有按照這個思路去預(yù)估業(yè)務(wù)系統(tǒng)壓力,然后給一個合理的內(nèi)存設(shè)置
其實(shí)就是希望大家以后建立起來一個全面的工程素養(yǎng),每個合格的工程師,都應(yīng)該在上線系統(tǒng)的時候,對系統(tǒng)壓力做出預(yù)估,然后對JVM內(nèi)存、磁盤空間大小、網(wǎng)絡(luò)帶寬、數(shù)據(jù)庫壓力做出預(yù)估,然后各方面都給出合理的配置。
10、今日思考題
看完今天的文章,我想給大家一個思考題,假設(shè)大家手頭負(fù)責(zé)的系統(tǒng)業(yè)務(wù)量暴增100倍,甚至1000倍,按照我們文章的思路,自己去分析一下,有沒有可能出現(xiàn)JVM上的問題?
要是業(yè)務(wù)真的增長這么多,你應(yīng)該怎么調(diào)整機(jī)器配置和JVM內(nèi)存大?。?/p>
End
版權(quán):公眾號儒猿技術(shù)窩
未經(jīng)許可不得傳播,如有侵權(quán)將追究法律責(zé)任