天天看點

ElasticSearch CPU和記憶體占用高的優化記錄出現GC 

      公司最近使用ElasticSearch作為資料報表彙總引擎.上線三個月累計資料800萬,但是今天突然大面積出現查詢逾時,上伺服器檢視服務運作情況,發現cpu使用率高達300% mem 使用率也到了90%,下面記錄了整個排查問題的過程

     1.首先檢視elastic cpu和mem占用情況

ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
//首先檢視所有程序
# top
//找到對應的elasticserch運作的PID,檢視占用記憶體比較高的線程,Ctrl+c 退出
#top -Hp 12345   
//為了下面友善調用API,将elasticsearch.yml
//   xpack.security.enabled: false
//關閉認證,重新開機elasticsearch      
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
    2.确定是由于某個線程引起的狀況,查詢所有segment的駐留記憶體的情況
//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的差別
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
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操作的時候,才會把已删除的記錄實體删除掉。      
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
   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的解釋
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
與C/C++相比,JAVA并不要求我們去人為編寫代碼進行記憶體回收和垃圾清理。JAVA提供了垃圾回收器(garbage collector)來自動檢測對象的作用域),可自動把不再被使用的存儲空間釋放掉,也就是說,GC機制可以有效地防止記憶體洩露以及記憶體溢出。

JAVA 垃圾回收器的主要任務是:

配置設定記憶體
確定被引用對象的記憶體不被錯誤地回收
回收不再被引用的對象的記憶體空間
凡事都有兩面性。垃圾回收器在把程式員從釋放記憶體的複雜工作中解放出來的同時,為了實作垃圾回收,garbage collector必須跟蹤記憶體的使用情況,釋放沒用的對象,在完成記憶體的釋放之後還需要處理堆中的碎片, 這樣做必定會增加JVM的負擔。

為什麼要了解JAVA的GC機制? 綜上所述,除了作為一個程式員,精益求精是基本要求之外,深入了解GC機制讓我們的代碼更有效率,尤其是在建構大型程式時,GC直接影響着記憶體優化和運作速度。      
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 

     關于java程式的性能   G1 Garbage Collector *

    [ElasticSearch填坑] 聚合請求導緻GC故障  *

      生産環境elasticsearch的配置建議

      jvm如何優化java GC[譯]

   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 以上,那就是記憶體不足。      

Elasticsearch技巧指南 **

  6.綜合上述,可以定位

     6.1  jvm heap 設定比較小,預設是2g 本機有10g 配置記憶體為6g

     6.2 jvm GC 配置原來為 UseConcMarkSweepGC 更新為 UseG1GC

    修改elasticSeaerch安裝目錄下,jvm.options ,如果是叢集則每個節點都要改

ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
//注釋掉原來的配置
## GC configuration
#-XX:+UseConcMarkSweepGC
#-XX:CMSInitiatingOccupancyFraction=75
#-XX:+UseCMSInitiatingOccupancyOnly

//更新為
-XX:+UseG1GC
-XX:MaxGCPauseMillis=50

//修改

-Xms6g
-Xms6g      
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 
    改elasticsearch.yml打開認證,重新啟動ElasticSearch,在檢視cpu沒有那麼高了,而且查詢速度也快了
ElasticSearch CPU和記憶體占用高的優化記錄出現GC 

    貌似記憶體消耗還是有點高,但是正常情況,通過使用

    _cat/segments?v檢視是具體情況

繼續閱讀