Elasticsearch性能優化實戰指南

0、背景
在當今世界,各行各業天天都有海量數據產生,爲了從這些海量數據中獲取想要的分析結果,須要對數據進行提取、轉換,存儲,維護,管理和分析。 這已然遠遠超出了普通處理工具、數據庫等的實現能力,只有基於的分佈式架構和並行處理機制的大數據工具所才能實現這些功能。 Elasticsearch是響應如前所述大多數用例的最熱門的開源數據存儲引擎之一。html

Elasticsearch是一種分佈式數據存儲和搜索引擎,具備容錯和高可用性特色。爲了充分利用其搜索功能,須要正確配置Elasticsearch。node

簡單的默認配置不適合每一個實際業務場景。實戰開發運維中,個性化實現貼合本身業務場景的集羣配置是優化集羣性能的必經之路。本文集合實戰業務場景,重點介紹搜索密集型Elasticsearch集羣的提高性能的乾貨配置。算法

一、索引層面優化配置
默認狀況下,6.x及以前的版本中Elasticsearch索引有5個主分片和1個副本,7.X及以後版本1主1副。 這種配置並不適用於全部業務場景。 須要正確設置分片配置,以便維持索引的穩定性和有效性。數據庫

1.一、分片大小
分片大小對於搜索查詢很是重要。bootstrap

一方面, 若是分配給索引的分片太多,則Lucene分段會很小,從而致使開銷增長。當同時進行多個查詢時,許多小分片也會下降查詢吞吐量。緩存

另外一方面,太大的分片會致使搜索性能降低和故障恢復時間更長。性能優化

Elasticsearch官方建議一個分片的大小應該在20到40 GB左右。架構

例如,若是您計算出索引將存儲300 GB的數據,則能夠爲該索引分配9到15個主分片。 併發

根據集羣大小,假設羣集中有10個節點,您能夠選擇爲此索引分配10個主分片,以便在集羣節點之間均勻分配分片。app

深刻原理推薦:

Elasticsearch之如何合理分配索引分片?

https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

Elasticsearch究竟要設置多少分片數?

https://qbox.io/blog/optimizing-elasticsearch-how-many-shards-per-index

1.二、數據動態持續寫入場景
若是存在連續寫入到Elasticsearch集羣的數據流,如:實時爬蟲互聯網數據寫入ES集羣。則應使用基於時間的索引以便更輕鬆地維護索引。

若是寫入數據流的吞吐量隨時間而變化,則須要適當地改變下一個索引的配置才能實現數據的動態擴展。

那麼,如何查詢分散到不一樣的基於時間索引的全部文檔?答案是別名。能夠將多個索引放入別名中,而且對該別名進行搜索會使查詢就像在單個索引上同樣。

固然,須要保持好平衡。注意思考:將多少數據寫入別名?別名上寫入太多小索引會對性能產生負面影響。

例如,是以周仍是以月爲單位爲單位創建索引是須要結合業務場景平衡考慮的問題?

若是以月爲單位建議索引性能最優,那麼相同數據以周爲單位創建索引勢必會由於索引太多致使負面的性能問題。

深刻原理推薦:Elasticsearch索引管理利器——Curator深刻詳解

1.三、Index Sorting
注意:索引排序機制是6.X版本纔有的特性。

在Elasticsearch中建立新索引時,能夠配置每一個分片中的分段的排序方式。 默認狀況下,Lucene不會應用任何排序。 index.sort.* 定義應使用哪些字段對每一個Segment內的文檔進行排序。

使用舉例:

1PUT /twitter
2{
3 "settings" : {
4 "index" : {
5 "sort.field" : "date",
6 "sort.order" : "desc"
7 }
8 },
9 "mappings": {
10 "properties": {
11 "date": {
12 "type": "date"
13 }
14 }
15 }
16}

目的:index sorting是優化Elasticsearch檢索性能的很是重要的方式之一。

大白話:index sorting機制經過寫入的時候指定了某一個或者多個字段的排序方式,會極大提高檢索的性能。

更深原理:推薦閱讀:

https://www.elastic.co/cn/blog/index-sorting-elasticsearch-6-0

二、分片層面優化配置
分片是底層基本的讀寫單元,分片的目的是分割巨大索引,讓讀寫並行執行。寫入過程先寫入主分片,主分片寫入成功後再寫入副本分片。

副本分片的出現,提高了集羣的高可用性和讀取吞吐率。

在優化分片時,分片的大小、節點中有多少分片是主要考慮因素。副本分片對於擴展搜索吞吐量很重要,若是硬件條件容許,則能夠當心增長副本分片的數量。

容量規劃的一個很好的啓動點是分配分片,「《深刻理解Elasticsearch》強調:最理想的分片數量應該依賴於節點的數量。」其數量是節點數量的1.5到3倍。

分配副本分片數的公式:max(max_failures,ceil(num_nodes /) num_primaries) - 1)。

原理:若是您的羣集具備num_nodes節點,總共有num_primaries主分片,若是您但願最多可以同時處理max_failures節點故障,那麼適合您的副本數量爲如上公式值。

公式來源:

https://www.elastic.co/guide/en/elasticsearch/reference/master/tune-for-search-speed.html

總的來講:節點數和分片數、副本數的簡單計算公式以下:
所需作大節點數=分片數*(副本數+1)。

三、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 動態設置
一、設置歷史數據索引爲只讀狀態。
基於時間的動態索引的執行階段,若是存放歷史數據的索引沒有寫操做,能夠將月度索引設置爲只讀模式,以提升對這些索引的搜索性能。
6.X以後的只讀索引實戰設置方式:

1PUT /twitter/_settings
2{
3 "index.blocks.read_only_allow_delete": null
4}

二、對只讀狀態索引,進行段合併。
當索引設置爲只讀時,能夠經過強制段合併操做以減小段的數量。

優化段合併將致使更好的搜索性能,由於每一個分片的開銷取決於段的計數和大小。

注意1:不要將段合併用於讀寫索引,由於它將致使產生很是大的段(每段> 5Gb)。

注意2:此操做應在非高峯時間進行,由於這是一項很是耗資源的操做。

段合併操做實戰方式:

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

三、使用preference優化緩存利用率
有多個緩存能夠幫助提升搜索性能,例如文件系統緩存,請求緩存或查詢緩存。

然而,全部這些緩存都維護在節點級別,這意味着若是您在擁有1個或更多副本且基於默認路由算法集羣上連續兩次運行相同的請求,這兩個請求將轉到不一樣的分片副本上 ,阻止節點級緩存幫助。

因爲搜索應用程序的用戶一個接一個地運行相似的請求是常見的,例如爲了檢索分析索引的部分較窄子集,使用preference標識當前用戶或會話的偏好值能夠幫助優化高速緩存的使用。

preference實戰舉例:

1GET /_search?preference=xyzabc123
2{
3 "query": {
4 "match": {
5 "title": "elasticsearch"
6 }
7 }

四、禁止交換
能夠在每一個節點上禁用交換以確保穩定性,而且應該不惜一切代價避免交換。它可能致使垃圾收集持續數分鐘而不是毫秒,而且可能致使節點響應緩慢甚至斷開與集羣的鏈接。

在Elasticsearch分佈式系統中,讓操做系統終止節點更有效。能夠經過將bootstrap.memory_lock設置爲True來禁用它。

Linux系統級配置:

1sudo swapoff -a

Elasticsearch配置文件elasticsearch.yml配置:

1bootstrap.memory_lock: true

五、增長刷新間隔 refresh_interval
默認刷新間隔爲1秒。這迫使Elasticsearch每秒建立一個分段。實際業務中,應該根據使用狀況增長刷新間隔,舉例:增長到30秒。

這樣以後,30s產生一個大的段,較每秒刷新大大減小將來的段合併壓力。最終會提高寫入性能並使搜索查詢更加穩定。

更新刷新間隔實戰:

1PUT /twitter/_settings
2{
3 "index" : {
4 "refresh_interval" : "1s"
5 }
6}

六、設置max_thread_count
index.merge.scheduler.max_thread_count默認設置爲

Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))

但這適用於SSD配置。對於HDD,應將其設置爲1。

實戰:

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

七、禁止動態分配分片
有時,Elasticsearch將從新平衡集羣中的分片。此操做可能會下降檢索的性能。

在生產模式下,須要時,能夠經過cluster.routing.rebalance.enable設置將從新平衡設置爲none。

1PUT /_cluster/settings
2{
3 "transient" : {
4 "cluster.routing.allocation.enable" : "none"
5 }
6}

其中典型的應用場景之包括:

集羣中臨時重啓、剔除一個節點;

集羣逐個升級節點;當您關閉節點時,分配過程將當即嘗試將該節點上的分片複製到集羣中的其餘節點,從而致使大量浪費的IO. 在關閉節點以前禁用分配能夠避免這種狀況。

更多實踐,推薦閱讀:

https://www.elastic.co/guide/en/elasticsearch/reference/5.5/restart-upgrade.html

八、充分利用近似日期緩存效果
如今使用的日期字段上的查詢一般不可緩存,由於匹配的範圍一直在變化。

然而,就用戶體驗而言,切換到近似日期一般是可接受的,而且能更好地使用查詢高速緩存帶來的益處。

實戰以下:

1GET index/_search
2{
3 "query": {
4 "constant_score": {
5 "filter": {
6 "range": {
7 "my_date": {
8 "gte": "now-1h/m",
9 "lte": "now/m"
10 }
11 }
12 }
13 }
14 }
15}

這裏可能不大好理解,推薦深刻閱讀:

https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-search-speed.html

3.2 初始設置
一、合併多字段提高檢索性能
query_string或multi_match查詢所針對的字段越多,檢索越慢。

提升多個字段的搜索速度的經常使用技術是在索引時將其值複製到單個字段中。

對於常常查詢的某些字段,請使用Elasticsearch的copy-to功能。

例如,汽車的品牌名稱,發動機版本,型號名稱和顏色字段能夠與複製到指令合併。它將改善在這些字段上進行的搜索查詢性能。

1PUT movies
2{
3 "mappings": {
4 "properties": {
5 "cars_infos": {
6 "type": "text"
7 },
8 "brand_name": {
9 "type": "text",
10 "copy_to": "cars_infos"
11 },
12 "engine_version": {
13 "type": "text",
14 "copy_to": "cars_infos"
15 },
16 "model ": {
17 "type": "text",
18 "copy_to": "cars_infos"
19 },
20 "color": {
21 "type": "text",
22 "copy_to": "cars_infos"
23 }
24 }
25 }
26}

二、設置分片分配到指定節點
實戰業務中常常遇到的業務場景問題:如何將分片設置非均衡分配,有新節點配置極高,可否多分片點過去?

某個 shard 分配在哪一個節點上,通常來講,是由 ES 自動決定的。如下幾種狀況會觸發分配動做:

1)新索引生成

2)索引的刪除

3)新增副本分片

4)節點增減引起的數據均衡

ES 提供了一系列參數詳細控制這部分邏輯,其中之一是:在異構集羣的情爲具備更好硬件的節點的分片分配分配權重。

爲了分配權重,

須要設置cluster.routing.allocation.balance.shard值,默認值爲0.45f。

數值越大越傾向於在節點層面均衡分片。

實戰:

1PUT _cluster/settings
2{
3「transient」 : {
4「cluster.routing.allocation.balance.shard」 : 0.60
5}
6}

三、調整熔斷內存比例大小
查詢自己也會對響應的延遲產生重大影響。爲了在查詢時不觸發熔斷並致使Elasticsearch集羣處於不穩定狀態,

能夠根據查詢的複雜性將indices.breaker.total.limit設置爲適合您的JVM堆大小。此設置的默認值是JVM堆的70%。

1PUT /_cluster/settings
2{
3 "persistent" : {
4 "indices.breaker.fielddata.limit" : "60%"
5 }
6}

最好爲斷路器設置一個相對保守點的值。更深原理推薦閱讀:

https://www.elastic.co/guide/cn/elasticsearch/guide/current/_limiting_memory_usage.html

《Elastic源碼分析》做者張超指出:「Elasticsearch 7.0 增長了 indices.breaker.total.use_real_memory 配置項,能夠更加精準的分析當前的內存狀況,及時防止 OOM 出現。雖然該配置會增長一點性能損耗,可是能夠提升 JVM 的內存使用率,加強了節點的保護機制。」

四、特定搜索場景,增長搜索線程池配置
默認狀況下,Elasticsearch將主要用例是搜索。在須要增長檢索併發性的狀況下,能夠增長用於搜索設置的線程池,與此同時,能夠根據節點上的CPU中的核心數量多少斟酌減小用於索引的線程池。

舉例:更改配置文件elasticsearch.yml增長以下內容:

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

官方:

https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html

五、打開自適應副本選擇
應打開自適應副本選擇。該請求將被重定向到響應最快的節點。

當存在多個數據副本時,elasticsearch可使用一組稱爲自適應副本選擇的標準,根據包含每一個分片副本的節點的響應時間,服務時間和隊列大小來選擇數據的最佳副本。

這樣能夠提升查詢吞吐量並減小搜索量大的應用程序的延遲。

這個配置默認是關閉的,實戰打開方法:

1PUT /_cluster/settings
2{
3 "transient": {
4 "cluster.routing.use_adaptive_replica_selection": true
5 }
6}

四、小結
Elasticsearch集羣有許多配置設置能夠減小響應延遲,提高檢索性能。 以上只是冰山一角。更多實踐配置推薦閱讀官方文檔之鼻祖級優化指南:

https://www.elastic.co/guide/en/elasticsearch/reference/6.7/tune-for-search-speed.html

本文受權翻譯至國外Burak Altaş的博文,結合實戰並仔細覈對官網最新7.2版本的配置,進行了細節的調整和改動,實操性更強。但願對你有幫助。

歡迎留言分享交流你在性能優化上的經驗和教訓。

相關文章
相關標籤/搜索