公司最近使用ElasticSearch做爲數據報表彙總引擎.上線三個月累計數據800萬,可是今天忽然大面積出現查詢超時,上服務器查看服務運行狀況,發現cpu使用率高達300% mem 使用率也到了90%,下面記錄了整個排查問題的過程html
1.首先查看elastic cpu和mem佔用狀況java
//首先查看全部進程 # top //找到對應的elasticserch運行的PID,查看佔用內存比較高的線程,Ctrl+c 退出 #top -Hp 12345
//爲了下面方便調用API,將elasticsearch.yml
// xpack.security.enabled: false
//關閉認證,重啓elasticsearch
2.肯定是因爲某個線程引發的情況,查詢全部segment的駐留內存的狀況node
//kibana 如下所有以kibanna爲例 GET _cat/segments?v&h=index,segment,size //curl #curl -XGET 'http://10.0.7.134:9200/ _cat/segments?v&h=index,segment,size'
這裏摘錄一下,elasticsearch,segment,shard的區別程序員
Shard(分片)
一個Shard就是一個Lucene實例,是一個完整的搜索引擎。一個索引能夠只包含一個Shard,只是通常狀況下會用多個分片,能夠拆分索引到不一樣的節點上,分擔索引壓力。
segment
elasticsearch中的每一個分片包含多個segment,每個segment都是一個倒排索引;在查詢的時,會把全部的segment查詢結果彙總歸併後最爲最終的分片查詢結果返回;
在建立索引的時候,elasticsearch會把文檔信息寫到內存bugffer中(爲了安全,也一塊兒寫到translog),定時(可配置)把數據寫到segment緩存小文件中,而後刷新查詢,使剛寫入的segment可查。
雖然寫入的segment可查詢,可是尚未持久化到磁盤上。所以,仍是會存在丟失的可能性的。
因此,elasticsearch會執行flush操做,把segment持久化到磁盤上並清除translog的數據(由於這個時候,數據已經寫到磁盤上,不在須要了)。
當索引數據不斷增加時,對應的segment也會不斷的增多,查詢性能可能就會降低。所以,Elasticsearch會觸發segment合併的線程,把不少小的segment合併成更大的segment,而後刪除小的segment。
segment是不可變的,當咱們更新一個文檔時,會把老的數據打上已刪除的標記,而後寫一條新的文檔。在執行flush操做的時候,纔會把已刪除的記錄物理刪除掉。
3.沒有發現特別佔用內存和cpu的segment,接着查看node的內存和cpu的使用狀況緩存
GET _cat/nodes?v
參考: Day 19 ES內存那點事安全
4.通過查找總體的cpu佔用率仍是很高,接着查看,elastic運行日誌發現服務器
//jvm gc [gc][51125] overhead, spent [15s] collecting in the last [15.2s]
這裏摘錄一下java jvm gc的解釋curl
與C/C++相比,JAVA並不要求咱們去人爲編寫代碼進行內存回收和垃圾清理。JAVA提供了垃圾回收器(garbage collector)來自動檢測對象的做用域),可自動把再也不被使用的存儲空間釋放掉,也就是說,GC機制能夠有效地防止內存泄露以及內存溢出。
JAVA 垃圾回收器的主要任務是:
分配內存
確保被引用對象的內存不被錯誤地回收
回收再也不被引用的對象的內存空間
凡事都有兩面性。垃圾回收器在把程序員從釋放內存的複雜工做中解放出來的同時,爲了實現垃圾回收,garbage collector必須跟蹤內存的使用狀況,釋放沒用的對象,在完成內存的釋放以後還須要處理堆中的碎片, 這樣作一定會增長JVM的負擔。
爲何要了解JAVA的GC機制? 綜上所述,除了做爲一個程序員,精益求精是基本要求以外,深刻了解GC機制讓咱們的代碼更有效率,尤爲是在構建大型程序時,GC直接影響着內存優化和運行速度。
關於java程序的性能 G1 Garbage Collector *jvm
[ElasticSearch填坑] 聚合請求致使GC故障 *elasticsearch
5.查看節點狀態
//kibana
_nodes/stats
//jvm 佔用cpu 98% 內存 80%
須要提的一點就是 GC 是很是影響性能的,因此咱們來簡單介紹一下 JVM 的機制。啓動 JVM 虛擬機的時候,會分配固定大小的內存塊,也就是堆 heap。堆又分紅兩組,Young 組是爲新實例化的對象所分配的空間,比較小,通常來講幾百 MB,Young 組內又分爲兩個 survivor 空間。Young 空間滿了後,就垃圾回收一次,還存活的對象放到倖存空間中,失效的就被移除。Old 組就是保存那些重啓存活且一段時間不會變化的內容,對於 ES 來講可能有 30 GB 內存是 Old 組,一樣,滿了以後就垃圾回收。 垃圾回收的時候,JVM 採用的是 STW(Stop The World) 機制,Young 組比較小還好,可是 Old 組可能須要幾秒十幾秒,那就是服務器無響應啊!因此咱們必須很是關注 GC 性能。 若是 ES 集羣中常常有很耗時的 GC,說明內存不足,若是影響集羣之間 ping 的話,就會退出集羣,而後由於分片緣故致使更大的影響。咱們能夠在節點狀態中的 jvm 部分查看對應的數值,最重要是 heap_used_percent,若是大於 75,那麼就要垃圾回收了,若是長期在 75 以上,那就是內存不足。
6.綜合上述,能夠定位
6.1 jvm heap 設置比較小,默認是2g 本機有10g 配置內存爲6g
6.2 jvm GC 配置原來爲 UseConcMarkSweepGC 更新爲 UseG1GC
修改elasticSeaerch安裝目錄下,jvm.options ,若是是集羣則每一個節點都要改
//註釋掉原來的配置 ## GC configuration #-XX:+UseConcMarkSweepGC #-XX:CMSInitiatingOccupancyFraction=75 #-XX:+UseCMSInitiatingOccupancyOnly //更新爲 -XX:+UseG1GC -XX:MaxGCPauseMillis=50 //修改 -Xms6g -Xms6g
改elasticsearch.yml打開認證,從新啓動ElasticSearch,在查看cpu沒有那麼高了,並且查詢速度也快了
貌似內存消耗仍是有點高,可是正常狀況,經過使用
_cat/segments?v查看是具體狀況