20170718一次內(nèi)存溢出排查經(jīng)歷

一、好言

熬得住就出眾,熬不住就出局关串,相信糟糕得日志熬過去了拧廊,剩下得就是好運氣 。


二晋修、背景

上周一晚上十點多吧碾,就開始MQ消息累積然后報警,運維早上找我看墓卦,那些消息累積了倦春,然后運維重啟服務(wù)后消息就消費了,然后過一會又累積了落剪,到上午十一點多的時候睁本,開始報內(nèi)存過高,然后發(fā)現(xiàn)已經(jīng)又兩臺服務(wù)已經(jīng)掛了忠怖,看了日志呢堰,有錯誤,但是沒有很多可用的錯誤凡泣。所以重啟枉疼,吃完飯服務(wù)又掛了,jconsole看到結(jié)果如下圖:

jconsole-1.png

然后下午的時候內(nèi)存的爆發(fā)簡直更加頻繁了


jsonsole-2

三:解決

3.1鞋拟、內(nèi)容

出現(xiàn)內(nèi)存溢出問題骂维,所以肯定首要需要dump內(nèi)存溢出文件,所以先讓運維導(dǎo)出*.hprof 文件贺纲,然后我也查看日志文件航闺,我們使用kibana進行日志統(tǒng)計了,所以查看其中錯誤日志猴誊,的確又很多錯誤的信息潦刃,redis錯誤,MQ錯誤稠肘,還有mysql錯誤福铅。

org.springframework.dao.QueryTimeoutException: Redis command timed out; nested exception is com.lambdaworks.redis.RedisCommandTimeoutException: Command timed out
    at org.springframework.data.redis.connection.lettuce.LettuceExceptionC
onverter.convert(LettuceExceptionConverter.java:66)
    at org.springframework.data.redis.connection.lettuce.LettuceExceptionC
onverter.convert(LettuceExceptionConverter.java:41)
    at org.springframework.data.redis.PassThroughExceptionTranslationStr
ategy.translate(PassThroughExceptionTranslationStrategy.java:37)
[ActiveMQ Transport: tcp://mqtest.com/10.10.10.10:6161@123] org.apache.activemq.transport.failover.FailoverTransport - Transport (tcp://mqtest.com/10.10.10.10:6161) failed, attempting to automatically reconnect
java.io.IOException: Unexpected error occurred: java.lang.OutOfMemoryError: Java heap space
    at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:222)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.OutOfMemoryError: Java heap space

如上兩個認(rèn)為是內(nèi)存溢出了萝毛,造成沒有內(nèi)存可使用沒法開線程處理项阴。
看看下面mysql錯誤

### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackExceptio
n: Lock wait timeout exceeded; try restarting transaction
; SQL []; Lock wait timeout exceeded; try restarting transaction; 
nested exception is 
com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackExceptio
n: Lock wait timeout exceeded; try restarting transaction
    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTransl
ator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:259)
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTran
slator.translate(AbstractFallbackSQLExceptionTranslator.java:73)
    at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfP
ossible(MyBatisExceptionTranslator.java:74)
    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke
(SqlSessionTemplate.java:421)
    at com.sun.proxy.$Proxy31.update(Unknown Source)
    at org.mybatis.spring.SqlSessionTemplate.update(SqlSessionTemplate.j
ava:270)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:55)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:53)
    at com.sun.proxy.$Proxy55.updateByPrimaryKey(Unknown 
Source)
    at com.mouse.moon.app.service.Userervice.update(
UserService.java:26)
    at com.mouse.moon.app.service.Userervice$$FastClassBySpringCGLIB$$3eb1bfc8.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.
proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSuppor
t.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.inv
oke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proc
eed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvised
Interceptor.intercept(CglibAopProxy.java:655)
    at com.mouse.moon.app.service.UserService$$EnhancerBySpringCGLIB$$31a8197.update(<generated>)
    at com.mouse.moon.app.service.userService.dealUser(MobileAppRegisterService.java:154)
    at com.mouse.moon.app.service.UserService.(userService.java:104)
    at com.mouse.moon.app.service.UserService$$FastClassBySpringCGLIB$$a99b8cf4.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:720)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
    at com.mysql.jdbc.Util.getInstance(Util.java:387)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:946)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3878)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3814)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2478)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2625)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2551)
    at com.mysql.jdbc.MultiHostMySQLConnection.execSQL(MultiHostMySQLConnection.java:157)
    at sun.reflect.GeneratedMethodAccessor306.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.mysql.jdbc.LoadBalancedConnectionProxy.invokeMore(LoadBalancedConnectionProxy.java:484)
    at com.mysql.jdbc.MultiHostConnectionProxy.invoke(MultiHostConnectionProxy.java:452)
    at com.sun.proxy.$Proxy63.execSQL(Unknown Source)
    at com.mysql.jdbc.MultiHostMySQLConnection.execSQL(MultiHostMySQLConnection.java:157)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
    at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1192)
    at sun.reflect.GeneratedMethodAccessor314.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.mysql.jdbc.MultiHostConnectionProxy$JdbcInterfaceProxy.invoke(MultiHostConnectionProxy.java:103)
    at com.sun.proxy.$Proxy68.execute(Unknown Source)

這個地方的錯誤我在網(wǎng)上也搜過,其實基本是鎖等待超時問題,這個一個同事之前遇到過环揽,跟他交流了下略荡,這個錯誤說明我的事物太大了,造成事物等待超時歉胶,并且有查處和更新相同數(shù)據(jù)造成的汛兜。這個現(xiàn)在想想這里代碼的業(yè)務(wù)邏輯的確是存在這種問題,由于數(shù)據(jù)量大通今,如果按照現(xiàn)在的查詢條件粥谬,地區(qū)會查詢出相同數(shù)據(jù),并且由于事物放在servicec層辫塌,在for循環(huán)中update數(shù)據(jù)的時候漏策,會造成事物最后一起提交,所以造成鎖等待超時問題臼氨。所以最后更新代碼業(yè)務(wù)如下
1:對查詢代碼順序做優(yōu)化

List list = ...
if(符合條件){
   list = ...(select ...where)
}

由于數(shù)據(jù)庫數(shù)據(jù)量有4500w左右掺喻,上述代碼先查詢,然后再判斷條件储矩,所以有可能會查詢兩次數(shù)據(jù)庫感耙,所以代碼優(yōu)化,處理代碼順序持隧,先判斷條件即硼。

2:對加在service的事物移動到dao層,每次更新一次提交一次屡拨,把事物縮小谦絮。

3:對于一些處理可以做異步處理

4:做限流操作(使用hystrix做限流)

5:<a href ="http://www.reibang.com/p/82c27c58e0b6">對消費做消費速度限制</a>

3.2:dump文件分析
由于之前系統(tǒng)是假死狀態(tài),每次沖上去之后洁仗,過十幾分鐘或者半小時后层皱,可能又會慢慢回收。所以每次爆的時候并沒有dump文件赠潦,<a href="http://www.reibang.com/p/05e9f46e3f09">腳本</a>
每次沒dump,最后我們在內(nèi)存上升期間叫胖,只用使用

#查看內(nèi)存
jmap -heap pid 
jmap -dump:format=b,file=$dumpfile pid
圖片.png

導(dǎo)出文件,查看如下

圖1.png

上圖是在沒有處理完sql錯誤時倒出的hprof文件她奥。
下圖是處理完sql異常導(dǎo)出的文件
圖2.png

圖二我們可以看到一個很大的對象瓮增,就是我畫紅色的部分,點進去看哩俭,有三百多萬個對象绷跑,占用內(nèi)存三百多兆,并且我們看到老年代使用的量特別大凡资,基本沒回收樣砸捏。怎么會有這么大的對象了,根據(jù)對象我們找到代碼位置,確定是查詢問題垦藏,造成大量對象產(chǎn)生梆暖,并且也是之前大量更新,并且數(shù)據(jù)有重復(fù)的概率掂骏,所以造成占用大量內(nèi)存轰驳。其實這種發(fā)生也是要有數(shù)據(jù)量的情況下才會出現(xiàn),發(fā)生溢出.

下面幾張是檢測到的日志信息數(shù)據(jù):


log-1.png
log-2.png
log-3.png

最后簡單總結(jié)下處理的過程弟灼,首先需要排除所有可能造成該問題的問題级解,也就是先解決掉看到的錯誤,然后查看導(dǎo)出dump文件中的大對象田绑,根據(jù)大對象查看代碼蠕趁,進一步分析問題。其實在這個中間辛馆,做了很多各種處理看效果俺陋,比如MQ限流消費處理等。但是現(xiàn)在看來昙篙,最終原因應(yīng)該還是出在數(shù)據(jù)庫層面腊状。

四:感觸

其實之前沒怎么解決過內(nèi)存溢出問題,這算是自己第一次全程經(jīng)歷此次內(nèi)存溢出并解決苔可,不過首先說缴挖,這代碼并不是我寫的代碼,是我被按排接手的項目焚辅,所以還的感謝這之前寫這代碼的人映屋,才使得我有這么一次經(jīng)歷,通過這次經(jīng)歷同蜻,也會讓自己對于一個內(nèi)存溢出問題的解決思路更佳清晰棚点,思考問題更佳全面,處理問題更佳穩(wěn)重湾蔓,并且對于一些工具的使用瘫析,比如MAT,Jprofile有了接觸默责。所以有些經(jīng)歷真的是不可求的贬循。因此才有了經(jīng)驗之說。努力吧桃序,騷年杖虾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市媒熊,隨后出現(xiàn)的幾起案子奇适,更是在濱河造成了極大的恐慌坟比,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滤愕,死亡現(xiàn)場離奇詭異,居然都是意外死亡怜校,警方通過查閱死者的電腦和手機间影,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茄茁,“玉大人魂贬,你說我怎么就攤上這事∪雇纾” “怎么了付燥?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長愈犹。 經(jīng)常有香客問我键科,道長,這世上最難降的妖魔是什么漩怎? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任勋颖,我火速辦了婚禮,結(jié)果婚禮上勋锤,老公的妹妹穿的比我還像新娘饭玲。我一直安慰自己,他們只是感情好叁执,可當(dāng)我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布茄厘。 她就那樣靜靜地躺著,像睡著了一般谈宛。 火紅的嫁衣襯著肌膚如雪次哈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天吆录,我揣著相機與錄音亿乳,去河邊找鬼。 笑死径筏,一個胖子當(dāng)著我的面吹牛葛假,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播滋恬,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聊训,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恢氯?” 一聲冷哼從身側(cè)響起带斑,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鼓寺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后勋磕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妈候,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年挂滓,在試婚紗的時候發(fā)現(xiàn)自己被綠了苦银。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赶站,死狀恐怖幔虏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贝椿,我是刑警寧澤想括,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站烙博,受9級特大地震影響瑟蜈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渣窜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一踪栋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧图毕,春花似錦夷都、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛤虐,卻和暖如春党饮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背驳庭。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工刑顺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饲常。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓蹲堂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贝淤。 傳聞我的和親對象是個殘疾皇子柒竞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,960評論 2 355

推薦閱讀更多精彩內(nèi)容