本文主要介紹了Elasticsearch的索引優化和索引的settings、mappings,而且舉例說明了在什麼場景下應該使用什麼參數來實現更細緻的優化。
上篇文章回顧: Mac OS下用Homebrew安裝本身寫的開源工具
Elasticsearch(下面簡稱ES)自己的搜索性能已經很是優秀,默認參數也適用於大部分場景;但爲了更高效地利用計算資源,或者防止出現一個請求消耗掉集羣全部的資源狀況,咱們會對一些參數進行調優和限制。node
有關於集羣級別的優化,網上已經有不少相關的文章能夠借鑑,而索引級別的優化則相對較少。ES的集羣優化一般是通用性的優化,而索引優化則更加貼近於業務,更有針對性。本文主要將介紹索引的settings、mappings,舉例說明什麼場景下使用什麼參數來實現更細緻的優化。算法
經常使用的參數,默認使用LZ4壓縮算法,優勢是壓縮速度很是快,對於寫入速度要求比較高,有充裕的存儲空間和讀寫速度的存儲介質的場景使用。
將該設置改成best_compression可以使用DEFLATE算法來得到更高的壓縮率,但會使用更多的CPU資源和時間來壓縮/解壓。一般都將該參數設爲best_compression,除非寫入時CPU成爲瓶頸。
該設置可在索引建立時或者處於Close狀態的索引上指定,新的壓縮算法將在下一次merge後生效。bash
另外一個經常使用的參數,增長索引分片數可提升搜索的併發度。當一個Query分發到不一樣分片上時,ES會將充分利用多核心CPU的優點,每一個分片使用不一樣的核心來處理搜索請求;一般來講,分配到一個節點上的主副分片之和等於CPU核心數將得到最大的CPU利用率和最短的搜索耗時。但分片數過多也會在合併搜索結果時帶來額外的計算量,同時若其餘的索引也在進行搜索的會形成上下文切換,所以搜索耗時不會隨着分片數增加而線性減小。併發
在知足搜索延遲的前提下,設置最小的分片數是最佳的選擇(暫時不考慮分片大小)。app
也一個經常使用的參數,用於調整寫入時的刷新間隔,刷新(refresh)既是將內存中的數據寫到文件系統緩衝中;寫入的數據在刷新後才能被搜索,這也是ES被稱爲近實時搜索的緣由。其本質是Segment的生成間隔。增大刷新間隔能夠減小Segment的生成,同時也能減小搜索耗時。一般將該值設爲"30s",對實時性要求較高的索引可適當減小刷新間隔。運維
由於Segment沒法作到實時生成,若是在兩次refresh間隔中節點宕掉,會致使數據丟失。Translog的存在則是爲了解決這個問題。Translog中記錄了每一次對ES的操做,默認是每一個請求(bulk, delete, upadte, etc)完成後,或者達到同步間隔(sync_interval,默認5s)都會將日誌持久化(fsync)到磁盤中,當主副分片都確認持久化完成後,客戶端纔會受到請求成功的響應;若節點出現異常,能夠重放translog中在最後一次刷新後發生的變動操做來恢復數據。
可是每次執行fsync會帶來少量的性能損失,若能夠接受幾秒鐘的數據損失,能夠將該參數設爲"async",使用異步fsync來減少translog帶來的影響。異步
當某個節點離線後,默認狀況下1m後就會執行重建副本。當咱們預知短期內離線的節點可以從新加入集羣,能夠延長重建副本的延時,來避免沒必要要的分片拷貝。
可以使用PUT /_all/_settings來對集羣中現有的全部索引應用該參數,該參數值視節點重啓的時間而定,一般可設爲"5m"。async
ES默認會使用max(1, min(4, CPU核心數 / 2))的線程數來進行merge操做,這會下降機械硬盤的讀寫效率,若是索引保存在機械硬盤上,可將該值固定爲"1"。工具
動態映射一方面下降了用戶的使用成本,另外一方面也對集羣管理形成了不便——因爲不規範的稀疏的數據致使索引中的字段數大幅增加而影響搜索性能。若是對一份數據規範性要求比較高,能夠經過將該參數設爲"false"來關閉自動生成字段映射的特性。性能
以咱們線上使用的經驗來看,ES5.x(6.x的狀況有待觀察)的分片分配機制不夠完善。當某個節點新加入集羣的時候,會優先把大索引的分片和當天正在寫入的索引的大部分分片分配到該節點上,致使該節點的負載飆高。經過設置該參數可限制索引在該節點上的最大分片數,必定程度上避免這種狀況的發生。
可是這個參數不能恰好設置爲( pri_shard_num + rep_shard_num) / data_node_num,若是剛好設置成這個值,可能會出現最後一個分配的副本和主分片在同一節點上,致使分配不上去。
若您大部分的搜索請求是基於必定順序取TopN,例如看最近的10條日誌,耗時最長的100個請求,或者交易最頻繁的5個用戶等等,ES默認狀況下會掃描所有數據後在返回結果。在ES6.x中加入了一個特性,可以大幅下降這類搜索的耗時:Index Sorting。若啓用該特性,ES在寫入時候就會按照必定順序排列數據,例如按時間倒敘,這樣在搜索的時候就不要掃描全量數據,只要得到每一個Segment前TopN的數據便可返回結果。該特性須要在索引建立的時候啓用,方法以下:
PUT log
{ "settings" : {
"index" : {
"sort.field" : "timestamp",
"sort.order" : "desc"
}
},
...
}複製代碼
注意,啓用該特性會下降寫入速度,所以須要在寫入和搜索之間進行權衡。
ES之因此具備不須要事先定義schema是由於dynamic mapping功能的存在,它大大下降了用戶使用成本。
默認ES對字符串類型的字段會自動映射成text類型,同時再生成一個名爲字段名.keyword的keyword類型的子字段。若大部分字段不須要對字段進行分詞,可將默認的字符串類型映射爲keyword來下降寫入時的額外資源開銷:
"mappings": {
"doc": {
"dynamic_templates": [
{ "strings_as_keywords": {
"match_mapping_type": "string",
"mapping": { "type": "keyword" }
}
}
]
}
}複製代碼
效果同索引級別的"mapper.dynamic",可針對某個字段或者整個Type設置,經過將該參數設爲"false"來關閉自動生成字段的特性,新添加的字段將被忽略;或者設爲"strict",若是遇到新字段拋出異常。
對於keyword類型的字段,若是咱們只須要對該字段進行搜索,不須要進行聚合、排序或是使用腳本操做,能夠將doc_value設爲false,可大幅降節省磁盤空間,必定程度上提高索引速度。
若是咱們只須要對某個字段進行聚合、排序或是使用腳本操做,不須要搜索該字段(一般是keyword或者numeric類型的字段),能夠將index設爲false,可釋放該字段倒排索引佔用的常駐內存。
索引的倒排索引佔用的內存可經過GET /<INDEX_NAME>/_stats?human=true中的segments.terms_memory查看。
norms參數對搜索評分頗有用,若咱們不須要計算字段的評分,將該參數設爲false,特別是該字段僅用於過濾或聚合。若索引中存在某個字段啓用了norms,不管文檔中是否存在該字段,全部文檔都會佔用N bytes(N爲文檔數)磁盤空間,所以禁用norms能夠釋放大量的磁盤空間。
norms能夠經過如下API禁用,將在生成新的Segment時生效,但不能被從新啓用。
PUT my_index/_mapping/_doc
{ "properties": {
"title": {
"type": "text",
"norms": false
}
}
}複製代碼
在一些狀況下,咱們只須要保存某個字段,經過搜索其餘的字段來定位到這條記錄查看這個字段的內容,不須要對該字段進行搜索、排序、聚合等操做,能夠將該字段的"enabled"設爲false,同時節省大量內存和磁盤的空間。
咱們常常碰到一些內容不規範或者格式不對的數據,例如某個IP字段的裏出現"UNKNOWN",某個數字字段出現"-"。若是在這些字段上已經設置了明確的類型,好比"ip"或者"float",字段中出現了非該類型的值,ES會拋出異常並丟棄整條數據。
咱們能夠在該字段上設置"ignore_malformed": ture來忽略這個字段並保留該文檔中的其餘字段。
該字段屬於索引的元數據,其中存儲了文檔原始的JSON內容,會被存儲但不會被索引,用於執行fetch請求時返回原始數據。
當咱們不須要得到任何原始數據,只須要對數據進行排序,聚合等計算,或者寫入時文檔id是手動指定的,經過搜索取到文檔id來進一步處理,能夠將"_source"設爲false來節約大量的磁盤空間。
注意,禁用"_source"後會致使沒法使用update,update_by_query,reindex等須要獲取原始文檔的API,也沒法使用高亮功能。
一些比較經常使用的針對索引級別的設置就介紹到這裏,某些在ES6.x以上的版本已被棄用的參數將再也不贅述。經過靈活地配置參數可將ES的性能發揮到更高的水平。
本文首發於公衆號「小米運維」,點擊查看原文