1. 程式人生 > >ElasticSearch學習總結(七):效能優化總結

ElasticSearch學習總結(七):效能優化總結

本文主要總結Elasticsearch效能優化方面的相關內容

1. 概述

效能優化是個涉及面非常廣的問題,不同的環境,不同的業務場景可能會存在不同的優化方案,本文只對一些相關的知識點做簡單的總結,具體方案可以根據場景自行嘗試。

1.1 效能測試

如果需要做效能調優,效能基準測試的工具必不可少,這裡可以選擇Rally

1.2 熱點執行緒

當叢集緩慢,使用大量的CPU資源時,可以使用熱點執行緒API來檢視資源都執行在了哪些地方,並可以檢視資源消耗的情況。

可以通過已下方式檢視熱點執行緒
1. 全域性的分析:/_nodes/hot_threads
2. 某個節點的分析:/_nodes/{nodesIds}/hot_threads

3. 常規配置

3.1 部署方案

  1. 當單機容納不下資料時,考慮多分片
  2. 當查詢效能不足時,考慮多副本。
  3. 對於一些高效能的伺服器,可以考慮一臺伺服器上部署多個例項
  4. 通過awarenss的相關配置,阻止分片及其副本部署在同一臺機器上。
  5. 儘量平均分配分片和副本。
  6. 當叢集較大時,考慮設計每個節點的角色。例如 節點只作為查詢聚合節點,資料節點,或是主/候選主節點

3.2 避免記憶體交換

記憶體交換是指把記憶體頁寫入磁碟的過程,一般發生在實體記憶體不夠或是某些情況下作業系統認為應該發生的時候發生。如果交換了的記憶體頁再次被需要,作業系統會從交換區載入到記憶體,該過程相對於記憶體操作而言是是比較慢的。

為了保證ES的高效,在ES中應該避免記憶體交換的發生,如果達到此目的,需要進行如下配置:
1. 設定elasticserach.yml檔案中的bootstrap.mlockall=true
2. 設定Xms與Xmx的值相同
3. 在/etc/security/limits.conf中新增elasticsearch -memlock unlimited
4. 在/etc/pam.d/common-session中新增session required pam_limits.so
5. 重啟es

3.3 採用G1垃圾回收機制代替預設CMS

3.4 索引重新整理頻率(refresh_interval)

該引數基本遵循如下規律:
1. 重新整理越快,資料更新越快,但是查詢與索引的效率越低
2. 雖然增加該值,可以一定程度的提升效率,但是超過一定數值後,提升的效果將微乎其微。

3.5 執行緒池調優

如果你發現ES例項的資源沒有100%飽和,但卻受到了拒絕執行的錯誤,此時可能就需要調整ES的執行緒池了。可以嘗試增加併發的執行緒數或是增加佇列的長度。在調整的過程中需要注意的是,當併發執行緒數到一個很大的數值時,會產生大量的CPU上下文切換,進而導致效能下降。大量的佇列也可能會出現佇列大量積壓的情況。

3.6 調整段合併過程

一般情況下,如果希望查詢的速度更快,就需要更少的段。例如設定index.merge.policy.merge_factory低於預設值10,會導致更少的段,更低的RAM消耗,更快的查詢執行速度但是會出現更慢的索引速度。如果設定的index.merge.policy.merge_factory較高則會出現相反的情況。

另外需要注意的是,預設情況下ES會限制合併的速度在20MB/s.如果使用的是固態硬碟或是I/O效率更高的裝置,則可以適當的增加限制的速度。

4. 高查詢頻率下的優化

本章節主要針對高查詢吞吐量場景的優化方案進行總結

4.1 查詢快取

分片查詢快取的主要目的是快取聚合,提示詞和命中數(不會快取返回的文件)

如果想要開啟mastering索引的查詢快取,可以執行類似下面的操作

PUT /mastering/_settings
{ "index.requests.cache.enable": true }

查詢快取預設使用節點堆疊的1%記憶體,可以通過下列方式對該值進行設定:

indices.requests.cache.size: 2%

4.2 使用doc_values優化查詢

快取有時候可以帶來效能的顯著提高,但是對於某些場景快取可能不是萬能的,例如:
1. 文件頻繁更新
2. 查詢具有唯一性,且不可重複性,例如帶了時間或是id左右查詢條件

對於快取需要容納全部資料的場景(例如,排序,聚合 等操作時),如果擁有大量的文件,很容易碰到OOM的問題,此時可以考慮使用doc_values的特性。

在 Elasticsearch 中,Doc Values 就是一種列式儲存結構,預設情況下每個欄位的 Doc Values 都是啟用的,Doc Values 是在索引時建立的,當欄位索引時,Elasticsearch 為了能夠快速檢索,會把欄位的值加入倒排索引中,同時它也會儲存該欄位的 Doc Values

Elasticsearch 中的 Doc Values 常被應用到以下場景:

  1. 對一個欄位進行排序
  2. 對一個欄位進行聚合
  3. 某些過濾,比如地理位置過濾
  4. 某些與欄位相關的指令碼計算
    因為文件值被序列化到磁碟,我們可以依靠作業系統的幫助來快速訪問。當 working set 遠小於節點的可用記憶體,系統會自動將所有的文件值儲存在記憶體中,使得其讀寫十分高速; 當其遠大於可用記憶體,作業系統會自動把 Doc Values 載入到系統的頁快取中,從而避免了 jvm 堆記憶體溢位異常。

因為 Doc Values 預設啟用,你可以選擇對你資料集裡面的大多數字段進行聚合和排序操作。但是如果你知道你永遠也不會對某些欄位進行聚合、排序或是使用指令碼操作,可以禁用特定欄位的 Doc Values 。這樣不僅節省磁碟空間,也許會提升索引的速度。 例子如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "session_id": {
          "type":       "string",
          "index":      "not_analyzed",
          "doc_values": false 
        }
      }
    }
  }
}

4.3 儘量使用過濾器

由於過濾器執行的過程中不會涉及評分的操作以及過濾器快取的緣故,所以查詢應該優先考慮使用過濾器(例如,對於靜態的,不分詞的欄位儘量使用過濾器)。

儘量使用路由

有著相同路路由值的資料會被儲存到相同的分片上,於是在查詢時就可以將請求傳送到指定的分片上,可以避免合併結果的開銷。
因此應該儘量使用路由

4.4 欄位資料快取和斷路

欄位資料快取主要用於在欄位上排序或計算聚合時使用。它將所有欄位值載入到記憶體中,以提供基於快速的基於這些值的操作。

Elasticsearch的欄位資料快取預設是沒有大小限制的,尤其是當在很多欄位上進行分組和排序的時候。如果這些欄位的基礎很高,很容易出現OOM.

為此可以採取以下措施:
1. 限制欄位緩衝區的大小:indices.fielddata.cache.size
2. 使用斷路器( Field data circuit breaker):配置斷路器後可以在滿足某些條件下丟擲異常而不是OOM

如果查詢大量使用了欄位資料快取(聚合和排序),且頻繁的存在記憶體的問題,可以考慮使用doc_values進行替換。

4.5 控制size和shard_size

  • size:引數定義最後聚合結果會返回多少組資料給客戶端。
  • shard_size:和size類似,其主要作用在分片上

上述兩個值的增加會讓聚合結果更加精準,同事也會消耗過多的資源。降低這兩個值會降低精準度,但是會減少資源損耗。

5. 寫資料

5.1 批量索引

如果有大量資料需要索引,可以使用批量索引取代逐個文件的索引。

因為處理批量索引的時候是在批量資料處理執行緒池中執行的,所以批次的量也不能太大,否則會ES也會消耗過多的記憶體來處理這些資料。

5.2 doc_values 與索引速度的取捨

ES為了實現排序,聚合或是分組操作需要反轉欄位,需要巨大的記憶體,doc_values可以解決這些問題。

但是在索引是doc_values也會產生一些額外的消耗,因此:
1. 如果不涉及排序,聚合或是分組操作,且對索引的吞吐量較大,可以考慮關閉doc_values
2. 如果海量資料的涉及排序,聚合或是分組操作,doc_values或許必不可少。

5.3 控制文件的欄位

文件的大小在一定程度上會影響索引的速度,可以採取如下方式對大小進行控制
1. _all欄位在很多場景下可能不會被使用,可以選擇性的對其進行關閉。
如果關閉了可以同時指定一個預設的查詢欄位

curl -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_type": {
      "_all": {
        "enabled": false 
      },
      "properties": {
        "content": {
          "type": "text"
        }
      }
    }
  },
  "settings": {
    "index.query.default_field": "content" 
  }
}
'
  1. 儘量減少文件的大小和文字欄位的數量。

5.4 考慮分片以及副本的數量

過多的副本會增加複製與傳輸的開銷

5.5 控制refresh與flush

對於需要進行大批量資料寫入,且在寫入過程中不需要查詢的場景,可以採取以下優化手段

  • 修改translog的flush方式

預設情況下每次對索引的操作都會出發一次tranlog的flush操作,對於大批量資料寫入的場景,可以先改成定期flush,下列配置會根據index.translog.sync_interval的配置進行定期flush,等導完資料後,再恢復正常值

PUT test_index/_settings
{
  "index":{
    "translog.durability":"async"
  }
}
  • 修改refresh的時間

Searcher會更具refresh_interval的配置定期的更新索引,在大量資料匯入的情況下,可以先將該值改為-1,等導完資料後,再恢復正常值

PUT test_index/_settings
{
  "index":{
    "refresh_interval":"-1"
  }
}

5.6 索引期間的記憶體快取

增加節點的索引快取大小(indices.memory.index_buffer_size,預設使用10%),也將有利於索引吞吐量的增加。

該配置主要是針對節點的,例如節點有20GB的記憶體,且有10十個分片,則每個分片大約分的200MB的記憶體作為索引快取(20GB*10%/10=200MB)