一次故障排查過程

上週晚上,某環境 ES 出現阻塞, 運行緩慢。因而開始排查問題的過程。java

開始

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

登陸到目標服務器,因爲 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 線程,看來是內存不夠了。ui

使用 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 修改權限,而後下載。code

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

最後,將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 狀態。

相關文章
相關標籤/搜索