Elasticsearch系列---性能調優最佳實踐

概要

性能調優是系統架構裏所有組件必不可少的話題,Elasticsearch也不例外,雖說Elasticsearch內的默認配置已經非常優秀,但這不表示它就是完美的,必要的一些實踐我們還是需要了解一下。

開啓慢查詢日誌

慢查詢日誌是性能診斷的重要利器,常規操作是設置慢查詢的閥值,然後運維童鞋每天對慢日誌進行例行巡查,有特別慢的查詢,立即報備事件處理,其餘的定期將慢日誌的top n取出來進行優化。

慢日誌的配置在elasticsearch 6.3.1版本下是通過命令配置的,讀操作和寫操作可以單獨設置,閥值的定義可根據實際的需求和性能指標,有人覺得5秒慢,有人覺得3秒就不可接受,我們以3秒爲例:

PUT /_all/_settings
{
"index.search.slowlog.threshold.query.warn":"3s",
"index.search.slowlog.threshold.query.info":"2s",
"index.search.slowlog.threshold.query.debug":"1s",
"index.search.slowlog.threshold.query.trace":"500ms",

"index.search.slowlog.threshold.fetch.warn":"1s",
"index.search.slowlog.threshold.fetch.info":"800ms",
"index.search.slowlog.threshold.fetch.debug":"500ms",
"index.search.slowlog.threshold.fetch.trace":"200ms",

"index.indexing.slowlog.threshold.index.warn":"3s",
"index.indexing.slowlog.threshold.index.info":"2s",
"index.indexing.slowlog.threshold.index.debug":"1s",
"index.indexing.slowlog.threshold.index.trace":"500ms",
"index.indexing.slowlog.level":"info",
"index.indexing.slowlog.source":"1000"
}

這三段分別表示query查詢、fetch查詢和index寫入三類操作的慢日誌輸出閥值,_all表示對所有索引生效,也可以針對具體的索引。

同時在log4j2.properties配置文件中增加如下配置:

# 查詢操作慢日誌輸出
appender.index_search_slowlog_rolling.type = RollingFile
appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling
appender.index_search_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog.log
appender.index_search_slowlog_rolling.layout.type = PatternLayout
appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n
appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog-%d{yyyy-MM-dd}.log
appender.index_search_slowlog_rolling.policies.type = Policies
appender.index_search_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.index_search_slowlog_rolling.policies.time.interval = 1
appender.index_search_slowlog_rolling.policies.time.modulate = true

logger.index_search_slowlog_rolling.name = index.search.slowlog
logger.index_search_slowlog_rolling.level = trace
logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling.ref = index_search_slowlog_rolling
logger.index_search_slowlog_rolling.additivity = false

# 索引操作慢日誌輸出
appender.index_indexing_slowlog_rolling.type = RollingFile
appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling
appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog.log
appender.index_indexing_slowlog_rolling.layout.type = PatternLayout
appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n
appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog-%d{yyyy-MM-dd}.log
appender.index_indexing_slowlog_rolling.policies.type = Policies
appender.index_indexing_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.index_indexing_slowlog_rolling.policies.time.interval = 1
appender.index_indexing_slowlog_rolling.policies.time.modulate = true

logger.index_indexing_slowlog.name = index.indexing.slowlog.index
logger.index_indexing_slowlog.level = trace
logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling
logger.index_indexing_slowlog.additivity = false

重啓elasticsearch實例後,就能在/home/esuser/esdata/log目錄中看到生成的兩個日誌文件了。

優化實踐建議

基本使用規範

  1. 搜索結果不要返回過大的結果集

過大的結果集會佔用大量的IO資源和帶寬,速度肯定快不了,Elasticsearch是一個搜索引擎,最理想的搜索是精準查詢或次精準查詢,最關心的是排在前面的少數結果,而不是所有結果,優化搜索條件,控制搜索結果數量是高性能的前提。

如果真有大批量的數據查詢,建議使用scroll api。

  1. 避免超大的document

http.max_context_length的默認值是100mb,如果你一次document寫入時,document的內容不能超過100mb,否則es就會拒絕寫入。雖然你可以修改此配置,但不建議這麼做,es底層的lucene引擎還是有一個2gb的最大限制。

過大的document會佔用非常多的資源,從任何方面考慮都不建議,如果業務需求真有非常大的內容,如對書的內容搜索,建議按章節、按段落進行拆分存儲。

  1. 避免稀疏的數據

document的設計會從根本上影響索引的性能,稀疏數據是一個典型的不良設計,浪費存儲空間,影響讀寫性能。

下面有一些document結構設計的建議:

  • 避免將沒有任何關聯性的數據寫入同一個索引

沒有關聯性的數據,意味着數據結構也不相同,硬生生放在同一個索引,會導致index數據非常稀疏,建議是將這些數據放在不同的索引中。

  • 對document的結構進行統一規範化

document的結構、命名儘可能統一規範處理,同樣是創建時間字段,避免有的叫timestamp,有的叫create_time,儘可能統一。

  • 對某些field禁用norms和doc_values

如果一個field不需要考慮其相關度分數,那麼可以禁用norms,如果不需要對一個field進行排序或者聚合,那麼可以禁用doc_values字段。

服務器層級

硬件資源是性能最硬核的部分,硬件好,起點就高。

  1. 用更快的硬件資源

在預算範圍內,能用SSD固態硬盤就不要選用機械硬盤;

CPU主頻、核數當然是強大到預算上限;

內存單機上限64GB,加機器加到沒錢爲止;

儘量使用本地存儲系統,不要用NFS等網絡存儲,畢竟硬盤便宜。

  1. 給filesystem cache更多的內存

Elasticsearch的搜索嚴重依賴於底層的filesystem cache,如果所有的數據都能夠存放在filesystem cache中,那麼搜索基本上是秒級。

由於實際情況的限制,最佳的情況下,就是你的機器的內存,至少可以容納你的總數據量的一半。

要達到最佳情況有兩個辦法:一個是砸錢,買更多機器,加更大內存;另一種是精簡document數據,只把需要搜索的field放進es內,filesystem cache就能存下更多的document,可以提高內存的利用率。剩餘的其他字段,可以放在redis/mysql/hbase/hapdoop做二級加載。

  1. 禁止swapping交換內存

將swapping禁止掉,如果es jvm內存交換到磁盤,再交換回內存,會造成大量磁盤IO,性能很差。

Elasticsearch層級

  1. index buffer

在高併發寫入場景,我們可以將index buffer調大一些,indices.memory.index_buffer_size,這個可以調節大一些,這個值默認是jvm heap的10%,這個index buffer大小,是所有的shard公用的,這個值除以shard數量,算出來平均每個shard可以使用的內存大小,一般建議對於每個shard最多給512mb。

  1. 禁止_all field

_all field會將document中所有field的值都合併在一起進行索引,很佔用磁盤空空間,實際上用處卻不大,生產環境最好禁用_all field。

  1. 使用best_compression

_source field和其他field很佔用磁盤空間,建議對其使用best_compression進行壓縮。

  1. 用最小的最合適的數字類型

es支持4種數字類型:byte,short,integer,long。如果最小的類型就合適,那麼就用最小的類型,節省磁盤空間。

  1. 禁用不需要的功能

對於需要進行聚合和排序的field,我們才建立正排索引;
對於需要進行檢索的field,我們才建立倒排索引;
對於不關心doc分數的field,我們可以禁用掉norm;
對於不需要執行phrase query近似匹配的field,那麼可以禁用位置這個屬性;

  1. 不要用默認的動態string類型映射

默認的動態string類型映射會將string類型的field同時映射爲text類型以及keyword類型,大多數情況我們只需要使用其中一種,剩下的都是浪費磁盤空間,例如,id field這種字段可能只需要keyword,而body field可能只需要text field。

所以是使用keyword和text在設計時就應該區分清楚,而不是全盤保存。

  1. 預熱filesystem cache

如果我們重啓了Elasticsearch,那麼filesystem cache是空的,每次數據查詢時再加載數據進filesystem cache,我們可以先對一些數據進行查詢,提前將一些常用數據加載到內存,待真實客戶使用時,可以直接使用內存數據,響應就很快了。

代碼研發層級

  1. 多使用bulk做寫入

我們使用Java作爲客戶端時,寫入操作全部利用bulk api來完成。

  1. 使用多線程將數據寫入

  2. document使用自動生成的id

手動給document設置一個id,那麼es需要每次都去確認一下那個id是否存在,這個過程是比較耗費時間的。如果我們使用自動生成的id,那麼es就可以跳過這個步驟,寫入性能會更好。

對於關係型數據庫中的表id,可以作爲es document的一個field存入。

  1. 重視document結構設計

業務研發的重中之重,好的document結構會帶來非常優秀的性能表現。

  1. 避免使用script腳本

  2. 充分利用緩存

時間查詢時,不要使用now這種函數,應該在客戶端把時間轉換成規範的格式,再到Elasticsearch裏查詢,這樣能提高緩存的使用率。

小結

本篇介紹了Elasticsearch性能調優的常見實踐方法,從服務器、實例再到代碼層級,可以作爲參考,但性能調優沒有約定俗成的方法,需要反覆的驗證,僅供參考,謝謝

專注Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區
可以掃左邊二維碼添加好友,邀請你加入Java架構社區微信羣共同探討技術
Java架構社區

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