一次故障排查過程


上周晚上,某環境 ES 出現阻塞, 運行緩慢。於是開始排查問題的過程。

開始

思路:現象是阻塞,通常是 CPU 彪高,導致業務線程分配不到 CPU 時間片,或者內存吃緊,頻繁 GC 導致的 STW。

登錄到目標服務器,由於 ES 的用戶不是 LZ,因此找運維要了 root 權限,登錄到服務器。sudo -i 切到 root,使用 ps -ef | grep Elasticsearch 找到該用戶,然后 su - es 切到 es 用戶(不切是無法處理 es 用戶的 Java 進程的,例如打印 jstack 日志)。

top 查看服務器狀態,發現 pid 4335 進程的 CPU 占用達到 180%,查看 CPU 核數:cat /proc/cpuinfo| grep "processor"| wc -l, 核數為 4,根據經驗,通常是 C2 編譯器,或者 GC 線程,最后是業務代碼導致。因此需要定位該線程。使用 top -Hp 4335,得到線程號 30785,使用 printf "%x" 得到 16 進制數字 7841,方便在 jstack 日志查找線程。

使用 jstack -l 4335 > jstacklog.txt 打印日志,然后找線程,vim jstacklog.txt, 開始查找,gg,/7841,enter,n, 找到 "Concurrent Mark-Sweep GC Thread" os_prio=0 tid=0x00007fd380063800 nid=0x7841 runnable 這個 CMS GC 線程,看來是內存不夠了。

使用 jps -l 找到 es 啟動類名稱,然后使用 ps aux | grep Elasticsearch 找到啟動詳細信息,發現啟動配置為 -Xmx2g -Xms2g, -XX:CMSInitiatingOccupancyFraction=50 ,這里為了防止串行 FGC,讓 CMS 在 old 區達到 50% 時就開始 GC,所以 CMS 非常繁忙。為了驗證此問題,使用 jstat -gcutil 4335 1000 查看 gc 狀態,發現 fgc 頻繁(5 秒一次),ygc 正常(3 秒一次) ,這里說一下,CMS 的 fgc 此時和我們想象的不一樣,CMS GC 只工作在老年代,每次 GC 會對 FGC 次數加 2,一次是 init mark,一次是 remark,這兩個階段會影響暫停應用,其他的清理階段是並行清理的,對業務線程無影響,所以,當使用 CMS GC ,如果 jstat 看到 FGC 次數很多,不用在意。但當 CMS 出現 concurrent mode failure(CMS GC 的速度趕不上對象晉升到 old 區的速度),則會使用備用收集器 Serial,開始串行 GC,此時將會徹底 STW。 因此,這個 ES 將 CMS 的閾值調的很低,就是為了防止出現 concurrent mode failure。

原因

原因已經找出,由於 CMS GC 頻繁,導致 CPU 彪高,ES 查詢速度變慢,最后業務阻塞。

繼續

但是為什么頻繁 CMS 呢?肯定是內存不夠,為什么不夠呢? 通常是通過 dump 內存文件查看,但是注意,jmap 和 jcmd dump 文件時,會導致 fgc,線上需要注意,我這里由於不是業務高峰,使用 jmap -dump:format=b,file=/tmp/dump.hprof 3445 , 導出該文件到 tmp 目錄,方便從跳板機上下載。

從跳板機下載文件,權限不夠,使用 sudo chown -R username dump.hprof 修改權限,然后下載。

LZ 使用的是 mac,使用 mat(Mac 的 mat 有 bug,需要替換一個 jar 包,具體自行搜索) 開始分析,發現內存中有 1個多 g 的 indexService 對象(600 多),即 ES 的索引對象,通過和 ES 同學的溝通,確實發現有 600 多索引,有很多都是國企索引,通常一台 ES 差不多配置 100-200 索引,大量索引引起更新,頻繁更新索引對象。

最后,將ES 內存升級到 4g,-XX:CMSInitiatingOccupancyFraction 修改為75,減少 CMS GC。刪除 ES 無效索引。問題解決。

后期為了檢驗結果,使用 jvisualvm 連上服務器 Java 進程: 登錄到目標服務器,創建文件 jstatd.all.policy,文件內容:

grant codebase "file:${java.home}/../lib/tools.jar" {
   permission java.security.AllPermission;
};

執行 jstatd -J-Djava.security.policy=jstatd.all.policy -p 1222 & , 啟動 jstatd 后台服務,方便 jvisualvm 連接到這台服務器的 Java 進程。找到本機 Java 目錄下的 VisualVM ,連接上目標 ip 和 1222 端口服務,安裝 GC 插件,查看 GC 狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM