做者 | Mason MAgit
【Arthas 官方社區正在舉行徵文活動,參加即有獎品拿哦~點擊投稿】github
Arthas 是個不錯的工具,這裏要再安利一波,固然整個過程還用到了其餘工具,如 MAT、YourKIT(這個是付費的),結合起來使用更加便於發現和解決問題。期間還和開發大佬屢次溝通,分別獲取了不一樣的信息。小程序
Cloud Toolkit 是阿里雲發佈的免費本地 IDE 插件,幫助開發者更高效地開發、測試、診斷並部署應用。經過插件,能夠將本地應用一鍵部署到任意服務器,甚至雲端(ECS、EDAS、ACK、ACR 和 小程序雲等);而且還內置了 Arthas 診斷、Dubbo工具、Terminal 終端、文件上傳、函數計算 和 MySQL 執行器等工具。不只僅有 IntelliJ IDEA 主流版本,還有 Eclipse、Pycharm、Maven 等其餘版本。服務器
推薦使用 IDEA 插件下載 Cloud Toolkit 來使用 Arthas:http://t.tb.cn/2A5CbHWveOXzI7sFakaCw8 app
地址:https://github.com/alibaba/arthas。less
心裏 OS:糟糕,G1 還不熟可怎麼辦,先想個辦法把大佬們支開,我本身再慢慢研究。
我還有點別的事兒,我等會再看函數
在現有掌握的信息下判斷,大膽假設一下,反正猜錯了又不會賠錢。微服務
進程啓動參數工具
-Xms12g -Xmx12g -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -XX:MaxGCPauseMillis=200 -XX:G1HeapWastePercent=20 -XX:+PrintAdaptiveSizePolicy -XX:+UseStringDeduplication -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintTenuringDistribution -Xloggc:/home/search/fse2/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=2 -XX:GCLogFileSize=512M -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMTStatistics -XX:NativeMemoryTracking=summary
能夠看到,使用了 G1 收集器,這個以前作業務開發的時候還不常見呢,畢竟是爲大內存打造的追求低延遲的垃圾回收器。關於 G1 收集器的一些基本特性,你們能夠去搜集一些資料。大概主要包括如下幾項:性能
從 G1 的這些屬性來看,它指望作到減小人爲操做調優,實現自動化的調優(說到這裏,感受本次出現的 OOM 彷佛跟垃圾收集器自己關聯並不大,並非由於業務量大堆內存不夠用,可能根本緣由在代碼邏輯層面),而且適應在硬件成本下降,大內存堆逐漸變多的場景(後面還有 ZGC 和 Shenandoah,一樣是能夠管理超大內存並停頓很低的神奇垃圾收集器)。
已經有GC日誌了,那先看看日誌,發現一處異常:
#### 這裏Heap回收的還只是300多M內存 [Eden: 316.0M(956.0M)->0.0B(1012.0M) Survivors: 48.0M->44.0M Heap: 359.2M(12.0G)->42.0M(12.0G)] [Times: user=0.31 sys=0.01, real=0.05 secs] 2020-06-09T02:59:23.489+0800: 2020-06-09T02:59:23.489+0800: 35.922: Total time for which application threads were stopped: 0.0578199 seconds, Stopping threads took: 0.0000940 seconds 35.922: [GC concurrent-root-region-scan-start] ...... ...... ...... #### 這個點Heap回收的就是11G內存了 [Eden: 724.0M(1012.0M)->0.0B(540.0M) Survivors: 44.0M->72.0M Heap: 11.5G(12.0G)->355.6M(12.0G)] [Times: user=1.51 sys=0.07, real=0.26 secs] 2020-06-09T03:12:36.329+0800: 828.762: Total time for which application threads were stopped: 0.2605902 seconds, Stopping threads took: 0.0000600 seconds
增長 -XX:G1ReservePercent 選項的值,爲「目標空間」增長預留內存量。
減小 -XX:InitiatingHeapOccupancyPercent
提早啓動標記週期
懷疑在 GC 的當時,有大量數據全量寫入,內存還沒回收完,寫進大量對象,致使了 OOM,因而調了啓動週期,佔比由 70 降低到55,提早觸發,預留更多堆空間。
GC 變得頻繁了,可是內存佔用過大的問題並無獲得解釋。而且是否會再次在凌晨出現 OOM 還須要等。。。因而還要繼續看看有沒有別的問題。
有疑點沒有解答,確定是要繼續挖掘的,抄起鍵盤就是幹,一頓操做猛如虎。
不知道哪位已經安裝了,先拿來用用看吧,大概用到了如下幾個命令:
看看基本狀況,線程數,堆大小,老年代大小,使用佔比狀況。首次看到這裏時,eden 和 old 區的佔用都挺高的, 70~80% 吧(當時忘了截圖)。內存使用率比較高。
看看線程數有沒有異常,線程數正常,只是找出了資源佔用比較高的線程,其中一個線程在後面其餘信息統計中還會出現:
YJPAgent-Telemetry ctrl-bidsearch-rank-shard1 YJPAgent-RequestListener ctrl-bidsearch-rank-shard1
竟然有兩個線程是 YourKit 監控工具的 agent,看來這個監控工具對性能影響還挺大的。
分別採集一下內存和 CPU 的火焰圖數據:
# 內存 profiler start --event alloc ### profiler stop # 默認CPU profiler start ### profiler stop
從 CPU 火焰圖看到,G1 收集器線程竟然佔了一半資源,可能採集當時正在進行 GC,不過,除此以外,基本都能定位到是一個叫 IncrementIndexService
的類,使用了比較多的 CPU 和內存資源。
若是業務代碼真的存在缺陷,那麼必定在這個流程裏,後來通過溝通,發現這個應用處理任務主要入口的確是在這裏面。先持有保留意見。
thread 看到的線程和 profiler 看到的 class,都最終定位到是同一個業務流程。
開始驗證以前的猜測:
計算了一些業務代碼獲取數據的量,元數據大約也就在 1.3G 左右,就算全量寫入,也不該該佔用 12G 的堆內存,因此猜想全量數據寫入時,代碼邏輯可能有什麼缺陷,致使 1.3G 的原數據被封裝成遠大於 1.3G 的對象了。
有,可是通過 watch 觀察,沒有發現容器只 put 不 remove 的狀況,命令以下:
watch com.xxx.classname method "{params,target}" -x 3
對於 G1,默認將堆分紅 2048 個 Region,12G 的堆,一個 Region 是 6M,超過 3M 纔是大對象。
jmap histo 30123
至少輸出的數據中,大對象不是 G1 定義的大對象。
既然沒什麼發現,就把堆 dump 出來吧。若是不想或者不能 dump,也能夠用 jmap histo 查看內存佔用,優勢是不用 dump,缺點是一般不能很好的和業務代碼之間創建關聯。
警告:jmap 或者 Arthas 的 heapdump 操做以前必定要斷開流量。好在咱們這個服務沒有線上流量,建索引有延遲,可能短暫影響搜索體驗。
dump 出來以後,發現有 7 個 G,這麼大的文件通常很難傳到本地來分析了,因而用 MAT,佔用服務器 1 個 G 內存進行分析,分析完成的結果下載到本地。
線程名稱和以前發現的信息吻合,點開 detail 有驚喜。
一串奇怪的字符串,有點像 XML,好像在拼裝着什麼,因而找到業務大佬請教,發現的確有拼裝 solrDocument 的邏輯,並且,通過 YourKit 輸出部分對象值的片斷,能夠發現有大部分是在重複拼裝,大概意思以下:
<xml> ... <country>CA</country> <country>CA</country> <country>CA</country> <country>CA</country> <country>CA</country> ...n次重複 <country>US</country> <country>US</country> <country>US</country> <country>US</country> <country>US</country> <country>US</country> ...n次重複 <country>UK</country> <country>UK</country> ... </xml>
代碼邏輯修改其實比較簡單了,業務開發大佬們比較熟悉業務流程,很快就就有了修改方案。
調整以後發現,內存使用量降低了不少。
直接降到了 4-5G 左右,若是是這樣的話,即使全量數據寫入時,正在作垃圾回收,應該仍是夠用的。可是感受這個代碼邏輯裏面,應該還有優化空間,不過,先解決問題,優化能夠作下一步操做。
不管從哪一個工具得出的數據,都顯示 IncrementIndexService
這個類的邏輯可能有問題,最終問題的根本和 G1 參數設置好像也沒什麼關係,代碼邏輯缺陷纔是根源,再擴大內存可能或者調整 JVM 參數,也只能將故障緩解,可是不能解決。
Arthas 官方正在舉行徵文活動,若是你有:
歡迎參加徵文活動,還有獎品拿哦~點擊投稿
「 阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,作最懂雲原生開發者的公衆號。」