日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

每天億級數據量的日志清洗系統,從Kafka不停消費各種日志數據,然后對日志格式進行各種清洗,如對敏感信息字段(姓名、手機號、身份證號)進行脫敏,再把清洗后數據給其它系統,如推薦系統、廣告系統、分析系統都會去使用這些清洗好的數據。

OOM 現場

某天我們也是突然收到線上的報警,發現日志清洗系統發生OOM。第一時間登錄到線上機器,查看日志,經典日志

 JAVA.lang.OutOfMemoryError: java heap space

堆內存溢出。套路應該很熟了。

先看異常日志,定位啥導致的問題,日志里看到了:

 java.lang.OutOfMemoryError: java heap space xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.process() xx.xx.xx.log.clean.XXClass.xx() xx.xx.xx.log.clean.XXClass.xx()

似乎同樣的一個方法(XXClass.process())反復出現,最終導致堆內存溢出。

再仔細分析日志,代碼出現大量遞歸操作,正是這大量遞歸,導致堆內存溢出。接著自然就是MAT分析內存快照。

初步分析內存快照

雖然日志能看到哪個方法導致內存溢出,但不知道到底哪個方法調用創建的大量對象。因此還得用MAT分析。

因大量XXClass.process()遞歸執行,每個XXClass.process()中都創建了大量char數組,最后因XXClass.process()又多次遞歸調用,也就導致大量的char[]數組耗盡內存:

億級流量的數據清洗系統OOM排查實戰

 

JVM參數問題?

基本定位出問題了,但先別急直接去代碼檢查問題,因為發現了比較大問題。

雖然XXClass.process()遞歸調用多次,但實際上我們在MAT中發現遞歸調用的次數也不多,最多幾十次。所有遞歸調用加起來創建的char[]數組對象總和其實也最多1G。

可能這次OOM發生不一定是代碼寫的爛,可能就是JVM 內存參數不對,給堆內存分配太少。

分析GC日志

要知道堆內存是不是設小了,就得分析JVM運行時的內存使用模型。

現在宕機了,唯一能看到的,就是當時在JVM啟動參數中加入的自動記錄的GC日志。

從GC日志中,可見JVM啟動時的完整參數設置:

 -Xmx1024m
 -Xms1024m
 -XX:+PrintGCDetails
 -XX:+PrintGC()
 -XX:+HeapDumpOnOutOfMemoryError
 -Xloggc:/opt/logs/gc.log 
 -XX:HeapDumpPath=/opt/logs/dump

這里主要是把gc日志詳細記錄在了一個日志文件,另外指定OOM時要導出內存快照,堆內存1G,但這臺機器可是4核8G!

記錄下來的gc.log日志:

 [Full GC (Allocation Failure) 866M->654M(1024M)]
 [Full GC (Allocation Failure) 843M->633M(1024M)] 
 [Full GC (Allocation Failure) 855M->621M(1024M)] 
 [Full GC (Allocation Failure) 878M->612M(1024M)]

因Allocation Failure觸發的Full GC很多,即堆內存無法創建新對象,然后觸發GC,結果觸發時肯定先觸發Full GC了。發現每次Full GC都只回收一點點對象,堆內存幾乎都占滿的。

日志顯示的是每s都會執行一次Full GC,這就絕了。應該是在系統運行時,因為XXClass.process()不停遞歸創建大量char[]數組,導致堆內存幾乎滿。

然后導致連續一段時間,每s觸發一次Full GC,因為內存都滿了,特別是Old可能幾乎都滿了,所以可能每s執行YGC前,發現Old可用空間不足,就會提前觸發Full GC。

億級流量的數據清洗系統OOM排查實戰

 

也可能YGC后,存活對象太多無法放入Survivor,而都要進入Old,也放不下了,只能Full GC。但每次full gc只能回收少量對象,直到最后可能某次full gc回收不掉任何對象了,然后新的對象無法放入堆內存了,就觸發OOM了:

億級流量的數據清洗系統OOM排查實戰

 

明顯就是堆內存偏小了,導致頻繁full gc。

分析一下JVM運行時內存使用模型

接著jstat分析當時JVM運行時的內存模型,當時重啟系統,每s打印一次:

 S0 S1 E O YGC FGC
 
 0 100 57 69 36 0
 
 0 100 57 69 36 0
 
 0 100 65 69 37 0
 
 0 100 0 99 37 0
 
 0 100 0 87 37 1

我就給出部分信息大家就可以看出來問題所在了,剛開始都是Eden在漲,接著YGC從36到37,發生了一次YGC,Old直接從69%到99%。

why?

YGC后存活對象太多,Survivor放不下,直接進了Old!接著Old都占99%了,直接觸發一次Full GC,但也僅讓Old從99%到87%,只回收少量對象。

該過程反復循環了幾次,年輕代對象反復進入老年代,不停觸發Full GC,但是還回收不了多少對象,幾次循環過后,老年代滿了,可能Full GC沒回收多少對象,新的對象一大批放不下了,就觸發OOM了。

優化第一步:加大堆內存

所以這OOM,不能一口說是代碼問題,從JVM運行情況及內存大小來看,其實是內存分配不足問題。

第一步,直接在4核8G的機器上,加大堆內存,直接給堆5G。

接著運行系統,jstat發現,每次YGC過后存活對象都落入Survivor區域了,不會隨便進入老年代,而且因為堆內存很大,基本上運行一段時間不會發生OOM問題了。

優化第二步:改寫代碼

讓他不要占用過多內存。代碼之所以遞歸,是因為在一條日志中,可能出現很多用戶的信息,一條日志也許會合并包含了十幾個到幾十個用戶的信息。

這時代碼中就是會遞歸處理日志,每次遞歸都會產生大量char[]數組,是切割了日志用來處理的。

這代碼寫的完全沒必要,因為對每一條日志,若發現包含多個用戶的信息,就對這一條日志切割出來進行處理,沒必要遞歸調用,每次調用都切割一次日志,生成大量char[]數組。

該步代碼優化后,線上系統的內存使用情況降低10倍以上。

總結

先通過OOM的排查方法去分析,發現主要是內存太小導致的問題然后用gc日志和jstat分析,明顯發現是內存不夠用了,最后加大系統內存,并優化代碼即可。

分享到:
標簽:清洗 數據
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定