Elasticsearch搜索引擎之缓存:Request Cache、Query Cache、Fielddata Cache
????????ElasticSearch 查詢需要占用 CPU、內存資源,在復雜業務場景,會出現慢查詢,需要花費大量的時間。為了提高系統的性能,除了增加集群硬件配置這種成本高昂的開銷外,還可以使用 ES 的緩存,下面我們就介紹幾種 ES 中常用的緩存。
一、Request cache:
1、什么是 Request cache:
????????Request Cache,全稱是 Shard Request Cache,即分片級請求緩存。當對一個或多個索引發送搜索請求時,搜索請求首先會發送到ES集群中的某個節點,稱之為協調節點;協調節點會把該搜索請求分發給其他節點并在相應分片上執行搜索操作,我們把分片上的執行結果稱為“本地結果集”,之后,分片再將執行結果返回給協調節點;協調節點獲得所有分片的本地結果集之后,合并成最終的結果并返回給客戶端。
By default, the requests cache will only cache the results of search requests where size=0, so it will not cache hits, but it will cache hits.total, aggregations, and suggestions.Most queries that use now (see Date Mathedit) cannot be cached.
????????Request Cache 在每個分片上緩存了本地結果集,這使得頻繁使用的搜索請求幾乎立即返回結果。默認情況下只會緩存查詢中參數 size=0 的搜索請求的結果,因此將不會緩存hits,但會緩存 hits.total,aggregations(聚合) 和 suggestions。所以,request cache 分片請求緩存非常適合日志用例場景,在這種情況下,數據不會在舊索引上更新,并且可以將常規聚合保留在高速緩存中以供重用。
2、request cache 緩存的失效:
????????ES 能夠保證在使用與不使用?Request Cache 情況下的搜索結果一致,那 ES 是如何保證的呢?這就要通過 Request Cache 的失效機制來了解啦。
????????Request Cache 緩存失效是自動的,當索引 refresh 時就會失效,也就是說在默認情況下, Request Cache 是每1秒鐘失效一次,但需要注意的是,只有在分片的數據實際上發生了變化時,刷新分片緩存才會失效。也就是說當一個文檔被索引 到 該文檔變成Searchable的這段時間內,不管是否有請求命中緩存該文檔都不會被返回。
????????所以我們可以通過 index.refresh_interval 參數來設置 refresh 的刷新時間間隔,刷新間隔越長,緩存的數據越多,當緩存不夠的時候,將使用LRU最近最少使用策略刪除緩存數據。
????????當然,我們也可以手動設置參數 indices.request.cache.expire 指定失效時間(單位為分鐘),但是基本上我們沒必要去這樣做,因為緩存在每次索引 refresh 時都會自動失效。
????????最后,我們也可以通過 API 手動清除 Request Cache,使用方式如下:
curl -XPOST '索引的IP:端口/索引名/_cache/clear?request_cache=true'
3、request cache 的使用與設置:
3.1、request cache 的使用:
默認情況下,Request Cache 是關閉的,我們可以在創建新的索引時啟用,例如:
curl -XPUT 服務器IP:端口/索引名 -d '{"settings": {"index.requests.cache.enable": true} }'也可以通過動態參數配置來進行設置:
curl -XPUT 服務器IP:端口/索引名/_settings -d '{ "index.requests.cache.enable": true }'開啟緩存后,需要在搜索請求中加上 request_cache=true 參數,才能使查詢請求被緩存,比如:
curl -XGET '服務器IP:端口/索引名/_search?request_cache=true&pretty' -H 'Content-Type: application/json' -d '{"size": 0,"aggs": {"popular_colors": {"terms": {"field": "colors"}}} }'兩個注意事項:
(1)第一:參數 size:0 必須強制指定才能被緩存,否則請求是不會緩存的,即使手動的設置request_cache=true
(2)第二:在使用 script 腳本執行查詢時,由于腳本的執行結果是不確定的(比如使用 random 函數或使用了當前時間作為參數),一定要指定 request_cache=false 禁用 Request Cache 緩存。
3.2、request cache 的設置:
Request Cache 作用域為 Node,在 Node 中的 Shard 共享這個Cache空間。默認最大大小為 JVM堆內存的1%。可以使用以下命令在 config / elasticsearch.yml 文件中進行更改:
indices.requests.cache.size: 1%
Request Cache 是以查詢的整個DSL語句做為key的,所以如果要命中緩存,那么查詢生成的DSL一定要一樣,即使修改了一個字符或者條件順序,都不能利用緩存,需要重新生成Cache。
3.3、request cache 大小的查看方式:
GET?/_stats/request_cache?human
GET?/_nodes/stats/indices/request_cache?human
二、QueryCache:
1、什么是?Query Cache:
????????Query Cache,也稱為 Filter Cache,就是對查詢中包含的 Filter 過濾器的執行結果進行緩存,緩存在節點查詢緩存中,以便快速查找。每個節點都有一個所有分片共享的查詢緩存。當緩存空間存滿時,使用 LRU 策略清理最近最少使用的查詢結果,以騰出空間存放新結果數據。
ES 在 5.1.1 版本中移除了 term query 的緩存,因為 term query 和 filter query 二者查詢時間相差不多。
????????默認情況下,節點查詢緩存最多可容納10000個查詢,最多占總堆空間的10%,為了確定查詢是否符合緩存條件,Elasticsearch 維護查詢歷史記錄以跟蹤事件的發生。但是,當 segment 的文檔數量小于 10000 或者 小于分片文檔總數的 3% 時,該查詢是不會被緩存的。
? ? ? ? 由于緩存是按段劃分的,因此合并段可使緩存的查詢無效,同時,只有對頻繁訪問的請求才會使用查詢緩存,因為查詢緩存是基于 bitmap 的,而建立?bitmap 的過程需要一定的時間。
2、Query Cache 相關參數配置:
(1)index.queries.cache.enabled:控制是否啟用節點查詢緩存,可以設置 true(默認)?或者 false。該設置只能在創建索引或者索引關閉(close)時設置:
PUT my_index_01{ ?"settings": { ? ?"index.queries.cache.enabled": false ?}}
(2)indices.queries.cache.size:設置查詢緩存的對堆內存大小,默認10%,可設置成百分比,也可設置成具體值,如 512m。
三、Fielddata Cache:
1、什么是?Fielddata Cache:
? ? ? ? ES 的快速搜索特性主要依賴于倒排索引這種數據結構,但如果僅僅依靠倒排索引是很難在查詢中做到排序和統計的,因為它并不像關系型數據庫那樣采用“列式存儲”,而是基于一個 “term” 到 “document” 的倒排。這種情況下,如果需要做數據聚合和排序,就需要將倒排索引的數據讀取出來,重新組織成一個數組緩存,也就是從倒排索引中生成出來的要自己維護這段Cache, 之后才能夠高效的做排序和聚合計算。
? ? ? ? 為了解決上面的問題,就出現了 Fielddata Cache 字段數據緩存,它主要用于字段的排序和聚合,將所有的字段值加載到內存中,以便提供基于文檔快速訪問這些值。當第一次在某個分詞的字段上執行聚合、排序或通過腳本訪問的時候就會觸發該字段 Fielddata Cache 的加載,這種緩存是 segment?級別的,當有新的 segment 打開時舊的緩存不會重新加載,而是直接把新的 segment 對應的 Fielddata Cache 加載到內存。
因為是基于 segment 級別的,所以 Fielddata Cache 失效和 Node Query Cache 失效機制相同,當 segment 被合并后,才會失效。
????????Fielddata Cache 的構建成本很高,一旦 Fielddata 被加載到內存,那么在該 Fielddata Cache?對應的 Segment 生命周期范圍內都會駐留在堆內存中,也就是說當觸發段合并時會導致合并后的更大段的 Fielddata Cache 加載。同時,由于 Fielddata Cache 默認緩存大小是無限的,這將導致緩存高速增長直到達到 field data 斷路器設置的限制。特別是當加載“高基數”的分詞字段時(那些分詞后存在大量不同詞的字段),針對這種字段的聚合排序其實是非常沒有意義的,我們更多的要去考慮是否能用 not_analyzed 代替。如果設置了 fielddata cache 大小限制,緩存就會清除緩存中最新最少更新的數據。此設置可以避開 field data? 斷路器限制,但需要根據需要重建緩存;如果達到 field data 斷路器限制,Elasticsearch 底層將阻止進一步增加緩存大小的請求。
? ? ? ? 由于 Fielddata Cache 是存放在堆內存中,在海量數據聚合的時候,生成的這些 fielddata 可能堆內存放不下,從而引起性能問題,甚至JVM OOM。所以?Elasticsearch2.0 開始,在非 text 字段開啟 doc_values,基于 doc_values 做排序和聚合,可以減少對 FielddataCache 的依賴,減少內存消耗,因為 doc_values 在使用時不需要全部載入內存,可以減少節點 OOM 的概率。由于 doc_values 的特性性能上也不會有多少損失,doc_values 是一種正向索引結構以順序預讀的方式進行獲取,所以隨機獲取就很慢了。在 5.0?開始,text 字段默認關閉了 Fielddata 功能, Fielddata Cache 應當只用于 global ordinals。
對 doc_values 的介紹與使用感興趣的讀者可以移步這篇文章:https://blog.csdn.net/a745233700/article/details/117915118
2、?Fielddata Cache 參數配置:
(1)開啟與關閉?Fielddate Cache:
默認情況下Fielddate Cache是默認開啟的,我們可以通過下面的設置來關閉,關閉后就無法對分詞字段執行聚合、排序操作了。
PUT my_index {"mappings": {"my_type": {"properties": {"text": {"type": "string","fielddata": {"format": "disabled" }}}}} }(2)indices.fielddata.cache.size:設置字段數據緩存的最大值,通過百分比 30% 或者具體值 12GB 來設置,默認無限制。
(3)indices.breaker.fielddata.limit:此參數設置 Fielddata 斷路器限制大小(公式:預計算內存 + 現有內存 <= 斷路器設置內存限制),默認是60%JVM堆內存,當查詢嘗試加載更多數據到內存時會拋異常(以此來阻止JVM OOM發生)
(4)indices.breaker.fielddata.overhead:一個常數表示內存預估值系數,默認1.03,比如預計算加載100M數據,那么100*1.03=103M會用103M作為參數計算是否超過斷路器設置的最大值。
參考文章:Elasticsearch2.x 三種緩存介紹:Query Cache、Request Cache、Fielddata Cache_飛奔的代碼-CSDN博客_es query_cache
總結
以上是生活随笔為你收集整理的Elasticsearch搜索引擎之缓存:Request Cache、Query Cache、Fielddata Cache的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Elasticsearch搜索引擎:ES
- 下一篇: JUC多线程:synchronized锁