3.7 ES中的緩存
Elasticsearch在運行過程中會使用到各種各樣的緩存,如Query cache、Request cache、page cache、fielddata。這里主要討論Query cache 和 Request cache
3.7.1 Shard Request Cache
1)簡介
顧名思義,這是分片級別的緩存。緩存采用LRU機制,key包含shard、indexreader、查詢請求的信息,value是查詢結果序列化之后的數據。
由於客戶端查詢請求會被序列化之后作為key的一部分,所以有可能同樣的查詢、json內容順序不同等變化都會導致無法命中緩存
由於這是分片級別的緩存,所以當新的段寫入到分片后,原有的緩存將會失效
2)緩存策略
不是所有的查詢請求都會被緩存。在IndicesService#canCache中定義了哪些請求時不能被緩存的。不被緩存的情況有
- 使用了scroll滾動查詢
- 查詢類型不是QUERY_THEN_FETCH
- 帶有分析的查詢,設置了profile屬性
- 設置不需要緩存
- 范圍查詢中帶有now的。這種查詢是毫秒級別的,緩存沒有意義
3)配置項與監控api
-
indices.requests.cache.size
:設置緩存占用堆空間的大小,默認是1% -
index.requests.cache.enable
:緩存開關 -
GET /_nodes/stats/indices/request_cache?human
3.7.2 Node Query Cache
1)簡介
相比於Shard Request Cache這種分片級別的緩存,Node Query Cache就只緩存filter中過濾的結果。所以,Node Query Cache又被稱為Filter Cache。
Filter查詢和普通查詢最主要的區別就是不會計算評分
它可以緩存不同查詢之間使用到重復數據的部分。比如說張三查詢了近一個月內火腿腸的銷量,李四查詢了近一個月內火腿腸不合格的數量。這兩次查詢的共同之處是時間范圍都是一個月內。而Node Query Cache會在第一次查詢時對近一個月內的數據打上標記,在下一次查詢的時候只去搜索這些打過標記的數據。
這種緩存是Lucene中實現的,ES主要進行的是策略控制。
2)工作原理
Node Query Cache使用位圖這種數據結構來對數據進行標記。首先創建一個大小為maxDoc(文檔數量)的位圖:FixedBitSet。然后在遍歷過程中對命中的文檔在位圖對應位置做標記。例如,[1,2,7]
位置的文檔命中了查詢條件,那么對應的位圖則為[1,1,0,0,0,0,1]
。當一個查詢中有多個filter條件時,只需要做位運算即可快速准確的找到命中的文檔
3)緩存策略
ES使用UsageTrackingQueryCachingPolicy作為默認的緩存策略。這個策略的主要關注點是:
- 是不是特定類型的查詢。如term query(精確查詢)、MatchAllDocsQuery、MatchNoDocsQuery。以及子查詢為空的BooleanQuery、DisjunctionMaxQuery
- 某條 query 的訪問頻率大於等於特定閾值之后,該 query結果才會被緩存。對於訪問頻率,主要分為2類,一類是訪問2次就會被緩存,包括: MultiTermQuery、MultiTermQueryConstantScoreWrapper、TermInSetQuery、PointQuery 在 isCostly方法中定義。其余類型的查詢訪問5次會被緩存。
如何統計某個query的頻率?
Lucene中維護了一個長度為256的環形buffer。每個查詢在被hash之后保存進去。因此,上面的頻率可以理解為最近256次查詢中出現的頻率
4)配置項與監控
indices.queries.cache.count
,緩存查詢的數量,默認是1windices.queries.cache.size
,緩存占堆內存的大小,默認是10%GET /_nodes/stats/indices/query_cache?human