簡介: 我們穿過山和大海,也見過人山人海。我們見過各類故障,也排過千雷萬險。這一次,不如我們一起,開啓穩定性的探索之旅。讓無法解決的問題少一點點,讓世界的確定性多一點點。無論是前端業務的開發者,還是後端架構的開發者,都會遇到業務穩定性的難題。
我們穿過山和大海,也見過人山人海。
我們見過各類故障,也排過千雷萬險。
這一次,不如我們一起,開啓穩定性的探索之旅。
讓無法解決的問題少一點點,讓世界的確定性多一點點。
無論是前端業務的開發者,還是後端架構的開發者,都會遇到業務穩定性的難題。但穩定性的話題涉及之廣、之深,很難通過一兩篇文章道清原委。因此,我們集結了多位阿里技術工程師,他們來自性能壓測、故障演練、JVM、應用容器、服務框架、流量調度、監控、診斷等不同的技術領域,以更結構化的方式來打造穩定性領域的知識庫,該知識庫的目錄將分爲:
- 事前規範:代碼規約、變更管控、性能壓測、故障演練、風險預案、限流降級、業務隔離;
- 事中“止血”:監控、告警、異常巡檢、流量調度;
- 事後診斷:系統診斷、JVM診斷、組件診斷、在線診斷、鏈路追蹤、Root cause;
但我們也深知,僅憑阿里自身的業務場景和技術積累,很難滿足各行業不同業務場景下對穩定性知識和經驗獲取的需求,因此,我們將以開源的方式進行共建,歡迎您將自己或所在企業在穩定性方面的實踐分享給更多的人,讓無法解決的問題少一點,讓世界的確定性多一點:
- 開源項目名稱:StabilityGuide
- 參與方式:
- 提 issue:將您遇到的穩定性難題詳細的描述出來;
- 寫文章:申領目錄中的某個主題,分享您或所在企業在穩定性方面的實踐;
- 其他:您認爲對『StabilityGuide』的建設有幫助的建議;
- 項目地址,點擊這裏!
- 釘釘交流羣:23179349
歡迎在文末,寫下你的留言,隨機抽3位,送出紀念衫套裝( Polo 衫 & T恤,共計兩件)。
以下是來自『StabilityGuide』的第一篇文章:《系統穩定性——OutOfMemoryError 常見原因及解決方法》。
當 JVM 內存嚴重不足時,就會拋出 java.lang.OutOfMemoryError 錯誤。本文總結了常見的 OOM 原因及其解決方法,如下圖所示。如有遺漏或錯誤,歡迎補充指正。
如果對 JVM 內存模型和垃圾回收機制不熟悉,推薦閱讀 《咱們從頭到尾說一次 Java 垃圾回收》。
Java heap space
當堆內存(Heap Space)沒有足夠空間存放新創建的對象時,就會拋出 java.lang.OutOfMemoryError: Java heap space 錯誤(根據實際生產經驗,可以對程序日誌中的 OutOfMemoryError 配置關鍵字告警,一經發現,立即處理)。
原因分析
Java heap space 錯誤產生的常見原因可以分爲以下幾類:
- 請求創建一個超大對象,通常是一個大數組。
- 超出預期的訪問量/數據量,通常是上游系統請求流量飆升,常見於各類促銷/秒殺活動,可以結合業務流量指標排查是否有尖狀峯值。
- 過度使用終結器(Finalizer),該對象沒有立即被 GC。
- 內存泄漏(Memory Leak),大量對象引用沒有釋放,JVM 無法對其自動回收,常見於使用了 File 等資源沒有回收。
解決方案
針對大部分情況,通常只需要通過 -Xmx 參數調高 JVM 堆內存空間即可。如果仍然沒有解決,可以參考以下情況做進一步處理:
- 如果是超大對象,可以檢查其合理性,比如是否一次性查詢了數據庫全部結果,而沒有做結果數限制。
- 如果是業務峯值壓力,可以考慮添加機器資源,或者做限流降級。
- 如果是內存泄漏,需要找到持有的對象,修改代碼設計,比如關閉沒有釋放的連接。
GC overhead limit exceeded
當 Java 進程花費 98% 以上的時間執行 GC,但只恢復了不到 2% 的內存,且該動作連續重複了 5 次,就會拋出 java.lang.OutOfMemoryError:GC overhead limit exceeded 錯誤。簡單地說,就是應用程序已經基本耗盡了所有可用內存, GC 也無法回收。
此類問題的原因與解決方案跟 Java heap space 非常類似,可以參考上文。
Permgen space
該錯誤表示永久代(Permanent Generation)已用滿,通常是因爲加載的 class 數目太多或體積太大。
原因分析
永久代存儲對象主要包括以下幾類:
- 加載/緩存到內存中的 class 定義,包括類的名稱,字段,方法和字節碼;
- 常量池;
- 對象數組/類型數組所關聯的 class;
- JIT 編譯器優化後的 class 信息。
PermGen 的使用量與加載到內存的 class 的數量/大小正相關。
解決方案
根據 Permgen space 報錯的時機,可以採用不同的解決方案,如下所示:
- 程序啓動報錯,修改 -XX:MaxPermSize 啓動參數,調大永久代空間。
- 應用重新部署時報錯,很可能是沒有應用沒有重啓,導致加載了多份 class 信息,只需重啓 JVM 即可解決。
- 運行時報錯,應用程序可能會動態創建大量 class,而這些 class 的生命週期很短暫,但是 JVM 默認不會卸載 class,可以設置 -XX:+CMSClassUnloadingEnabled 和 -XX:+UseConcMarkSweepGC 這兩個參數允許 JVM 卸載 class。
如果上述方法無法解決,可以通過 jmap 命令 dump 內存對象 jmap -dump:format=b,file=dump.hprof ,然後利用 Eclipse MAT 功能逐一分析開銷最大的 classloader 和重複 class。
Metaspace
JDK 1.8 使用 Metaspace 替換了永久代(Permanent Generation),該錯誤表示 Metaspace 已被用滿,通常是因爲加載的 class 數目太多或體積太大。
此類問題的原因與解決方法跟 Permgen space 非常類似,可以參考上文。需要特別注意的是調整 Metaspace 空間大小的啓動參數爲 -XX:MaxMetaspaceSize。
想看完整文章內容:點擊這裏
原文出處:阿里雲大學開發者社區
作者信息:夏明,GitHub ID @StabilityMan,花名涯海,阿里雲 ARMS & EagleEye 技術專家,2016 年加入阿里巴巴,一直從事鏈路追蹤和 APM 監控診斷領域的相關工作。