elasticsearch 生產級別深度優化

  這是一篇轉自別人的文章,真的講的很詳細。已經讀了很多遍,分享給大家。

  貼上原文地址(原文將了很多內容,這是優化方面摘取出來的):https://www.cnblogs.com/kevingrace/p/10682264.html

  這個優化文章主要包括五部分:系統方面包括集羣的部署,以及服務器環境,linux環境; 以及內存方面的優化,以及存儲方面的優化;搜索的優化(讀優化);還有寫優化。

 

目錄

 

一、Elasticserach性能優化

二、Elasticserach內存優化

三、Elasticserach存儲優化

四、Elasticserach搜索速度優化

五、Elasticserach寫入性能優化


一、Elasticserach性能優化

1.  硬件選擇
目前公司的物理機機型在CPU和內存方面都滿足需求,建議使用SSD機型。原因在於,可以快速把 Lucene 的索引文件加載入內存(這在宕機恢復的情況下尤爲明顯),減少 IO 負載和 IO wait以便CPU不總是在等待IO中斷。建議使用多裸盤而非raid,因爲 ElasticSearch 本身就支持多目錄,raid 要麼犧牲空間要麼犧牲可用性。

2. 系統配置
ElasticSearch 理論上必須單獨部署,並且會獨佔幾乎所有系統資源,因此需要對系統進行配置,以保證運行 ElasticSearch 的用戶可以使用足夠多的資源。生產集羣需要調整的配置如下:
1. 設置 JVM 堆大小;
2. 關閉 swap;
3. 增加文件描述符;
4. 保證足夠的虛存;
5. 保證足夠的線程;
6. 暫時不建議使用G1GC;

3. 設置 JVM 堆大小
ElasticSearch 需要有足夠的 JVM 堆支撐索引數據的加載,對於公司的機型來說,因爲都是大於 128GB 的,所以推薦的配置是 32GB(如果 JVM 以不等的初始和最大堆大小啓動,則在系統使用過程中可能會因爲 JVM 堆的大小調整而容易中斷。 爲了避免這些調整大小的暫停,最好使用初始堆大小等於最大堆大小的 JVM 來啓動),預留足夠的 IO Cache 給 Lucene(官方建議超過一半的內存需要預留)。

4. 關閉 swap & 禁用交換
必須要關閉 swap,因爲在物理內存不足時,如果發生 FGC,在回收虛擬內存的時候會造成長時間的 stop-the-world,最嚴重的後果是造成集羣雪崩。公司的默認模板是關閉的,但是要巡檢一遍,避免有些機器存在問題。設置方法:

1

2

3

4

5

6

7

8

9

10

Step1. root 用戶臨時關閉

# swapoff -a

# sysctl vm.swappiness=0

 

Step2. 修改 /etc/fstab,註釋掉 swap 這行

Step3. 修改 /etc/sysctl.conf,添加:

vm.swappiness = 0

 

Step4. 確認是否生效

# sysctl vm.swappiness

也可以通過修改 yml 配置文件的方式從 ElasticSearch 層面禁止物理內存和交換區之間交換內存,修改 ${PATH_TO_ES_HOME}/config/elasticsearch.yml,添加:
bootstrap.memory_lock: true

==========================小提示=======================
Linux 把它的物理 RAM 分成多個內存塊,稱之爲分頁。內存交換(swapping)是這樣一個過程,它把內存分頁複製到預先設定的叫做交換區的硬盤空間上,以此釋放內存分頁。物理內存和交換區加起來的大小就是虛擬內存的可用額度。

內存交換有個缺點,跟內存比起來硬盤非常慢。內存的讀寫速度以納秒來計算,而硬盤是以毫秒來計算,所以訪問硬盤比訪問內存要慢幾萬倍。交換次數越多,進程就越慢,所以應該不惜一切代價避免內存交換的發生。

ElasticSearch 的 memory_lock 屬性允許 Elasticsearch 節點不交換內存。(注意只有Linux/Unix系統可設置。)這個屬性可以在yml文件中設置。
======================================================

5. 增加文件描述符
單個用戶可用的最大進程數量(軟限制)&單個用戶可用的最大進程數量(硬限制),超過軟限制會有警告,但是無法超過硬限制。 ElasticSearch 會使用大量的文件句柄,如果超過限制可能會造成宕機或者數據缺失。

文件描述符是用於跟蹤打開“文件”的 Unix 結構體。在Unix中,一切都皆文件。 例如,“文件”可以是物理文件,虛擬文件(例如/proc/loadavg)或網絡套接字。 ElasticSearch 需要大量的文件描述符(例如,每個 shard 由多個 segment 和其他文件組成,以及到其他節點的 socket 連接等)。

設置方法(假設是 admin 用戶啓動的 ElasticSearch 進程):

1

2

3

4

5

6

7

8

9

10

# Step1. 修改 /etc/security/limits.conf,添加:

admin soft nofile 65536

admin hard nofile 65536

 

# Step2. 確認是否生效

su - admin

ulimit -n

 

# Step3. 通過 rest 確認是否生效

GET /_nodes/stats/process?filter_path=**.max_file_descriptors

6. 保證足夠的虛存
單進程最多可以佔用的內存區域,默認爲 65536。Elasticsearch 默認會使用 mmapfs 去存儲 indices,默認的 65536 過少,會造成 OOM 異常。設置方法:

1

2

3

4

5

6

7

8

# Step1. root 用戶修改臨時參數

sudo sysctl -w vm.max_map_count=262144

 

# Step2. 修改 /etc/sysctl.conf,在文末添加:

vm.max_map_count = 262144

 

# Step3. 確認是否生效

sudo sysctl vm.max_map_count

7. 保證足夠的線程
Elasticsearch 通過將請求分成幾個階段,並交給不同的線程池執行(Elasticsearch 中有各種不同的線程池執行器)。 因此,Elasticsearch 需要創建大量線程的能力。進程可創建線程的最大數量確保 Elasticsearch 進程有權在正常使用情況下創建足夠的線程。 這可以通過/etc/security/limits.conf 使用 nproc 設置來完成。設置方法:

1

2

修改 /etc/security/limits.d/90-nproc.conf,添加:

admin soft nproc 2048

8. 暫時不建議使用G1GC
已知 JDK 8 附帶的 HotSpot JVM 的早期版本在啓用 G1GC 收集器時會導致索引損壞。受影響的版本是早於 JDK 8u40 附帶的HotSpot 的版本,出於穩定性的考慮暫時不建議使用。

 

二、Elasticserach內存優化

ElasticSearch 自身對內存管理進行了大量優化,但對於持續增長的業務仍需進行一定程度的內存優化(而不是純粹的添加節點和擴展物理內存),以防止 OOM 發生。ElasticSearch 使用的 JVM 堆中主要包括以下幾類內存使用:
1. Segment Memory;
2. Filter Cache;
3. Field Data Cache;
4. Bulk Queue;
5. Indexing Buffer;
6. Cluster State Buffer;
7. 超大搜索聚合結果集的 fetch;

1. 減少 Segment Memory
-  刪除無用的歷史索引。刪除辦法,使用 rest API

1

2

3

4

5

# 刪除指定某個索引

DELETE /${INDEX_NAME}

 

# 刪除符合 pattern 的某些索引

DELETE /${INDEX_PATTERN}

-  關閉無需實時查詢的歷史索引,文件仍然存在於磁盤,只是釋放掉內存,需要的時候可以重新打開。關閉辦法,使用 rest API

1

2

3

4

5

# 關閉指定某個索引

POST /${INDEX_NAME}/_close

 

# 關閉符合 pattern 的某些索引

POST /${INDEX_PATTERN}/_close

-  定期對不再更新的索引做 force merge(會佔用大量 IO,建議業務低峯期觸發)force merge 辦法,使用 rest API

1

2

3

4

5

6

7

8

9

10

11

12

13

# Step1. 在合併前需要對合並速度進行合理限制,默認是 20mb,SSD可以適當放寬到 80mb:

PUT /_cluster/settings -d '

{

    "persistent" : {

        "indices.store.throttle.max_bytes_per_sec" "20mb"

    }

}'

  

# Step2. 強制合併 API,示例表示的是最終合併爲一個 segment file:

# 對某個索引做合併

POST /${INDEX_NAME}/_forcemerge?max_num_segments=1

# 對某些索引做合併

POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1

2. Filter Cache
默認的 10% heap 設置工作得夠好,如果實際使用中 heap 沒什麼壓力的情況下,才考慮加大這個設置。

3. Field Data Cache
對需要排序的字段不進行 analyzed,儘量使用 doc values(5.X版本天然支持,不需要特別設置)。對於不參與搜索的字段 ( fields ),將其 index 方法設置爲 no,如果對分詞沒有需求,對參與搜索的字段,其 index 方法設置爲 not_analyzed。

4. Bulk Queue
一般來說官方默認的 thread pool 設置已經能很好的工作了,建議不要隨意去調優相關的設置,很多時候都是適得其反的效果。

5. Indexing Buffer
這個參數的默認值是10% heap size。根據經驗,這個默認值也能夠很好的工作,應對很大的索引吞吐量。 但有些用戶認爲這個 buffer 越大吞吐量越高,因此見過有用戶將其設置爲 40% 的。到了極端的情況,寫入速度很高的時候,40%都被佔用,導致OOM。

6. Cluster State Buffer
在超大規模集羣的情況下,可以考慮分集羣並通過 tribe node 連接做到對用戶透明,這樣可以保證每個集羣裏的 state 信息不會膨脹得過大。在單集羣情況下,縮減 cluster state buffer 的方法就是減少 shard 數量,shard 數量的確定有以下幾條規則:
1.  避免有非常大的分片,因爲大分片可能會對集羣從故障中恢復的能力產生負面影響。 對於多大的分片沒有固定限制,但分片大小爲 50GB 通常被界定爲適用於各種用例的限制;
2.  儘可能使用基於時間的索引來管理數據。根據保留期(retention period,可以理解成有效期)將數據分組。基於時間的索引還可以輕鬆地隨時間改變主分片和副本分片的數量(以爲要生成的下一個索引進行更改)。這簡化了適應不斷變化的數據量和需求;(週期性的通過刪除或者關閉歷史索引以減少分片)
3.  小分片會導致小分段(segment),從而增加開銷。目的是保持平均分片大小在幾GB和幾十GB之間。對於具有基於時間數據的用例,通常看到大小在 20GB 和 40GB 之間的分片;
4.  由於每個分片的開銷取決於分段數和大小,通過強制操作迫使較小的段合併成較大的段可以減少開銷並提高查詢性能。一旦沒有更多的數據被寫入索引,這應該是理想的。請注意,這是一個消耗資源的(昂貴的)操作,較爲理想的處理時段應該在非高峯時段執行;(對應使用 force meger 以減少 segment 數量的優化,目的是降低 segment memory 佔用)
5.  可以在集羣節點上保存的分片數量與可用的堆內存大小成正比,但這在 Elasticsearch 中沒有的固定限制。 一個很好的經驗法則是:確保每個節點的分片數量保持在低於每 1GB 堆內存對應集羣的分片在 20-25 之間。 因此,具有 32GB 堆內存的節點最多可以有 600-750 個分片;
6.  對於單索引的主分片數,有這麼 2 個公式:節點數 <= 主分片數 *(副本數 + 1) 以及 (同一索引 shard 數量 * (1 + 副本數)) < 3 * 數據節點數,比如有 3 個節點全是數據節點,1 個副本,那麼主分片數大於等於 1.5,同時同一索引總分片數需要小於 4.5,因爲副本數爲 1,所以單節點主分片最適爲 2,索引總分片數最適爲 6,這樣每個節點的總分片爲 4;
7.  單分片小於 20GB 的情況下,採用單分片較爲合適,請求不存在網絡抖動的顧慮;

小結:分片不超 20GB,且單節點總分片不超 600。比如互聯網區域,每天新建索引(lw-greenbay-online) 1 個分片 1 個副本,3 個月前的歷史索引都關閉,3 節點總共需要扛 90 * 2 = 180 個分片,每個分片大約 6 GB,可謂比較健康的狀態。

7. 超大搜索聚合結果集的 fetch
避免用戶 fetch 超大搜索聚合結果集,確實需要大量拉取數據可以採用 scan & scroll API 來實現。在 ElasticSearch 上搜索數據時,默認只會返回10條文檔,當我們想獲取更多結果,或者只要結果中的一個區間的數據時,可以通過 size 和 from 來指定。

1

GET /_search?size=3&from=20

如上的查詢語句,會返回排序後的結果中第 20 到第 22 條數據。ElasticSearch 在收到這樣的一個請求之後,每一個分片都會返回一個 top22 的搜索結果,然後將這些結果彙總排序,再選出 top22 ,最後取第 20 到第 22 條數據作爲結果返回。這樣會帶來一個問題,當我們搜索的時候,如果想取出第 10001 條數據,那麼就相當於每個一分片都要對數據進行排序,取出前 10001 條文檔,然後 ElasticSearch 再將這些結果彙總再次排序,之後取出第 10001 條數據。這樣對於 ElasticSearch 來說就會產生相當大的資源和性能開銷。如果我們不要求 ElasticSearch 對結果進行排序,那麼就會消耗很少的資源,所以針對此種情況,ElasticSearch 提供了scan & scroll的搜索方式。

1

2

3

4

5

GET /old_index/_search?search_type=scan&scroll=1m

{

    "query": { "match_all": {}},

    "size":  1000

}

我們可以首先通過如上的請求發起一個搜索,但是這個請求不會返回任何文檔,它會返回一個 _scroll_id ,接下來我們再通過這個 id 來從 ElasticSearch 中讀取數據:

1

2

GET /_search/scroll?scroll=1m

c2Nhbjs1OzExODpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExOTpRNV9aY1VyUVM4U0 NMd2pjWlJ3YWlBOzExNjpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzExNzpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzEyMDpRNV9aY1VyUVM4U0NMd2pjWlJ3YWlBOzE7dG90YWxfaGl0czoxOw==

此時除了會返回搜索結果以外,還會再次返回一個 _scroll_id,當我們下次繼續取數據時,需要用最新的 id。

 

三、Elasticserach存儲優化

1. 關閉不需要的功能
默認情況下 ElasticSearch 會將 indexs 和 doc values 添加到大多數字段中,以便可以搜索和聚合它們。 例如,如果有一個名爲 foo 的數字字段,需要運行 histograms 但不需要 filter,則可以安全地禁用映射中此字段的索引:

1

2

3

4

5

6

7

8

9

10

11

12

13

PUT ${INDEX_NAME}

{

  "mappings": {

    "type": {

      "properties": {

        "foo": {

          "type""integer",

          "index"false

        }

      }

    }

  }

}

text 字段在索引中存儲規範化因子以便能夠對文檔進行評分。 如果只需要在 text 字段上使用 matching 功能,但不關心生成的 score,則可以命令 ElasticSearch 配置爲不將規範寫入索引:

1

2

3

4

5

6

7

8

9

10

11

12

13

PUT ${INDEX_NAME}

{

  "mappings": {

    "type": {

      "properties": {

        "foo": {

          "type""text",

          "norms"false

        }

      }

    }

  }

}

text 字段也默認存儲索引中的頻率和位置。 頻率用於計算分數,位置用於運行短語查詢(phrase queries)。 如果不需要運行短語查詢,可以告訴 ElasticSearch 不要索引位置:

1

2

3

4

5

6

7

8

9

10

11

12

13

PUT ${INDEX_NAME}

{

  "mappings": {

    "type": {

      "properties": {

        "foo": {

          "type""text",

          "index_options""freqs"

        }

      }

    }

  }

}

此外,如果不關心計分,則可以配置 ElasticSearch 以僅索引每個 term 的匹配文檔。 這樣做仍然可以在此字段上進行搜索(search),但是短語查詢會引發錯誤,評分將假定 term 在每個文檔中只出現一次。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

PUT ${INDEX_NAME}

{

  "mappings": {

    "type": {

      "properties": {

        "foo": {

          "type""text",

          "norms"false,

          "index_options""freqs"

        }

      }

    }

  }

}

2. 強制清除已標記刪除的數據
Elasticsearch 是建立在 Apache Lucene 基礎上的實時分佈式搜索引擎,Lucene 爲了提高搜索的實時性,採用不可再修改(immutable)方式將文檔存儲在一個個 segment 中。也就是說,一個 segment 在寫入到存儲系統之後,將不可以再修改。那麼 Lucene 是如何從一個 segment 中刪除一個被索引的文檔呢?簡單的講,當用戶發出命令刪除一個被索引的文檔#ABC 時,該文檔並不會被馬上從相應的存儲它的 segment 中刪除掉,而是通過一個特殊的文件來標記該文檔已被刪除。當用戶再次搜索到 #ABC 時,Elasticsearch 在 segment 中仍能找到 #ABC,但由於 #ABC 文檔已經被標記爲刪除,所以Lucene 會從發回給用戶的搜索結果中剔除 #ABC,所以給用戶感覺的是 #ABC 已經被刪除了。

Elasticseach 會有後臺線程根據 Lucene 的合併規則定期進行 segment merging 合併操作,一般不需要用戶擔心或者採取任何行動。被刪除的文檔在 segment 合併時,纔會被真正刪除掉。在此之前,它仍然會佔用着JVM heap和操作系統的文件cach 等資源。在某些情況下,需要強制 Elasticsearch 進行 segment merging,已釋放其佔用的大量系統資源。

1

2

POST /${INDEX_NAME}/_forcemerge?max_num_segments=1&only_expunge_deletes=true&wait_for_completion=true

POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1&only_expunge_deletes=true&wait_for_completion=true

Force Merge 命令可強制進行 segment 合併,並刪除所有標記爲刪除的文檔。Segment merging 要消耗 CPU,以及大量的 I/O 資源,所以一定要在 ElasticSearch 集羣處於維護窗口期間,並且有足夠的 I/O 空間的(如:SSD)的條件下進行;否則很可能造成集羣崩潰和數據丟失。

3. 減少副本數
最直接的存儲優化手段是調整副本數,默認 ElasticSearch 是有 1 個副本的,假設對可用性要求不高,允許磁盤損壞情況下可能的數據缺失,可以把副本數調整爲0,操作如下:

1

2

3

4

5

6

7

8

9

PUT  /_template/${TEMPLATE_NAME}

{

  

  "template":"${TEMPLATE_PATTERN}",

  "settings" : {

    "number_of_replicas" : 0

  },

  "version"  : 1

}

其中 ${TEMPLATE_NAME} 表示模板名稱,可以是不存在的,系統會新建。${TEMPLATE_PATTERN} 是用於匹配索引的表達式,比如 lw-greenbay-online-*。

與此相關的一個系統參數爲:index.merge.scheduler.max_thread_count,默認值爲 Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),這個值在 SSD 上工作沒問題,但是 SATA 盤上還是使用 1 個線程爲好,因爲太多也來不及完成。

1

2

3

4

5

6

7

8

9

# SATA 請設置 merge 線程爲 1

PUT  /_template/${TEMPLATE_NAME}

{

  "template":"${TEMPLATE_PATTERN}",

  "settings" : {

    "index.merge.scheduler.max_thread_count": 1

  },

  "version"  : 1

}

4. 請勿使用默認的動態字符串映射
默認的動態字符串映射會將字符串字段索引爲文本(text)和關鍵字(keyword)。 如果只需要其中的一個,這樣做無疑是浪費的。 通常情況下,一個 id 字段只需要被索引爲一個 keyword,而一個 body 字段只需要被索引爲一個 text 字段。可以通過在字符串字段上配置顯式映射或設置將字符串字段映射爲文本(text)或關鍵字(keyword)的動態模板來禁用此功能。例如下面的模板,可以用來將 strings 字段映射爲關鍵字:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

PUT ${INDEX_NAME}

{

  "mappings": {

    "type": {

      "dynamic_templates": [

        {

          "strings": {

            "match_mapping_type""string",

            "mapping": {

              "type""keyword"

            }

          }

        }

      ]

    }

  }

}

5. 禁用 _all 字段
_all 字段是由所有字段拼接成的超級字段,如果在查詢中已知需要查詢的字段,就可以考慮禁用它。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

PUT /_template/${TEMPLATE_NAME}

{

  "template""${TEMPLATE_PATTERN}",

  "settings" : {...},

  "mappings": {

    "type_1": {

      "_all": {

         "enabled"false

       },

      "properties": {...}

   }

  },

  "version"  : 1

}

6. 使用 best_compression
_source 字段和 stored fields 會佔用大量存儲,可以考慮使用 best_compression 進行壓縮。默認的壓縮方式爲 LZ4,但需要更高壓縮比的話,可以通過 inex.codec 進行設置,修改爲 DEFLATE,在 force merge 後生效:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

# Step1. 修改壓縮算法爲 best_compression

PUT  /_template/${TEMPLATE_NAME}

{

  

  "template":"${TEMPLATE_PATTERN}",

  "settings" : {

    "index.codec" "best_compression"

  },

  "version"  : 1

}

 

# Step2. force merge

POST /${INDEX_NAME}/_forcemerge?max_num_segments=1&wait_for_completion=true

POST /${INDEX_PATTERN}/_forcemerge?max_num_segments=1&wait_for_completion=true

7. 使用最優數據格式
我們爲數字數據選擇的類型可能會對磁盤使用量產生重大影響。 首先,應使用整數類型(byte,short,integer或long)來存儲整數,浮點數應該存儲在 scaled_float 中,或者存儲在適合用例的最小類型中:使用 float 而不是 double,使用 half_float 而不是 float。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

PUT /_template/${TEMPLATE_NAME}

{

  "template""${TEMPLATE_PATTERN}",

  "settings" : {...},

  "mappings": {

    "type_1": {

      "${FIELD_NAME}": {

         "type""integer"

       },

      "properties": {...}

   }

  },

  "version"  : 1

}

 

四、Elasticserach搜索速度優化

1. 避免Join和Parent-Child
Join會使查詢慢數倍、 Parent-Child會使查詢慢數百倍,請在進行 query 語句編寫的時候儘量避免。

2. 映射
某些數據本身是數字,但並不意味着它應該總是被映射爲一個數字字段。 通常存儲着標識符的字段(如ISBN)或來自另一個數據庫的數字型記錄,可能映射爲 keyword 而不是 integer 或者 long 會更好些。

3. 避免使用 Scripts
之前 Groovy 腳本曝出了很大的漏洞,總的來說是需要避免使用的。如果必須要使用,儘量用 5.X 以上版本自帶的 painless 和 expressions 引擎。

4. 根據四捨五入的日期進行查詢
根據 timestamp 字段進行的查詢通常不可緩存,因爲匹配的範圍始終在變化。 但就用戶體驗而言,以四捨五入對日期進行轉換通常是可接受的,這樣可以有效利用系統緩存。舉例說明,有以下查詢:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

PUT index/type/1

{

  "my_date""2016-05-11T16:30:55.328Z"

}

  

GET index/_search

{

  "query": {

    "constant_score": {

      "filter": {

        "range": {

          "my_date": {

            "gte""now-1h",

            "lte""now"

          }

        }

      }

    }

  }

}

可以對時間範圍進行替換:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

GET index/_search

{

  "query": {

    "constant_score": {

      "filter": {

        "range": {

          "my_date": {

            "gte""now-1h/m",

            "lte""now/m"

          }

        }

      }

    }

  }

}

在這種情況下,我們四捨五入到分鐘,所以如果當前時間是 16:31:29 ,範圍查詢將匹配 my_date 字段的值在 15:31:00 和16:31:59 之間的所有內容。 如果多個用戶在同一分鐘內運行包含這個範圍的查詢,查詢緩存可以幫助加快速度。 用於四捨五入的時間間隔越長,查詢緩存可以提供的幫助就越多,但要注意過於積極的舍入也可能會傷害用戶體驗。

爲了能夠利用查詢緩存,建議將範圍分割成大的可緩存部分和更小的不可緩存的部分,如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

GET index/_search

{

  "query": {

    "constant_score": {

      "filter": {

        "bool": {

          "should": [

            {

              "range": {

                "my_date": {

                  "gte""now-1h",

                  "lte""now-1h/m"

                }

              }

            },

            {

              "range": {

                "my_date": {

                  "gt""now-1h/m",

                  "lt""now/m"

                }

              }

            },

            {

              "range": {

                "my_date": {

                  "gte""now/m",

                  "lte""now"

                }

              }

            }

          ]

        }

      }

    }

  }

}

然而,這種做法可能會使查詢在某些情況下運行速度較慢,因爲由 bool 查詢引入的開銷可能會因更好地利用查詢緩存而失敗。

5. 對只讀 indices 進行 force merge
建議將只讀索引被合併到一個單獨的分段中。 基於時間的索引通常就是這種情況:只有當前時間索引會寫入數據,而舊索引是隻讀索引。

6. 預熱 global ordinals
全局序號(global ordinals)是用於在關鍵字(keyword)字段上運行 terms aggregations 的數據結構。 由於 ElasticSearch 不知道聚合使用哪些字段、哪些字段不使用,所以它們在內存中被加載得很慢。 我們可以通過下面的 API 來告訴 ElasticSearch 通過配置映射來在 refresh 的時候加載全局序號:

1

2

3

4

5

6

7

8

9

10

11

12

13

PUT index

{

  "mappings": {

    "type": {

      "properties": {

        "foo": {

          "type""keyword",

          "eager_global_ordinals"true

        }

      }

    }

  }

}

 

五、Elasticserach寫入性能優化

之前描述了 ElasticSearch 在內存管理方面的優化,接下來梳理下如何對寫入性能進行優化,寫入性能的優化也和 HBase 類似,無非就是增加吞吐,而增加吞吐的方法就是增大刷寫間隔、合理設置線程數量、開啓異步刷寫(允許數據丟失的情況下)。

1. 增大刷寫間隔
通過修改主配置文件 elasticsearch.yml 或者 Rest API 都可以對 index.refresh_interval進行修改,增大該屬性可以提升寫入吞吐。

1

2

3

4

5

6

7

8

9

10

11

12

PUT  /_template/{TEMPLATE_NAME}

{

  "template":"{INDEX_PATTERN}",

  "settings" : {

    "index.refresh_interval" "30s"

  }

}

  

PUT {INDEX_PAATERN}/_settings

{

    "index.refresh_interval" "30s"

}

2. 合理設置線程數量
調整 elasticsearch.yml ,對 bulk/flush 線程池進行調優,根據本機實際配置:

1

2

3

4

threadpool.bulk.type:fixed

threadpool.bulk.size:8 #(CPU核數)

threadpool.flush.type:fixed

threadpool.flush.size:8 #(CPU核數)

3. 開啓異步刷寫
如果允許數據丟失,可以對特定 index 開啓異步刷寫:

1

2

3

4

5

6

7

8

9

10

11

12

PUT  /_template/{TEMPLATE_NAME}

{

  "template":"{INDEX_PATTERN}",

  "settings" : {

    "index.translog.durability""async"

  }

}

  

PUT  {INDEX_PAATERN}/_settings

{

  "index.translog.durability""async"

}

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