Elasticsearch搜尋調優權威指南 (1/3)
本文首發於 vivo網際網路技術 微信公眾號 https://mp.weixin.qq.com/s/qwkZKLb_ghmlwrqMkqlb7Q
英文原文: https://qbox.io/blog/elasticsearch-search-tuning-5-0-ultimate-guide
作者:Adam Vanderbush
譯者:楊振濤
目錄
- 文件建模
- 全域性序列號和延遲
- 多代關係
- 為檔案系統快取分配記憶體
Elasticsearch搜尋調優權威指南,是QBOX在其部落格上釋出的系列文章之一,本文是該系列的第一篇,主要從文件建模、記憶體分配、檔案系統快取、GC和硬體等方面介紹了最佳化查詢效能的一些經驗。
Elasticsearch 5.0.0確實是在2.x之後的一個大版本,為大家帶來了許多新東西。Elasticsearch現在作為Elastic Stack中的一員,與整個技術棧的其他產品的版本號已經對齊,現在Kibana、Logstash、Beats和Elasticsearch全都是5.0版本了。
這個版本的Elasticsearch是目前為止最快、最安全、最彈性,也是最易用的,而且還帶來了很多的改進和新特性。
我們已經透過“Elasticsearch效能調優權威指南”系列,介紹了一些效能調優的基本經驗和方法,解釋了每一步最關鍵的系統設定和衡量指標。該系列共分下列3個部分:
- The Authoritative Guide to Elasticsearch Performance Tuning (Part 1)
- The Authoritative Guide to Elasticsearch Performance Tuning (Part 2)
- The Authoritative Guide to Elasticsearch Performance Tuning (Part 3)
索引決策也很重要,它對如何搜尋資料有很大的影響。如果是一個字串欄位,是否需要分詞或歸一化?如果是,怎麼做?如果是一個數值型屬性,需要哪種精度?還有很多其他型別,比如date-time、geospatial shape以及父子關係等,需要更多特別的考慮。
我們也透過一個系列教程討論了“Elasticsearch索引效能最佳化”,介紹了一些通用的技巧和方法,來最大化索引的吞吐量並降低監控和管理的負載。該教程分如下3個部分:
- How to Maximize Elasticsearch Indexing Performance (Part 1)
- How to Maximize Elasticsearch Indexing Performance (Part 2)
- How to Maximize Elasticsearch Indexing Performance (Part 3)
本文旨在推薦一些搜尋調優技術、策略以及Elasticsearch 5.0及以上的推薦特性。
1.文件建模
內部物件屬性陣列並不像期望的那樣工作。 Lucene 中沒有內部物件的概念,所以Elasticsearch把物件層次展開到一個由屬性名稱和屬性值組成的簡單列表中。以下列文件為例:
curl -XPUT 'localhost:9200/my_index/my_type/1?pretty' -H 'Content-Type: application/json' -d '{ "group" : "fans", "user" : [ { "first" : "John", "last" : "Smith" }, { "first" : "Alice", "last" : "White" } ] }'
該請求會在內部轉換為如下的文件形式:
{ "group" : "fans", "user.first" : [ "alice", "john" ], "user.last" : [ "smith", "white" ] }
如果需要索引物件陣列,並維護陣列中每個物件的依賴關係,應當使用內嵌資料型別而不是物件資料型別。內嵌物件在內部會把陣列中的每個物件當作單獨的隱藏文件來索引,即使用下述內嵌查詢,可以單獨查詢每個內嵌物件:
curl -XPUT 'ES_HOST:ES_PORT/my_index?pretty' -H 'Content-Type: application/json' -d '{ "mappings": { "my_type": { "properties": { "user": { "type": "nested" } } } } }' curl -XPUT 'ES_HOST:ES_PORT/my_index/my_type/1?pretty' -H 'Content-Type: application/json' -d '{ "group" : "fans", "user" : [ { "first" : "John", "last" : "Smith" }, { "first" : "Alice", "last" : "White" } ] }' curl -XGET 'ES_HOST:ES_PORT/my_index/_search?pretty' -H 'Content-Type: application/json' -d '{ "query": { "nested": { "path": "user", "query": { "bool": { "must": [ { "match": { "user.first": "Alice" }}, { "match": { "user.last": "Smith" }} ] } } } } }' curl -XGET 'ES_HOST:ES_PORT/my_index/_search?pretty' -H 'Content-Type: application/json' -d '{ "query": { "nested": { "path": "user", "query": { "bool": { "must": [ { "match": { "user.first": "Alice" }}, { "match": { "user.last": "White" }} ] } }, "inner_hits": { "highlight": { "fields": { "user.first": {} } } } } } }'
當有一個主實體比如一篇部落格文章,帶有一些有一定關係但又不是非常重要的其他實體比如評論時,內嵌物件會非常有用。如果能根據評論內容來查詢到部落格文章,那就很不錯,而且內嵌查詢和過濾器一起提供了更快的join查詢能力。
內嵌物件模型的缺點如下:
為了 增加 、修改 或 刪除 一個內嵌物件文件,整個文件必須重建索引;這就導致內嵌文件越多開銷就越大。
搜尋請求返回整個文件,而不是隻返回匹配的內嵌文件。雖然已經以後計劃支援返回根文件的部分最配內嵌文件,但目前仍然不支援。
有時候可能需要把主文件和其關聯實體分離,這種分離由父子關係來提供。
透過建立另一個文件的父型別mapping,可以在相同索引的文件之間建立父子關係:
curl -XPUT 'ES_HOST:ES_PORT/my_index?pretty' -H 'Content-Type: application/json' -d '{ "mappings": { "my_parent": {}, "my_child": { "_parent": { "type": "my_parent" } } } }' curl -XPUT 'ES_HOST:ES_PORT/my_index/my_parent/1?pretty' -H 'Content-Type: application/json' -d '{ "text": "This is a parent document" }' curl -XPUT 'ES_HOST:ES_PORT/my_index/my_child/2?parent=1&pretty' -H 'Content-Type: application/json' -d '{ "text": "This is a child document" }' curl -XPUT 'ES_HOST:ES_PORT/my_index/my_child/3?parent=1&refresh=true&pretty' -H 'Content-Type: application/json' -d '{ "text": "This is another child document" }' curl -XGET 'ES_HOST:ES_PORT/my_index/my_parent/_search?pretty' -H 'Content-Type: application/json' -d '{ "query": { "has_child": { "type": "my_child", "query": { "match": { "text": "child document" } } } } }'
父子join對管理實體關係非常有用,尤其是在索引時間比檢索時間很重要的情形下,但是它會帶來較大的開銷;父子查詢比同等的內嵌查詢要慢5到10倍。
2.全域性序列號和延遲
父子關係使用了全域性序列號來加速join操作。無論父子map是否使用了記憶體快取或磁碟上的doc value,全域性序列號仍然需要在索引發生任何改變時進行重建。
分片中的父代越多,全域性序列號構建就越耗時。相對於需要父代和較少的子代, 父子關係最適合每個父代有很多子代的情形。
全域性序列號預設是 延遲 構建:refresh後的第一個父子查詢或聚合請求將會觸發構建全域性序列號。這會讓使用者感知到一個明顯的潛在峰值。可以使用eager_global_ordinals 來把查詢期構建全域性序列號的成本轉移到refresh期,透過如下方式mapping _parent屬性:
curl -XPUT 'ES_HOST:ES_PORT/company -d ‘{ "mappings": { "branch": {}, "employee": { "_parent": { "type": "branch", "fielddata": { "loading": "eager_global_ordinals" } } } } }’
這裡,_parent屬性的全域性序列號將會在一個新的段搜尋可見時被構建。
對於很多的父代,全域性序列號要花費數秒鐘來構建。此時,需要增加refresh_interval,以便refresh的頻率更低,而全域性序列號保持可用的時間更長。這將大幅減少每秒鐘重建全域性序列號的CPU消耗。
3.多代關係
對多代資料的Join(參考Grandparents and Grandchildren)能力聽起來很吸引人,但需要思考其代價:
- Join越多,效能越差。
- 每一個父代都需要把自己的string _id屬性儲存在記憶體,這可能會消耗大量RAM。
- 當考慮關係型方案及父子關係是否適合時,可參考下列關於父子關係的建議:
- 保守使用父子關係,僅當子代比父代多很多時才考慮。
- 避免在單個查詢中使用多父子關係來join。
- 避免對使用has_child過濾器,或score_mode為 none 的has_child查詢來打分。
- 父ID儘量簡短,以便在doc value中更好地壓縮,從而在瞬時載入時消耗更少的記憶體。
4.為檔案系統快取分配記憶體
對於執行中Elasticsearch,記憶體是需要密切監控的重要資源之一。Elasticsearch和Lucene透過JVM堆記憶體和檔案系統快取兩種方式來消耗記憶體。由於Elasticsearch執行在Java虛擬機器(JVM)中,所以JVM的GC週期和頻率也需要重點監控。
JVM堆記憶體
對於Elasticsearch一個“剛好合適”的JVM堆大小是非常重要的——不能設定過大或過小,原因見後文。一般來說Elasticsearch的經驗值是分配少於50%的可用RAM給JVM堆,且不要超過32GB。
為Elasticsearch分配過少的堆記憶體,那麼就會留給Lucene更多記憶體,而Lucene重度依賴於檔案系統快取來快速處理請求。不管怎樣也不能設定過小的堆記憶體,因為當應用由於頻繁GC而面臨短時中斷時,可能會遭遇記憶體溢位錯誤或吞吐量下降。
Elasticsearch預設安裝時設定的JVM堆大小為1GB,這在大多數情況下都偏小。可以透過環境變數來設定期望的對大小並重啟Elasticsearch:
export ES_HEAP_SIZE=10g
設定JVM堆大小的另一種方式(相當於設定一樣的最小值和最大值,以防止重新調整堆大小),是在每次啟動Elasticsearch時透過命令列引數指定:
ES_HEAP_SIZE="10g" ./bin/elasticsearch
這兩種示例方式都是設定了10GB的堆大小,為了驗證是否設定成功,執行:
curl -XGET
返回的輸出會顯示已正確地更新了最大堆記憶體。
垃圾回收
Elasticsearch依靠GC過程來釋放堆記憶體。由於GC本身也要消耗資源(為了釋放資源!),所以應當留意GC頻率和持續時間,以確認是否需要調整堆記憶體大小。設定過大的堆記憶體,換來的是更長的GC時間;這種過多的停頓非常危險,因為可能導致叢集誤認為該節點網路異常而失聯。
因此,Elasticsearch重度依賴檔案系統快取來加速搜尋。一般需要保證至少有一半的可用記憶體用於檔案系統快取,這樣Elasticsearch才能保持索引資料的熱點區域都在實體記憶體中。
使用更快的硬體
如果搜尋受限於I/O,應當考慮為檔案系統快取分片更多記憶體(參考前文),或者購買更快的驅動。特別地,SSD公認地比機械磁碟效能好很多。儘可能使用本地儲存,避免使用像 NFS 或 SMB 之類的遠端或網路檔案系統,也要注意像Amazon EBS這樣的虛擬化儲存。
Elasticsearch使用虛擬化儲存工作是沒有問題的,它因為快速和安裝簡單而受歡迎,但同樣不幸的是,在基礎上與專用的本地儲存相比它天生就比較慢。如果在EBS上建立了一個索引庫,請確認使用預分配的IOPS,否則很快就會被限流。
如果搜尋受限於CPU,那麼應當考慮購買更快的CPU。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69912579/viewspace-2648162/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Elasticsearch搜尋調優權威指南 (2/3)Elasticsearch
- Elasticsearch 權威指南(中文版)Elasticsearch
- (1)分散式搜尋ElasticSearch認識ElasticSearch分散式Elasticsearch
- 搜尋引擎ElasticSearch18_ElasticSearch簡介1Elasticsearch
- [Elasticsearch] 多欄位搜尋 (二) - 最佳欄位查詢及其調優(轉)Elasticsearch
- Elasticsearch常用搜尋Elasticsearch
- Elasticsearch——全文搜尋Elasticsearch
- elasticsearch搜尋商品Elasticsearch
- Elasticsearch 向量搜尋Elasticsearch
- HTML5與CSS3權威指南筆記案例1HTMLCSSS3筆記
- ElasticSearch全文搜尋引擎Elasticsearch
- elasticsearch之拼音搜尋Elasticsearch
- Elasticsearch 為了搜尋Elasticsearch
- Elasticsearch(ES)的高階搜尋(DSL搜尋)(上篇)Elasticsearch
- Elasticsearch(ES)的高階搜尋(DSL搜尋)(下篇)Elasticsearch
- elasticsearch(五)---分散式搜尋Elasticsearch分散式
- 認識搜尋引擎 ElasticsearchElasticsearch
- JavaScript 日期權威指南JavaScript
- Nebula 基於 ElasticSearch 的全文搜尋引擎的文字搜尋Elasticsearch
- Elasticsearch 實現簡單搜尋Elasticsearch
- Laravel 使用 Elasticsearch 全域性搜尋LaravelElasticsearch
- Laravel + Elasticsearch 實現中文搜尋LaravelElasticsearch
- 【elasticsearch】搜尋過程詳解Elasticsearch
- Elasticsearch搜尋資料彙總Elasticsearch
- ElasticSearch效能調優Elasticsearch
- [譯] JAVASCRIPT 日期權威指南JavaScript
- Java 13權威指南 - CodeFXJava
- JavaScript權威指南(6)——物件JavaScript物件
- ElasticSearch 簡單的 搜尋 聚合 分析Elasticsearch
- elasticsearch實現基於拼音搜尋Elasticsearch
- Elasticsearch核心技術(五):搜尋API和搜尋執行機制ElasticsearchAPI
- 開放搜尋開源相容版,支援Elasticsearch做搜尋召回引擎Elasticsearch
- 深度優先搜尋
- Elasticsearch調優實踐Elasticsearch
- HTTP 1.x 學習筆記 —— Web 效能權威指南HTTP筆記Web
- 搜尋引擎ElasticSearch18_ElasticSearch程式設計操作5Elasticsearch程式設計
- javascript權威指南——函式篇JavaScript函式
- HBase權威指南【中文版】