Elasticsearch性能優化實戰指南

作者:銘毅天下

背景
在當今世界,各行各業每天都有海量數據產生,爲了從這些海量數據中獲取想要的分析結果,需要對數據進行提取、轉換,存儲,維護,管理和分析。 這已然遠遠超出了普通處理工具、數據庫等的實現能力,只有基於的分佈式架構和並行處理機制的大數據工具所才能實現這些功能。Elasticsearch是響應如前所述大多數用例的最熱門的開源數據存儲引擎之一。
Elasticsearch是一種分佈式數據存儲和搜索引擎,具有容錯和高可用性特點。爲了充分利用其搜索功能,需要正確配置Elasticsearch。
簡單的默認配置不適合每個實際業務場景。實戰開發運維中,個性化實現貼合自己業務場景的集羣配置是優化集羣性能的必經之路。本文集合實戰業務場景,重點介紹搜索密集型Elasticsearch集羣的提升性能的乾貨配置。

1、索引層面優化配置
默認情況下,6.x及之前的版本中Elasticsearch索引有5個主分片和1個副本,7.X及之後版本1主1副。 這種配置並不適用於所有業務場景。 需要正確設置分片配置,以便維持索引的穩定性和有效性。
1.1、分片大小
分片大小對於搜索查詢非常重要。
一方面, 如果分配給索引的分片太多,則Lucene分段會很小,從而導致開銷增加。當同時進行多個查詢時,許多小分片也會降低查詢吞吐量。
另一方面,太大的分片會導致搜索性能下降和故障恢復時間更長。
Elasticsearch官方建議一個分片的大小應該在20到40 GB左右。
例如,如果您計算出索引將存儲300 GB的數據,則可以爲該索引分配9到15個主分片。
根據集羣大小,假設羣集中有10個節點,您可以選擇爲此索引分配10個主分片,以便在集羣節點之間均勻分配分片。
1.2、數據動態持續寫入場景
如果存在連續寫入到Elasticsearch集羣的數據流,如:實時爬蟲互聯網數據寫入ES集羣。則應使用基於時間的索引以便更輕鬆地維護索引。
如果寫入數據流的吞吐量隨時間而變化,則需要適當地改變下一個索引的配置才能實現數據的動態擴展。
那麼,如何查詢分散到不同的基於時間索引的所有文檔?答案是別名。可以將多個索引放入別名中,並且對該別名進行搜索會使查詢就像在單個索引上一樣。
當然,需要保持好平衡。注意思考:將多少數據寫入別名?別名上寫入太多小索引會對性能產生負面影響。
例如,是以周還是以月爲單位爲單位建立索引是需要結合業務場景平衡考慮的問題?
如果以月爲單位建議索引性能最優,那麼相同數據以周爲單位建立索引勢必會因爲索引太多導致負面的性能問題。
1.3、Index Sorting
注意:索引排序機制是6.X版本纔有的特性。
在Elasticsearch中創建新索引時,可以配置每個分片中的分段的排序方式。 默認情況下,Lucene不會應用任何排序。 index.sort.* 定義應使用哪些字段對每個Segment內的文檔進行排序。
使用舉例:

PUT /twitter
 {
     "settings" : {
         "index" : {
             "sort.field" : "date", 
             "sort.order" : "desc" 
         }
     },
     "mappings": {
        "properties": {
            "date": {
                "type": "date"
            }
        }
    }
}

目的:index sorting是優化Elasticsearch檢索性能的非常重要的方式之一。
大白話:index sorting機制通過寫入的時候指定了某一個或者多個字段的排序方式,會極大提升檢索的性能。

2、分片層面優化配置
分片是底層基本的讀寫單元,分片的目的是分割巨大索引,讓讀寫並行執行。寫入過程先寫入主分片,主分片寫入成功後再寫入副本分片。
副本分片的出現,提升了集羣的高可用性和讀取吞吐率。
在優化分片時,分片的大小、節點中有多少分片是主要考慮因素。副本分片對於擴展搜索吞吐量很重要,如果硬件條件允許,則可以小心增加副本分片的數量。
容量規劃的一個很好的啓動點是分配分片,“《深入理解Elasticsearch》強調:最理想的分片數量應該依賴於節點的數量。”其數量是節點數量的1.5到3倍。
分配副本分片數的公式:max(max_failures,ceil(num_nodes /) num_primaries) - 1)。
原理:如果您的羣集具有num_nodes節點,總共有num_primaries主分片,如果您希望最多能夠同時處理max_failures節點故障,那麼適合您的副本數量爲如上公式值。
總的來說:節點數和分片數、副本數的簡單計算公式如下:
所需做大節點數=分片數*(副本數+1)。

3、Elasticsearch整體層面配置
配置Elasticsearch集羣時,最主要的考慮因素之一是確保至少有一半的可用內存進入文件系統緩存,以便Elasticsearch可以將索引的hot regions保留在物理內存中。
在設計集羣時還應考慮物理可用堆空間。 Elasticsearch建議基於可用堆空間的分片分配最多應爲20個分片/ GB,這是一個很好的經驗法則。
例如,具有30 GB堆的節點最多應有600個分片,以保持集羣的良好狀態。
一個節點上的存儲可以表述如下:節點可以支持的磁盤空間= 20 (堆大小單位:GB)(以GB爲單位的分片大小),由於在高效集羣中通常會看到大小在20到40 GB之間的分片,因此最大存儲空間可以支持16 GB可用堆空間的節點,最多可達12 TB的磁盤空間(201640=12.8TB)。
邊界意識有助於爲更好的設計和未來的擴展操作做好準備。
可以在運行時以及初始階段進行許多配置設置。
在構建Elasticsearch索引和集羣本身以獲得更好的搜索性能時,瞭解在運行時哪些配置可以修改以及哪些配不可以修改是至關重要的。
3.1 動態設置
1、設置歷史數據索引爲只讀狀態。
基於時間的動態索引的執行階段,如果存放歷史數據的索引沒有寫操作,可以將月度索引設置爲只讀模式,以提高對這些索引的搜索性能。
6.X之後的只讀索引實戰設置方式:

PUT /twitter/_settings
{
  "index.blocks.read_only_allow_delete": null
}

2、對只讀狀態索引,進行段合併。
當索引設置爲只讀時,可以通過強制段合併操作以減少段的數量。
優化段合併將導致更好的搜索性能,因爲每個分片的開銷取決於段的計數和大小。
注意1:不要將段合併用於讀寫索引,因爲它將導致產生非常大的段(每段> 5Gb)。
注意2:此操作應在非高峯時間進行,因爲這是一項非常耗資源的操作。
段合併操作實戰方式:

curl -X POST "localhost:9200/kimchy/_forcemerge?only_expunge_deletes=false&max_num_segments=100&flush=true"

3、使用preference優化緩存利用率
有多個緩存可以幫助提高搜索性能,例如文件系統緩存,請求緩存或查詢緩存。
然而,所有這些緩存都維護在節點級別,這意味着如果您在擁有1個或更多副本且基於默認路由算法集羣上連續兩次運行相同的請求,這兩個請求將轉到不同的分片副本上 ,阻止節點級緩存幫助。
由於搜索應用程序的用戶一個接一個地運行類似的請求是常見的,例如爲了檢索分析索引的部分較窄子集,使用preference標識當前用戶或會話的偏好值可以幫助優化高速緩存的使用。
preference實戰舉例:

GET /_search?preference=xyzabc123
{
    "query": {
        "match": {
            "title": "elasticsearch"
        }
    }

4、禁止交換
可以在每個節點上禁用交換以確保穩定性,並且應該不惜一切代價避免交換。它可能導致垃圾收集持續數分鐘而不是毫秒,並且可能導致節點響應緩慢甚至斷開與集羣的連接。
在Elasticsearch分佈式系統中,讓操作系統終止節點更有效。可以通過將bootstrap.memory_lock設置爲True來禁用它。
Linux系統級配置:

sudo swapoff -a

Elasticsearch配置文件elasticsearch.yml配置:

bootstrap.memory_lock: true

5、增加刷新間隔 refresh_interval
默認刷新間隔爲1秒。這迫使Elasticsearch每秒創建一個分段。實際業務中,應該根據使用情況增加刷新間隔,舉例:增加到30秒。
這樣之後,30s產生一個大的段,較每秒刷新大大減少未來的段合併壓力。最終會提升寫入性能並使搜索查詢更加穩定。
更新刷新間隔實戰:

PUT /twitter/_settings
{
    "index" : {
        "refresh_interval" : "1s"
    }
}

6、設置max_thread_count
index.merge.scheduler.max_thread_count默認設置爲
Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))
但這適用於SSD配置。對於HDD,應將其設置爲1。
實戰:

curl -XPUT 'localhost:9200/_settings' -d '{ 
     "index.merge.scheduler.max_thread_count" : 1
}

7、禁止動態分配分片
有時,Elasticsearch將重新平衡集羣中的分片。此操作可能會降低檢索的性能。
在生產模式下,需要時,可以通過cluster.routing.rebalance.enable設置將重新平衡設置爲none。

PUT /_cluster/settings 
{ 
  "transient" : {
    "cluster.routing.allocation.enable" : "none"
  }
}

其中典型的應用場景之包括:
集羣中臨時重啓、剔除一個節點;
集羣逐個升級節點;當您關閉節點時,分配過程將立即嘗試將該節點上的分片複製到集羣中的其他節點,從而導致大量浪費的IO. 在關閉節點之前禁用分配可以避免這種情況。

8、充分利用近似日期緩存效果
現在使用的日期字段上的查詢通常不可緩存,因爲匹配的範圍一直在變化。
然而,就用戶體驗而言,切換到近似日期通常是可接受的,並且能更好地使用查詢高速緩存帶來的益處。
實戰如下:

GET index/_search
 {
   "query": {
     "constant_score": {
       "filter": {
         "range": {
           "my_date": {
             "gte": "now-1h/m",
             "lte": "now/m"
          }
        }
      }
    }
  }
}

3.2 初始設置
1、合併多字段提升檢索性能
query_string或multi_match查詢所針對的字段越多,檢索越慢。
提高多個字段的搜索速度的常用技術是在索引時將其值複製到單個字段中。
對於經常查詢的某些字段,請使用Elasticsearch的copy-to功能。
例如,汽車的品牌名稱,發動機版本,型號名稱和顏色字段可以與複製到指令合併。它將改善在這些字段上進行的搜索查詢性能。

PUT movies
 {
   "mappings": {
     "properties": {
       "cars_infos": {
         "type": "text"
       },
       "brand_name": {
         "type": "text",
        "copy_to": "cars_infos"
      },
      "engine_version": {
        "type": "text",
        "copy_to": "cars_infos"
      },
   "model ": {
        "type": "text",
        "copy_to": "cars_infos"
      },
   "color": {
        "type": "text",
        "copy_to": "cars_infos"
      }
    }
  }
}

2、設置分片分配到指定節點
實戰業務中經常遇到的業務場景問題:如何將分片設置非均衡分配,有新節點配置極高,能否多分片點過去?
某個 shard 分配在哪個節點上,一般來說,是由 ES 自動決定的。以下幾種情況會觸發分配動作:
1)新索引生成
2)索引的刪除
3)新增副本分片
4)節點增減引發的數據均衡
ES 提供了一系列參數詳細控制這部分邏輯,其中之一是:在異構集羣的情爲具有更好硬件的節點的分片分配分配權重。
爲了分配權重,
需要設置cluster.routing.allocation.balance.shard值,默認值爲0.45f。
數值越大越傾向於在節點層面均衡分片。
實戰:

PUT _cluster/settings
{
“transient” : {
“cluster.routing.allocation.balance.shard” : 0.60
}
}

3、調整熔斷內存比例大小
查詢本身也會對響應的延遲產生重大影響。爲了在查詢時不觸發熔斷並導致Elasticsearch集羣處於不穩定狀態,
可以根據查詢的複雜性將indices.breaker.total.limit設置爲適合您的JVM堆大小。此設置的默認值是JVM堆的70%。

PUT /_cluster/settings
{
  "persistent" : {
    "indices.breaker.fielddata.limit" : "60%" 
  }
}

最好爲斷路器設置一個相對保守點的值。
《Elastic源碼分析》作者張超指出:“Elasticsearch 7.0 增加了 indices.breaker.total.use_real_memory 配置項,可以更加精準的分析當前的內存情況,及時防止 OOM 出現。雖然該配置會增加一點性能損耗,但是可以提高 JVM 的內存使用率,增強了節點的保護機制。”
4、特定搜索場景,增加搜索線程池配置
默認情況下,Elasticsearch將主要用例是搜索。在需要增加檢索併發性的情況下,可以增加用於搜索設置的線程池,與此同時,可以根據節點上的CPU中的核心數量多少斟酌減少用於索引的線程池。
舉例:更改配置文件elasticsearch.yml增加如下內容:

thread_pool.search.queue_size: 500
#queue_size允許控制沒有線程執行它們的掛起請求隊列的初始大小。

5、打開自適應副本選擇
應打開自適應副本選擇。該請求將被重定向到響應最快的節點。
當存在多個數據副本時,elasticsearch可以使用一組稱爲自適應副本選擇的標準,根據包含每個分片副本的節點的響應時間,服務時間和隊列大小來選擇數據的最佳副本。
這樣可以提高查詢吞吐量並減少搜索量大的應用程序的延遲。
這個配置默認是關閉的,實戰打開方法:

PUT /_cluster/settings
{
    "transient": {
        "cluster.routing.use_adaptive_replica_selection": true
    }
}

4、小結
Elasticsearch集羣有許多配置設置可以減少響應延遲,提升檢索性能。 以上只是冰山一角。

歡迎大家一起交流,喜歡文章記得點個贊,感謝支持!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章