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

讓人頭疼的WAS內(nèi)存溢出,看銀行運(yùn)維人員如何優(yōu)雅的解決

新聞 系統(tǒng)運(yùn)維
在日常的生產(chǎn)運(yùn)維中,WAS應(yīng)用問題的排查確實(shí)讓筆者這種銀行運(yùn)維人員頭疼。

 [[313156]]

1 引言

WAS(IBM WebSphere Application Server)是IBM發(fā)布的一款成熟的企業(yè)級Web中間件產(chǎn)品,憑借其可靠性與穩(wěn)定性,一直是國內(nèi)大型商業(yè)銀行Web服務(wù)的主流選擇??稍俜€(wěn)定也會(huì)出問題,在日常的生產(chǎn)運(yùn)維中,WAS應(yīng)用問題的排查確實(shí)讓筆者這種銀行運(yùn)維人員頭疼。一方面廠商提供技術(shù)支持的時(shí)效性與準(zhǔn)確性有待改善,另一方面像IBM其他產(chǎn)品一樣,網(wǎng)上開放的可參考和借鑒的資料太少,發(fā)生WAS問題時(shí)著實(shí)讓人無從下手。不過不要緊,魯迅先生曾經(jīng)說過,“走的人多了,自然就有路了”,筆者作為具有多年WAS運(yùn)維經(jīng)驗(yàn)的老鳥,下面就把自己在應(yīng)對WAS內(nèi)存溢出方面的知識總結(jié)一下,為大家介紹一下如何優(yōu)雅的應(yīng)對WAS內(nèi)存溢出。

2 IBM JAVA內(nèi)存管理

要應(yīng)對WAS內(nèi)存溢出,必須對IBM對JAVA內(nèi)存的管理有所了解,下面,筆者就簡單介紹一下IBM是如何管理JAVA內(nèi)存的。不同于大家經(jīng)常使用的Oracle Java,WAS使用的JAVA是內(nèi)置于WAS內(nèi)部的IBM JAVA,與Oracle Java在JVM、配置參數(shù)等方面有著顯著不同。

 

IBM JAVA 同樣包含JDK、JRE、JVM三層,其關(guān)系如圖所示:

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖1 JDK、JRE、JVM關(guān)系

 

JVM內(nèi)存管理區(qū)域包括程序計(jì)數(shù)器、Java虛擬機(jī)棧、堆空間、方法區(qū)、運(yùn)行時(shí)常量池、本地方法棧(The Java® Virtual Machine Specification Java SE 8 Edition定義的內(nèi)存區(qū)域)。以上幾個(gè)內(nèi)存區(qū)域中,除程序計(jì)數(shù)器區(qū)域外,都可能會(huì)產(chǎn)生OutOfMemoryError錯(cuò)誤(本文中內(nèi)存溢出特指Java的“OutOfMemoryError”)。

 

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖2 JVM 運(yùn)行時(shí)內(nèi)存區(qū)域

程序計(jì)數(shù)器區(qū)域
Java虛擬機(jī)支持多線程運(yùn)行,所以對于每個(gè)線程,都需要一個(gè)指示其運(yùn)行程序位置的指針,這個(gè)指針指向當(dāng)前程序運(yùn)行方法的地址。

Java虛擬機(jī)棧
每一個(gè)Java線程都擁有一個(gè)私有的Java虛擬機(jī)棧。像其他傳統(tǒng)語言一樣,Java虛擬機(jī)棧保存了程序調(diào)用時(shí)的局部變量和部分結(jié)果(稱之為Frame)。

方法區(qū)、運(yùn)行時(shí)常量池
方法區(qū)存放運(yùn)行時(shí)常量池、字段以及方法(包括構(gòu)造方法、特殊方法)代碼。在IBM Java 8版本中,所有加載的類都存放在稱之為Metaspace的空間中,Metaspace使用操作系統(tǒng)本地內(nèi)存空間。

本地方法區(qū)域
為了支持操作系統(tǒng)本地方法(如C語言)調(diào)用,虛擬機(jī)中在本地方法區(qū)域中存儲本地方法調(diào)用的棧信息。

堆空間
堆是JVM運(yùn)行時(shí)內(nèi)存中最大的區(qū)域,也是和程序開發(fā)密切相關(guān)區(qū)域,所有的對象實(shí)例(包括基本類型)、數(shù)組都存放在這個(gè)區(qū)域。和傳統(tǒng)的C、C++語言不同,Java語言不需要開發(fā)人員顯式地進(jìn)行內(nèi)存的申請和釋放,而是由JVM的Allocator(內(nèi)存分配器)和Garbage Collection(內(nèi)存垃圾回收器,簡稱GC)負(fù)責(zé)管理內(nèi)存。我們最常見的內(nèi)存溢出“java.lang.OutOfMemoryError : Java heap space”也主要和該區(qū)域有關(guān)。下面我們將著重闡述IBM J9 VM堆空間相關(guān)模型和垃圾回收策略。

堆空間內(nèi)存結(jié)構(gòu)和垃圾回收策略(GC)
J9 VM支持多種不同的GC策略,不同的GC策略對應(yīng)不同的Heap內(nèi)存模型及分配回收算法,不同的GC策略適應(yīng)于不同的業(yè)務(wù)場景,對于大多數(shù)系統(tǒng)(特別是交易類系統(tǒng))來說,可使用“Generational Concurrent Garbage Collector”策略(簡稱gencon,參數(shù):-Xgcpolicy:gencon可以指定使用該策略),這也是J9 VM的默認(rèn)GC策略,本文主要詳細(xì)介紹該策略。

“Generational Concurrent Garbage Collector”策略特別適合存在非常多短生命周期對象的應(yīng)用,即對象申請完之后,很快就不被使用,可以被GC回收。而一般的交易類系統(tǒng),都符合這種場景。

在該策略下,Heap內(nèi)存被劃分成新區(qū)域(Nursery)、老區(qū)域(Tenured)。所有對象創(chuàng)建后都被分配到Nursery區(qū)域,之后如果該對象一直標(biāo)記為可用,則會(huì)被自動(dòng)到Tenured區(qū)域。

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖3 J9 VM 默認(rèn)堆空間內(nèi)存模型

 

更進(jìn)一步,可以將Nursery區(qū)域劃分為Allocate空間、Survivor空間。新創(chuàng)建的對象一開始被分配到Allocate空間,當(dāng)Allocate空間滿之后,觸發(fā)一次Local GC,由Scavenge 進(jìn)程將Allocate空間中“活著的”對象拷貝到Survivor區(qū),超過一定周期(Tenured age)的對象則直接被移動(dòng)到Tenured區(qū)域。之后,Allocate空間、Survivor空間的角色互換,等待下次Local GC。

 

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖4 Local GC過程

上文提到,在一般場景下,大部分對象創(chuàng)建后,很快就不被使用、存活的對象較少,所以Local GC移動(dòng)的數(shù)據(jù)也很少,而且Local GC后,可以得到很大的Allocate空間,這樣就減小了GC時(shí)間。在JVM中,GC意味著所有運(yùn)行中線程都要停下來(Pause)等待GC結(jié)束,GC完成后,才可以繼續(xù)運(yùn)行,所以Local GC可以減少因GC帶來的系統(tǒng)吞吐量下降的影響。

發(fā)生堆空間分配失敗或者調(diào)用System.gc()方法后,觸發(fā)Global GC過程。Global GC通過標(biāo)記、清除、壓縮過程來盡可能釋放JVM內(nèi)存空間。Global GC需要獲得整個(gè)JVM的排他控制權(quán),所以當(dāng)進(jìn)行Global GC時(shí),所有應(yīng)用線程也將暫停。當(dāng)Global GC結(jié)束后,應(yīng)用線程將恢復(fù)執(zhí)行。

3 常見的WAS內(nèi)存溢出原因

上面我們介紹了IBM Java內(nèi)存管理的模型和策略。理解上述模型后,我們可以清楚的知道為何會(huì)發(fā)生內(nèi)存溢出:

(1)JVM內(nèi)部或者JVM間接使用的操作系統(tǒng)內(nèi)存分配失敗后觸發(fā)內(nèi)存溢出報(bào)錯(cuò)。JVM內(nèi)存區(qū)域中,除了程序計(jì)數(shù)器區(qū)域外,Java虛擬機(jī)棧、堆空間、方法區(qū)、運(yùn)行時(shí)常量池、本地方法棧都可能會(huì)發(fā)生內(nèi)存溢出報(bào)錯(cuò)。

(2)對于堆空間,當(dāng)堆空間已經(jīng)盡可能擴(kuò)展,并且JVM花費(fèi)了95%以上的時(shí)間在GC時(shí),也會(huì)觸發(fā)內(nèi)存溢出報(bào)錯(cuò)。

以上兩點(diǎn)是內(nèi)存溢出的基本要點(diǎn),但實(shí)際生產(chǎn)系統(tǒng)由于運(yùn)行環(huán)境往往較為復(fù)雜,在處理實(shí)際問題時(shí),我們還應(yīng)結(jié)合環(huán)境配置和業(yè)務(wù)場景來分析。通過總結(jié)實(shí)際運(yùn)維過程中經(jīng)驗(yàn),可以將內(nèi)存溢出原因分為如下幾類:

(1)堆內(nèi)存大小上限配置過低
由于Java程序所能使用的堆空間上限完全取決于JVM啟動(dòng)時(shí)的參數(shù)配置,當(dāng)堆空間上限參數(shù)設(shè)置過低,即使操作系統(tǒng)物理內(nèi)存空閑較多,應(yīng)用程序也無法使用。所以在問題排查時(shí),我們首先應(yīng)該明確系統(tǒng)配置的堆空間上限(由Xmx參數(shù)指定),一般不能使用堆大小上限默認(rèn)值。

(2)程序內(nèi)存泄漏導(dǎo)致內(nèi)存持續(xù)增長
如果程序存在內(nèi)存泄漏,即使已經(jīng)不再使用的內(nèi)存仍將無法被GC回收釋放,JVM內(nèi)存將持續(xù)增長(而且,由于內(nèi)存使用率逐漸升高,將會(huì)更加頻繁的觸發(fā)GC,反復(fù)GC又會(huì)引發(fā)CPU過高),最終導(dǎo)致堆內(nèi)存空間滿而引發(fā)內(nèi)存溢出。

(3)數(shù)據(jù)查詢交易返回記錄數(shù)過多或者程序申請使用大內(nèi)存對象
當(dāng)程序過度地使用內(nèi)存大對象或數(shù)組,導(dǎo)致無法申請足夠的內(nèi)存空間而引發(fā)內(nèi)存溢出。例如,在實(shí)際生產(chǎn)中,可能存在應(yīng)用程序讀取整表數(shù)據(jù)或情況(數(shù)據(jù)條數(shù)在幾萬條以上),極易引發(fā)內(nèi)存溢出。

(4)物理內(nèi)存過低或因其他進(jìn)程消耗過多內(nèi)存引發(fā)內(nèi)存溢出
即使我們設(shè)定了合理的JVM內(nèi)存空間大小上限,但也有可能因?yàn)楸镜夭僮飨到y(tǒng)本身可用內(nèi)存過低、無法實(shí)現(xiàn)內(nèi)存空間的動(dòng)態(tài)擴(kuò)充,進(jìn)而導(dǎo)致內(nèi)存溢出;也可能因?yàn)樵谕粋€(gè)操作系統(tǒng)上運(yùn)行的其他JVM或者本地進(jìn)程使用過多的內(nèi)存導(dǎo)致內(nèi)存溢出;由于JVM的部分區(qū)域(如Metaspace、DirectMemory等)直接使用的是操作系統(tǒng)內(nèi)存,所以當(dāng)操作系統(tǒng)內(nèi)存過低,但創(chuàng)建本地線程過多、加載類過多時(shí)也有可能發(fā)生內(nèi)存溢出異常;當(dāng)程序過度使用DirectMemory也會(huì)引發(fā)內(nèi)存溢出。

(5)交易量突然增大
如果我們將JVM堆內(nèi)存上限設(shè)為M,每支交易處理需要使用的堆內(nèi)存是N,那么當(dāng)同時(shí)處理的交易量X突然增多N*X>M時(shí),就容易觸發(fā)內(nèi)存溢出。

4 如何優(yōu)雅的應(yīng)對WAS內(nèi)存溢出

當(dāng)發(fā)生內(nèi)存溢出后,首先要做的是恢復(fù)生產(chǎn),恢復(fù)因內(nèi)存溢出而宕機(jī)的Server?;謴?fù)生產(chǎn)后,可按照下面步驟進(jìn)行內(nèi)存溢出原因分析。

收集環(huán)境信息
內(nèi)存溢出分析首先要做的就是收集環(huán)境信息和日志信息。

收集日志文件

表 1 收集日志文件表
讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

分析應(yīng)用日志
查看SystemOut.log日志java.lang.OutOfMemoryError的提示信息,確定內(nèi)存溢出發(fā)生在JVM的哪個(gè)區(qū)域之后,查看SystemOut.log、SystemErr.log中應(yīng)用交易日志,分析是否可疑的異常交易。

分析堆內(nèi)存使用趨勢
一般內(nèi)存分析,第一步先查看JVM內(nèi)存使用情況,即通過“IBM Pattern Modeling and Analysis Tool for Java Garbage Collector”工具,打開native_stderr.log文件,查看JVM堆空間內(nèi)存使用曲線:

對于大對象或數(shù)組使用導(dǎo)致內(nèi)存溢出的曲線一般如下圖所示,存在曲線突然升高的情況:

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖5 大對象內(nèi)存溢出堆空間趨勢圖

內(nèi)存泄漏導(dǎo)致內(nèi)存溢出的曲線一般如下圖所示,曲線緩慢上升(紅色曲線):

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖6 內(nèi)存泄漏程序堆空間趨勢圖

找到堆空間可疑內(nèi)存溢出點(diǎn)

 

使用IBM HeapAnalyzer工具分析Heapdump文件。HeapAnalyzer工具列出了可疑的內(nèi)存溢出點(diǎn),分析人員需要逐個(gè)對這些可疑點(diǎn)進(jìn)行排查,結(jié)合程序代碼進(jìn)行進(jìn)一步確認(rèn)。

 

分析線程現(xiàn)場信息
使用“IBM Thread and Monitor Dump Analyzer for Java”工具,分析javacore文件。檢查內(nèi)存溢出時(shí)正在執(zhí)行的交易、正在執(zhí)行的方法。

非堆空間內(nèi)存溢出
如果出現(xiàn)“java.lang.OutOfMemoryError: 本機(jī)內(nèi)存耗盡”內(nèi)存溢出報(bào)錯(cuò),則需要考慮DirectByteBuffer內(nèi)存區(qū)域引發(fā)內(nèi)存溢出。

5 如何在具體場景應(yīng)用

 

上面白話了那么多,想必各位已經(jīng)頭暈眼花,那么接下來就來點(diǎn)干貨。在具體的運(yùn)維場景中,銀行運(yùn)維人員該如何快速分析和定位WAS內(nèi)存溢出的問題呢,讓筆者來結(jié)合自己遇到的某個(gè)實(shí)際場景進(jìn)行闡述。
某次筆者正在優(yōu)雅的喝著咖啡,寫著工作總結(jié),忽然接到監(jiān)控告警通知,“XX管理系統(tǒng)交易超時(shí)率提高,請盡快處置”。筆者一陣激靈,趕快扔下咖啡跑進(jìn)操作間開始排查系統(tǒng)問題。
第一步,當(dāng)然是盡快恢復(fù)生產(chǎn)嘍,筆者排查時(shí),通過監(jiān)控發(fā)現(xiàn)某臺WAS服務(wù)器內(nèi)存直沖天際,隱隱有突破內(nèi)存限制的隱患,而就在同時(shí),交易超時(shí)的情況開始同時(shí)升高?;疽呀?jīng)能定位問題是由于內(nèi)存原因?qū)е碌?,那么為了盡快恢復(fù)生產(chǎn),筆者當(dāng)然是首先選擇對故障服務(wù)器的WAS應(yīng)用進(jìn)行了重啟。

 

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖7:發(fā)生問題時(shí)某臺WAS服務(wù)器的內(nèi)存監(jiān)控情況

 

第二步,重啟大法果然不出意外的解決了問題,重啟WAS應(yīng)用后系統(tǒng)交易超時(shí)指標(biāo)恢復(fù)了正常。接下來,筆者就要認(rèn)真排查問題,到底是什么導(dǎo)致了這次內(nèi)存意外的沖高呢。筆者開始著手采集分析文件,主要包括SystemOut.log(輸出日志)、SystemErr.log(錯(cuò)誤日志)、native_stderr.log(GC日志),在采集時(shí),筆者還在日志目錄中發(fā)現(xiàn)了Javacore文件與Heapdump文件,這已經(jīng)能確認(rèn)是發(fā)生了內(nèi)存溢出,下面的問題就是分析原因了。

 

第三步,首先我們來查看日志文件,下面分別是SystemOut.log和SystemErr.log的部分內(nèi)容。果然,在問題時(shí)點(diǎn)附近的錯(cuò)誤日志中看到了OutOfMemoryError,同時(shí)在應(yīng)用日志中看到了一些正在執(zhí)行的sql,那么到底是哪個(gè)程序在作怪,又是為什么產(chǎn)生了內(nèi)存溢出呢。

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖8:問題時(shí)點(diǎn)的應(yīng)用日志

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖9:問題時(shí)點(diǎn)的錯(cuò)誤日志

第四步,看來僅從日志是無法定位具體問題的,筆者接下來要運(yùn)用工具來解決問題了。筆者先后用IBM HeapAnalyzer和IBM Thread and Monitor Dump Analyzer for Java工具,分別對Heapdump文件及Javacore文件進(jìn)行了具體的分析。對Heapdump文件的解析結(jié)果顯示,某個(gè)List居然存在68萬多個(gè)對象,占用了近50%的內(nèi)存空間。對Javacore文件的分析結(jié)果顯示,發(fā)生溢出時(shí)某支交易線程一直處于等待狀態(tài)。

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖10:Heapdump文件的分析結(jié)果

讓人頭疼的WAS內(nèi)存溢出,銀行運(yùn)維人員該如何優(yōu)雅的解決

圖11:Heapdump文件的分析結(jié)果

 

第五步,有了這么豐富的信息,筆者已經(jīng)做出了基本的判斷,本次WAS內(nèi)存溢出應(yīng)該是由于某線程在一次查詢時(shí)獲取了太多數(shù)據(jù),導(dǎo)致JVM為裝載這些數(shù)據(jù)的List對象分配了過多內(nèi)存,從而導(dǎo)致的內(nèi)存溢出。筆者將信息反饋給開發(fā)人員后,果然沒多久就得到確認(rèn),確實(shí)是某條查詢語句未對查詢結(jié)果進(jìn)行分頁處理,一次性命中過多查詢結(jié)果后將其全部裝入內(nèi)存導(dǎo)致。
至此,筆者的這次應(yīng)急處置與事件分析工作告了一段落,筆者心滿意足的回到工位,繼續(xù)開始喝咖啡,寫總結(jié),優(yōu)雅的等待下班的到來,相信開發(fā)人員修復(fù)這個(gè)隱藏缺陷后,筆者又可以清凈一段時(shí)間了。

 

6 如何預(yù)防或解決內(nèi)存溢出問題

 

經(jīng)過上面一番講解,相信對于WAS內(nèi)存溢出的分析,無論是理論還是實(shí)踐大家都有了一定的認(rèn)識,那么,我們?nèi)绾文茴A(yù)防或避免這種問題呢。筆者進(jìn)行了一些簡答的總結(jié)。
對于物理內(nèi)存不足或者堆空間上限配置不足的情況,需要評估合適的物理內(nèi)存或者堆空間上限大小,進(jìn)行擴(kuò)充。需要注意的是32位WAS最大堆內(nèi)存上限為1536MB,如果需要升級到更大內(nèi)存,則需要遷移到64位WAS平臺。另外,堆內(nèi)存空間并不是越大越好,越大的內(nèi)存意味著GC管理也越復(fù)雜,GC的耗時(shí)及應(yīng)用程序停頓的時(shí)間也越長。
對于存在內(nèi)存泄漏或者是大對象申請情況引發(fā)的內(nèi)存溢出,一般需要在定位問題原因后,在測試環(huán)境復(fù)現(xiàn)問題,進(jìn)行程序優(yōu)化解決問題。程序優(yōu)化的方法不一而足,例如存在大數(shù)據(jù)量數(shù)據(jù)查詢的情況可以加入篩選條件或者增加分頁處理;也可以暫時(shí)規(guī)避解決的方式,通過關(guān)閉發(fā)生問題的交易或者修改交易流程不觸發(fā)內(nèi)存溢出的場景來臨時(shí)性解決問題。

 

7 最后

 

以上就是筆者總結(jié)的如何優(yōu)雅的應(yīng)對WAS內(nèi)存溢出的全部內(nèi)容了,WAS作為一款企業(yè)級Web中間件,至少目前在國內(nèi)銀行、證券等大型國企中還占據(jù)著主導(dǎo)地位,了解WAS知識有助于我們在生產(chǎn)運(yùn)維過程中高效解決問題,提高應(yīng)急處置效率,后續(xù)筆者會(huì)繼續(xù)總結(jié)在日常運(yùn)維過程中碰到的問題,跟大家共同分享和交流。

 

 

 

責(zé)任編輯:張燕妮 來源: 高效運(yùn)維
相關(guān)推薦

2021-10-09 09:47:14

Java開發(fā) bug

2017-10-20 12:00:36

Python全局解釋器鎖GIL

2023-04-19 09:05:44

2017-12-12 13:27:20

主板跳線USB

2019-07-03 15:01:30

戴爾

2024-09-09 09:41:03

內(nèi)存溢出golang開發(fā)者

2017-07-14 14:52:25

MySQLAborted告警案例分析

2020-11-30 14:40:52

事務(wù)系統(tǒng)項(xiàng)目

2010-04-08 13:17:39

IT管理系統(tǒng)遷移賽門鐵克

2010-11-16 09:07:32

2009-06-16 11:01:14

Java內(nèi)存溢出

2022-05-19 12:14:22

分布式開發(fā)框架

2021-11-15 06:56:45

系統(tǒng)運(yùn)行空指針

2012-03-14 10:58:27

Java

2021-06-28 06:45:06

內(nèi)存溢出內(nèi)存泄露JavaScript

2019-01-08 08:50:56

2009-12-08 15:37:39

2021-12-06 09:57:25

容器Linux信號

2021-05-09 22:26:36

Python函數(shù)變量

2012-05-15 02:04:22

JVMJava
點(diǎn)贊
收藏

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