Elasticsearch高級調優方法論之——根治慢查詢!


1、引言

Elasticsearch是非常靈活且功能豐富的搜索引擎,它提供了許多不同查詢數據的方法。在實戰業務場景中,經常會出現遠遠低於預期查詢速度的慢查詢。作爲分佈式系統的Elasticsearch,可能有各種影響查詢性能的因素,包括外部因素,如負載均衡設置,網絡延遲(帶寬,NIC卡/驅動程序)等。

本文主要討論可能導致慢查詢的原因以及如何在Elasticsearch的上下文中識別它們?

本文主要源於常見慢查詢故障的排除方法,閱讀本文的前提需要你對Elasticsearch的原理有大致的瞭解。

如果不瞭解Elastic相關原理,可以移步:elastic.blog.csdn.net 或 歷史文章。

如果不瞭解慢查詢,可以移步:爲什麼Elasticsearch查詢變得這麼慢了?

本文的目的:根治慢查詢

2、Elasticsearch慢查詢六大症狀及解決方案

在我們研究一些棘手的案例之前,讓我們從一些最常見的慢查詢及其解決方案開始。

2.1 症狀1:非活動(檢索/寫入)狀態資源利用率也非常高

症狀詳情:每個分片都消耗資源(CPU /內存)。即使沒有索引/搜索請求,分片的存在也會消耗集羣開銷。

2.1.1 問題描述

集羣中的分片太多,以至於任何查詢執行起來都很慢。一個好的經驗法則——確保每個節點的非凍結分片數量保持在:20以下/每GB堆內存。

2.1.2 解決方案
  • 1、部署之前,設計先行。
    正如VIVO搜索技術總監振濤兄所說:“集羣規劃核心是容量預估,就好比你建個樓,必須規劃好容量,不然說用多少就建多高,吃在地基撐不住!!”。

    任何部署的良好開端都是執行適當的容量規劃,以幫助確定每個搜索用例的最佳分片數。

  • 2、減少分片數,實施凍結索引或添加其他節點以實現負載均衡。

  • 3、考慮冷熱數據分離架構(適用於基於時間的索引)以及Elasticsearch中的翻轉索引(rollover)/壓縮索引(shrink)功能,以有效管理分片計數。

推薦閱讀:我在 Elasticsearch 集羣內應該設置多少個分片?
https://www.elastic.co/cn/blog/how-many-shards-should-i-have-in-my-elasticsearch-cluster

Elasticsearch5.x冷熱架構實現
https://www.elastic.co/cn/blog/hot-warm-architecture-in-elasticsearch-5-x

容量規劃最佳實踐(必讀)
https://www.elastic.co/guide/en/elasticsearch/guide/master/capacity-planning.html

2.2 症狀2:線程池存在大量rejected

搜索線程池顯示“拒絕”計數的持續增加,該計數基於上次羣集重新啓動而累積。

1GET / _cat / thread_pool / search?v&h = node_name,name,active,rejected,completed

響應如下:

1node_name             name   active rejected completed
2instance-0000000001   search      0       10         0
3instance-0000000002   search      0       20         0
4instance-0000000003   search      0       30         0

2.2.1 問題描述

場景1:查詢的目標是太多分片,超過集羣中的CPU核數。這會在搜索線程池中創建排隊任務,從而導致搜索拒絕。

場景2:磁盤I/O速度慢或在某些情況下完全飽和的CPU導致搜索排隊。

2.2.2 解決方案

1、創建索引時採用1主分片&1副本模型。
使用索引模板是在創建索引階段做好設置是個好方法。(7.0及更高版本默認1主1副)。

2、 Elasticsearch 5.1或更高版本支持搜索任務取消,這對於取消顯示在任務管理API中慢查詢任務非常有用。

任務管理:

1GET _tasks?nodes=nodeId1,nodeId2

取消任務

1POST _tasks/oTUltX4IQMOUUVeiohTt8A:12345/_cancel

3、要改進磁盤I / O,請查看我們的存儲建議,並確保使用推薦的硬件以獲得最佳性能。

存儲優化建議:
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/tune-for-indexing-speed.html#_use_faster_hardware

2.3 症狀3:高CPU和索引化延遲

當集羣不堪重負時,度量標準關聯顯示CPU利用率高和索引化延遲大(如下圖)。

640?wx_fmt=png

Metric指標Kibana覈查方法:

https://www.elastic.co/guide/en/kibana/7.0/elasticsearch-metrics.html

2.3.1 問題描述

寫入數據量大(索引化)會影響搜索性能。

2.3.2 解決方案

1、調大刷新頻率

將index.refresh_ interval(文檔被索引到數據搜索可見時間間隔)增加到 30 s,通常有助於提高索引性能。

實戰中要結合具體業務場景,可能會有所不同,因此測試是關鍵。這樣避免了缺省一秒生成一個分段的麻煩。

2、對於重型索引用例,請檢查我們的索引調整建議,以優化索引和搜索性能。

包含但不限於:
1)數據初始化階段refresh設置 -1、副本設置爲 0,以提升寫入速度;寫入完畢後復原。
2)關閉swapping。
3)使用文件系統緩存。
4)使用自動生成ID。

性能調優實踐:
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/tune-for-indexing-speed.html#_disable_refresh_and_replicas_for_initial_loads

2.4 症狀4:副本增加後延時增大

在增加副本分片計數(例如,從1到2)之後可以觀察到查詢等待時間。如果存在更多數據,則緩存的數據將很快被逐出,導致操作系統層面頁面錯誤增加。

2.4.1 問題描述

文件系統緩存沒有足夠的內存來緩存經常查詢的索引部分。

Elasticsearch的查詢緩存實現了LRU置換算法:當緩存變滿時,最近最少使用的數據被置換以便爲新數據騰出空間。

請求緩存:

https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-cache.html

2.4.2 解決方案

1、爲文件系統緩存留出至少 50 %的物理RAM。

內存越多,可以緩存的越多,尤其是在集羣遇到I / O問題時。假設堆大小已正確配置,剩下的任何可用於文件系統緩存的剩餘物理RAM都可以大大加快搜索性能。

堆內存大小配置建議:Min(32 GB,物理機器內存 / 2)。

例如,128 GB內存服務器爲堆提供 30GB空間,爲文件系統緩存(有時稱爲OS緩存)留出剩餘內存,假設操作系統緩存最近訪問的4KB數據塊,如果你再一次讀取相同的文件,不需要花很長時間去磁盤上讀,直接在內存上讀來的更快。

2、使用query緩存和request緩存加快檢索速度。

節點級別的query緩存默認是開啓的。對應配置:

1index.queries.cache.enabled

請求緩存默認是開啓的,如果被強制關閉了,可以動態設置開啓。

1PUT /my_index/_settings
2"index.requests.cache.enable"true }

3、使用preference優化高速緩存

可以使用搜索請求首選項preference來優化所有這些高速緩存。以便每次將某些搜索請求路由到同一組分片,而不是在可用的不同副本之間交替

這將更好地利用請求緩存、節點查詢緩存和文件系統緩存。

2.5 症狀5:共享硬件資源時的高資源利用率。

操作系統顯示始終較高的CPU 、磁盤、I / O使用率。

停止第三方應用程序後可以看到性能提升。

2.5.1 問題描述

其他進程(例如Logstash)和Elasticsearch本身之間存在資源(CPU、內存、或磁盤I / O)爭用。

2.5.2 解決方案

給Elasticsearch隔離的硬件環境或虛擬環境。

避免在共享硬件上與其他資源密集型應用程序一起運行Elasticsearch。

2.6 症狀6:聚合N多唯一值引起的高內存使用率

查詢包含唯一值(例如,ID,用戶名,電子郵件地址等)的聚合字段時性能不佳。

在堆內存分析時發現:Java對象使用"search", "buckets", "aggregation"等術語,消耗大量的堆內存。

2.6.1 問題原因

聚合在高基數(high-cardinality)字段上運行,需要大量資源來獲取許多存儲桶。

還可以存在涉及nested字段和/或join字段的嵌套聚合。

註解:high-cardinality中文解讀爲高基數不好理解。舉個例子:

  • 高基數——列中有很多唯一值(),如主鍵

  • 低基數——與之相反,如性別列(只有男、女)。

2.6.2 解決方案

1、要提高高基數term聚合的性能,推薦閱讀:

https://www.elastic.co/cn/blog/improving-the-performance-of-high-cardinality-terms-aggregations-in-elasticsearch

核心:使用eager_global_ordinals: true 提升性能。

2、有關進一步調整,請查看官網nested字段類型和join字段類型的使用建議,以更好地提高聚合性能。

3 偶發慢查詢解決方案

一般而言,偶爾或間歇性慢查詢可以從官網的優化索引、優化檢索建議中中受益。

3.1 偶發慢查詢關聯監控指標

偶發慢查詢應與這些監控指標中的一個或多個密切相關:

  • 1)CPU負載

  • 2)索引吞吐量

  • 3)搜索吞吐量

  • 4)垃圾收集(GC)活動

  • 5)搜索線程池隊列大小

線程池查看方法:

1GET /_cat/thread_pool

3.2 ARS提升檢索吞吐率

Elasticsearch還有另一個有用的功能,稱爲自適應副本選擇(ARS),它允許協調節點了解數據節點上的負載,並允許它選擇最佳的分片副本來執行搜索,從而提高搜索吞吐量、降低延遲。

通過在查詢時間內更均勻地分散負載,ARS可以對偶爾的減速有很大幫助。

在Elasticsearch 7.0及更高版本中,默認情況下將啓用ARS

4 非偶發慢查詢解決方案

對於非偶發慢查詢的場景,我們可以嘗試逐個刪除查詢中的功能,並檢查查詢是否仍然很慢。

4.1 “拆解DSL”排查慢查詢根源

查找最簡單查詢以重現性能問題有助於隔離和識別問題:

  • 1)沒有高亮顯示它仍然很慢嗎?

  • 2)沒有聚合,它仍然很慢嗎?

  • 3)如果size設置爲0,它仍然很慢嗎?
    當size設置爲0時,Elasticsearch會緩存搜索請求的結果,以便更快地進行搜索

4.2 參考官方搜索優化建議,看是否湊效?

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

4.3 慢查詢排除實踐

  • 1)啓用"profile:true"。

1GET /twitter/_search
2{
3  "profile"true,
4  "query" : {
5    "match" : { "message" : "some number" }
6  }
7}

  • 2)查看節點的熱點線程。

這有助於瞭解CPU時間的使用情況。

1GET /_nodes/hot_threads

  • 3)使用kibana可視化profile分析工具

https://www.elastic.co/guide/en/kibana/7.0/xpack-profiler.html

5 捕獲慢查詢、耗費資源查詢

5.1 慢查詢、耗費資源查詢難捕獲

在Elasticsearch中同時處理不同的請求/線程時,很難捕獲慢查詢、耗費資源查詢。

實際N多人應用的業務場景,當無法定位耗費資源查詢的用戶時,情況變得更加複雜,這些查詢會降低集羣性能(例如,長垃圾收集(GC)週期)或更糟糕的是內存不足(OOM)情況。

在Elasticsearch 7.0版中,我們引入了一種新的內存熔斷策略,用於在保留內存時測量實際堆內存使用情況。

此新策略可提高節點對資源耗費高查詢導致集羣過載的彈性支持,並在默認情況下處於打開狀態,並可使用新的集羣設置:

indices.breaker.total.use_real_memory 進行控制。

內存熔斷策略推薦:

https://github.com/elastic/elasticsearch/pull/31767

5.2 dump堆內存分析

以上方案並未覆蓋全部業務場景。藉助dump文件有助於更好地理解根本原因。

在JVM OOM後Dump操作實戰參考:
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/heap-dump-path.html

Linux捕獲dump文件的方法

1ps -ef|egrep 'elasticsearch|logstash' | grep -v grep

5.3 Elasticsearch的保護設置

Elasticsearch具有另一個保護設置(最大桶search.max_buckets限制),以保護集羣出現OOM。

當超過桶的數量(在版本7.0中默認爲10,000)時(例如,當運行多層聚合時),
該最大桶聚合設置停止執行並且使搜索請求失敗。

5.4 斷路器設置

爲了進一步識別潛在的耗費資源的查詢,我們可以設置斷路器(indices.breaker.request.limit)。

設置方法:逐步縮放查詢範圍,從低閾值開始隔離查詢並逐漸向上移動閾值以縮小到特定的查詢。

斷路器設置參考:
https://www.elastic.co/guide/en/elasticsearch/reference/7.0/circuit-breaker.html#request-circuit-breaker

5.5 慢日誌分析

可以通過啓用Elasticsearch中的慢速日誌來識別運行緩慢的查詢。

Slowlogs專門用於分片級別,這意味着只應用數據節點

僅協調 Coordinating-only/客戶client節點不具備慢日誌分析功能,因爲它們不保存數據(索引/分片)。

Slowlogs有助於回答以下問題:

  • 1)查詢需要多長時間?

  • 2)查詢請求正文的內容是什麼?

Slowlogs輸出舉例:

1[2019-02-11T16:47:39,882][TRACE][index.search.slowlog.query] [2g1yKIZ] [logstash-20190211][4] took[10.4s], took_millis[10459], total_hits[16160], types[], stats[], 
2search_type[QUERY_THEN_FETCH], total_shards[10], source[{"size":0,"query":{"bool":{"must":[{"range":{"timestamp":{"from":1549266459837,"to":1549871259837,"include_lower":true,
3"include_upper":true,"format":"epoch_millis","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":[],"excludes":[]},"stored_fields":"*","docvalue_fields":
4[{"field":"timestamp","format":"date_time"},{"field":"utc_time","format":"date_time"}],"script_fields":{"hour_of_day":{"script":{"source":"doc['timestamp'].value.getHourOfDay()",
5"lang":"painless"},"ignore_failure":false}},"aggregations":{"maxAgg":{"max":{"field":"bytes"}},"minAgg":{"min":{"field":"bytes"}}}}], id[]],

Slowlog 日誌拆解:

日誌拆分項
描述

[2019-02-11T16:47:39,882]

檢索時間

[TRACE]

日誌級別

[index.search.slowlog.query]

屬於search的query階段慢日誌

[2g1yKIZ]

節點名稱

[logstash-20190211]

索引名稱

[4]

query執行的分片序號

took[10.4s]

在分片4所需的處理時間。注意:在查看慢速日誌時,我們希望避免從不同的分片中添加所有時間,因爲每個分片可能並行執行。

took_millis[10459]

耗費時間(毫秒)

total_hits[16160]

命中數

search_type[QUERY_THEN_FETCH]

search類型(query_then_fetch)

total_shards[10]

索引的總分片大小

source[]

執行檢索的請求body體

5.6 日誌審計(高階功能,低版本非付費會員建議跳過)

擁有金牌會員或鉑金會員訂閱的客戶(包括Elastic安全功能)可以打開審覈日誌以捕獲有關查詢的更多詳細信息。(用戶可以開始爲期30天的試用版來測試Elastic安全功能。)

注意:6.8和7.1之後,基礎安全功能已免費。之上的高版本可以使用該功能。低版本的非會員不建議使用。

審計日誌記錄有助於回答以下問題:

  • 1)查詢是什麼時候發生的?

  • 2)誰執行了查詢?

  • 3)查詢的內容是什麼?

我們需要調整審覈設置,因爲默認設置相當繁瑣:

  • 1)啓用安全審計日誌:

    在elasticsearch.yml中設置

    xpack.security.audit.enabled:true。

  • 2)在安全審計輸出中啓用日誌或索引:

    在elasticsearch.yml中設置

    xpack.security.audit.outputs:[logfile,index]。

出於故障排除的目的,我們建議選擇logfile而不是索引,因爲審計日誌記錄的詳細程度可能會對集羣性能造成不必要的壓力。

審計模式可能非常冗長,因此請在完成故障排除後將其關閉。

  • 3)在事件列表中包含authentication_success訪問權限
    在elasticsearch.yml中設置

    xpack.security.audit.logfile.events.include: authentication_success

6、小結

本文翻譯自Elastic官方博文,添加了自己的實踐解讀和星球內部討論總結內容。

在本文中,我們討論了慢查詢的常見原因以及解決方案。我們還討論了偶發慢查詢和非偶發慢查詢的解決方案。通常會將慢查詢視爲更廣泛集羣性能出問題的典型症狀。

640?wx_fmt=png

8月24日北京Meetup上medcl列舉了10個原因升級7.X,如果你還是6.X、5.X甚至更低版本,推薦升級。Elasticsearch7.X高級版本在搜索 qps 上提升很大,相同配置下慢查詢也還會有較大改善。

Elasticsearch性能優化非一朝一夕之功,“認準病根才能根除病痛”。


原文地址:

https://www.elastic.co/cn/blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries

官方優化:

https://www.elastic.co/guide/en/elasticsearch/reference/7.0/how-to.html

推薦閱讀:

Elasticsearch性能優化實戰指南

讓Elasticsearch飛起來!——性能優化實踐乾貨



640?wx_fmt=png

更短時間更快習得更多幹貨!

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