Elasticsearch 調優 (官方文檔How To)


How To

Elasticsearch默認是提供了一個非常簡單的即開即用體驗。用戶無需修改什么配置就可以直接使用全文檢索、結果高亮、聚合、索引功能。

但是想在項目中使用高性能的Elasticsearch,有幾方面優化方法最好掌握。

本文就是為了引導如何優化。

常規建議

不要一次返回太大量的搜索結果集

Elasticsearch設計作為一個搜索引擎,非常擅長返回匹配的查詢結果。但是,它並不合適像數據庫一樣,把整個document作為查詢結果返回。如果非要這樣做,最好還是使用Scroll這個接口來。

避免索引稀疏

Elasticsearch是基於Lucene進行索引和存儲數據的,最佳的工作方式是密集的數據,即是所有的document擁有相同的字段。特別是啟用了norms(通常是text字段是默認開啟)或者啟用了doc_values(通常是numerics, date, ip 或 keyword 是默認開啟)的字段。

原因是Lucene內部是通過由0到索引 document 總數的 doc_id 來識別 document 。doc_id 用於Lucene api內部之間的通訊:例如使用關鍵詞 match 查詢得到的doc_id,然后這些doc_id用於檢索 norms 的值去計算 score(匹配得分)。這個 norms 查找方式實現目前是通過為每個 document 保留一個字節。doc_id 可以直接讀取該 document 的 norms 值。這種方式好處是可以幫助Lucene快速訪問每個 document ,缺點是每個 document 還需要額外占多一個字節的存儲。

實際上,這就意味着如果一個index里面有M個document,每個字段的norms就需要M個字節的存儲,就算某些字段只是包含在小部份 document 。雖然復雜的類型字段存儲使用doc_values,但是一樣還會占用存儲的。眾所周知,fielddata 類型在 pre-2.0之后被替換成 doc_values ,除非 fielddata已經寫在硬盤上了,在內存里面的話,也是有這個問題。

需要注意的是,稀疏存儲會對索引和搜索速度有明顯的影響,額外的存儲字節雖然不是字段,也是需要花費時間去索引和搜索的。

當然,index是允許存在少數稀疏情況的,但是如果稀疏數量教大,則會影響整個index的效率。

本章節主要集中在 norms 和 doc_values 這兩個影響較大的特性。稀疏情況會影響倒排索引(用於索引 text/keyword 字段)和坐標點類型字段(用於索引 geo_point 和 numeric),影響的程度不一樣。

下面有幾點推薦能避免稀疏:

避免把無關聯的數據放在同一個index

不要把完全不同的數據結構 document 放在同一個 index 里面。最好是將這些 document 放到不同的index里面,可以考慮創建一些較小的index, 用較少的shard去存儲。

注意,這個建議不適用於有使用 parent/child 這種帶關系的 document 放在同一個 index 的情況。

標准化 document 結構

如果必需把不同類型的 document 放在同一個 index里面,也是有機會減少稀疏情況的。例如,在 index 內所有的 document 都添加一個時間戳字段,通常叫"timestamp"或者"creation_date",它將會有助於把所有的 document 重命成相同的字段。

避免不同的 type 放在同一個index

多個 type 放在單個 index 看起來是個簡單的方法。但是Elasticsearch並不是基於 type來存儲的,不同的 type 在單個 index 也會影響效率。如果 type 沒有非常相似的 mapping,建議考慮放到一個單獨的 index 上面。

對於不同的字段禁用 norms 和 doc_values

如果以上建議適用,還需要檢查字段是否啟用了 norms 和 doc_values。通常只用於過濾而不需要進行打分(匹配度打分)的字段,可以直接禁用 norms 。不用於排序或者聚合的字段可以禁用 doc_values 。注意,如果在已有的 index 做這些變更,是需要對 index 做 reindex的動作。

調優索引速度

使用 bulk 請求

Bulk 批量請求比單次 document 索引請求性能更好。為了驗證最優批量請求的大小,可以做一個基准測試,用一個單節點跑一個單 shard 。先嘗試索引100個document,然后 200, 然后400,等等。每次運行基准測試就相應加倍 document 的數量。取得索引速度最高的數值,就是最佳的bulk批量請求數。當然,批量請求也不是越多 document 越好。如果並發同時請求,太大的 bulk 請求會使集群內存壓力變大,所以建議避免每次請次超過幾十M,這樣會獲得較好的性能。

使用多進程/多線程去發送數據到Elasticsearch

一個單線程發送 bulk 請求似乎不能夠發揮一個集群的索引能力。為了更好地利用集群的資源,應該使用多線程或多進程來發送數據,同時這將有助於減少每次 fsync 的成本。

一定要留意系統是否返回 TOO_MANY_REQUESTS (429) 代碼。(通常Java client返回是EsRejectedExecutionException),這是表示Elasticsearch無法跟上當前的索引速度。發生這種情況時可以暫停一下索引一會再試。嘗試更換 bulk 一個隨機值或理想值。

對於相同大小的 bulk 請求,通過測試可以得到最優的線程數量。可以逐步增加線程數量直至到集群中的機器IO或CPU飽和。

增加 refresh_interval 刷新的間隔時間

index.refresh_interval的默認值是 1s,這迫使Elasticsearch集群每秒創建一個新的 segment (可以理解為Lucene 的索引文件)。增加這個值,例如30s,可以允許更大的segment寫入,減后以后的segment合並壓力。

在初始化索引時,可以禁用 refresh 和 replicas 數量

如果需要一次加載較大的數據量進 index 里面時,可以先禁用 refresh ,把 index.refresh_interval 設置成為 -1 ,把 index.number_of_replicas 設置成 0。暫時把多個shard副本關閉(即如果當前index發生損壞便用丟失數據),但是這樣做可以大大加快索引速度。當初始化索引完成,可以將 index.refresh_interval 和 index.number_of_replicas 設置回原來的值。

禁用 swapping

把操作系統的虛擬內存交換區關閉。sysctl 里面添加 vm.swappiness = 1

確保有空閑的內存給文件系統緩存

文件系統緩存是為了緩沖磁盤的IO操作。至少確保有一半機器的內存保留給操作系統,而不是JAVA VM占用了全部內存。

使用更快的硬件

當然這個不用說了上SSD是最好的了。如果有多個SSD硬盤,可以配置成 RAID 0陣列取得更佳的IO性能。但是任何一個SSD損壞都有可能弄壞 index。通常正確的權衡是優化單的shard存儲性能,然后添加 replicas 放在不同的節點。同時使用 snapshot 快照和 restore 功能去備份 index。

索引 buffer 大小

如果節點在做非常大的索引動作,需要確保 indices.memory.index_buffer_size足夠大,最多可以設置為512M的buffer。除此之外增加這個值,性能通常不會得到改善。

Elasticsearch的活躍shard需要使用java的heap內存的百份比或者絕對值去作為一個共享緩沖區。非常活躍的shard自然會使用較頻繁。

這個默認值是通常是10%,例如,如果JVM設置為10GB內存為heap,那么就會有1GB的索引緩沖區提供給大量的索引shard。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM