前言
- elasticsearch提供了非常靈活的搜索條件給我們使用,在使用復雜表達式的同時,如果使用不當,可能也會為我們帶來了潛在的風險,因為影響查詢性能的因素很多很多,這篇筆記主要記錄一下慢查詢可能的原因,及其優化的方向。
- 本文討論的es版本為7.0+。
慢查詢現象
查詢服務超時
- 最直觀的現象就是提供查詢的服務響應超時。
大量連接被拒絕
- 我們有時候寫查詢,為了圖方遍,經常使用通配符*來查詢,這有可能會匹配到多個索引,由於索引下分片太多,超過了集群中的核心數。就會在搜索線程池中造成排隊任務,從而導致搜索拒絕。
查詢延遲
主機CPU飆高
- 另一個常見原因是磁盤 I/O 速度慢,導致搜索排隊或在某些情況下 CPU 完全飽和。
- 除了文件系統緩存,Elasticsearch 還使用查詢緩存和請求緩存來提高搜索速度。 所有這些緩存都可以使用搜索請求進行優化,以便每次都將某些搜索請求路由到同一組分片,而不是在不同的可用副本之間進行交替。這將更好地利用請求緩存、節點查詢緩存和文件系統緩存。Es默認會在內存使用75%時發生FullGC ,做好主機和節點的監控同樣重要。
優化方法
根據查詢時間段動態計算索引
- elasticsearch支持同時查詢多個索引,為了提高查詢效率,避免使用通配符查詢,我們可以計算枚舉出所有的目標索引,一般es的數據都是按時間分索引,我們可以根據前端傳入的時間段,計算出目標索引。
控制分片數量
- 分片的數量和節點和內存有一定的關系。
- 最理想的分片數量應該依賴於節點的數量。 數量是節點數量的1.5到3倍。
- 每個節點上可以存儲的分片數量,和堆內存成正比。官方推薦:1GB 的內存,分片配置最好不要超過20。
注意from/to查詢帶來的深度分頁問題
- 舉例假如每頁為 10 條數據,你現在要查詢第 200 頁,實際上是會把每個 Shard 上存儲的前 2000條數據都查到一個協調節點上。
如果你有 5 個 分片,那么就有 10000 條數據,接着協調節點對這 10000 條數據進行一些合並、處理,再獲取到最終第 200 頁的 10 條數據。實在需要查詢很多數據,可以使用scroll API 滾動查詢。
為你的索引配置索引模板
- 在低版本的es中默認的分片是5個,在高版本中改成了1,我們需要根據索引的索引量來動態調整分片數量,這里推薦設置一個默認匹配規則,將優先級設置高一些(ps:order高的會覆蓋order低的模板),避免查詢掃描過多的分片,合理利用集群資源。
避免數據分桶太多
對於分桶數量太大的聚合請求,應該將所有數據切片,比如按時間分片,多次請求,來提高查詢效率,並且避免內存OOM。
獨立協調節點
- 集群中應該有獨立的協調節點,專門用於數據請求(node.master=false node.data=false),並給它們設置足夠的內存。通過數據節點與協調節點分離,可以避免節點掛掉之后,導致整個集群不可用,或者長時間響應遲鈍。
Routing數據路由
適當的增加刷新間隔
- es是一個准實時的搜索框架,這就意味着,從索引一個文檔直到文檔能夠被搜索到有一個輕微的延遲,也就是 index.refresh_ interval ,默認值是1秒,適當的增加這個值,可以避免創建過多的segment(segment是最小的檢索單元)。
配置慢查詢日志
- 通過在 Elasticsearch 中啟用 slowlogs 來識別運行緩慢的查詢。slowlogs 專門用於分片級別,僅適用於數據節點。協調/客戶端節點不具備慢日志分析功能,因為它們不保存數據。通過它,我們可以在日志中看到,那個查詢語句耗時長,從而制定優化措施。
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
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.search.slowlog.level: info
配置熔斷策略
- es7.0后版本提供一系列的斷路器,用於防止操作引起OutOfMemoryError。每個斷路器都指定了可以使用多少內存的限制。此外,還有一個父級斷路器,用於指定可在所有斷路器上使用的內存總量。
indices.breaker.request.limit:請求中斷的限制,默認為JVM堆的60%。
indices.breaker.total.limit:總體父中斷程序的啟動限制,如果indices.breaker.total.use_real_memory為,則默認為JVM堆的70% false。如果indices.breaker.total.use_real_memory 為true,則默認為JVM堆的95%。
network.breaker.inflight requests.limit 限制當前通過HTTP等進來的請求使用內存不能超過Node內存的指定值。這個內存主要是限制請求內容的長度。 默認100%。
script.max_compilations_rate:在允許的時間間隔內限制動態腳本的並發執行數量。默認值為75 / 5m,即每5分鍾75。
歡迎來公眾號【俠夢的開發筆記】 一起交流進步