ElasticSearch涉及的緩存,大(da)致有4種。分別為,page cache、node-level query cache、shard-level request cache、field data cache。
page cache 查詢(xun)過程中讀取 Lucene 文(wen)件(jian)時(shi)會(hui)被(bei)操作(zuo)系統 pagecache 緩存(cun),pagecache使用類似 LRU 的(de)策略對數(shu)據進行淘汰,但是由于(yu) pagecache 對所有文(wen)件(jian)一視(shi)同(tong)仁,并且(qie)難以控(kong)制,此處也不(bu)做深入討(tao)論。
field data cache 對于 text 類型進行聚(ju)(ju)合等獲取字段值的(de)行為時才會用到 fielddata,他會占用大量內存。fielddata默認關閉,因為在 text 類型上執行聚(ju)(ju)合一般是(shi)沒有意義的(de),因此這里不深入討(tao)論。
好了,接下來,我們重點(dian)介紹(shao)node-level query cache和shard-level request cache。
shard-level request cache
介紹:
是分片級別的查詢緩存,每個分片有自己的緩存。該緩存采用 LRU 機制,緩存的 key 是整個客戶端請求,緩存內容為單個分片的查詢結果。如果一個客戶端請求被數據節點緩存了,下次查詢的時候可以直接從緩存獲取,無需對分片進行查詢。緩存的實現在 IndicesRequestCache 類中,緩存的 key 是一個復合結構,主要包括shard,indexreader,以及客戶端請求三個信息。
注意,上面加黑(hei)的“客戶端請(qing)求(qiu)”五個(ge)字。官(guan)方blog中(zhong)有一句解(jie)釋,“This cache helps a lot in speeding Kibana up by caching search responses consisting only of aggregations”就是說(shuo)此(ci)緩存可(ke)以(yi)加快我(wo)們再kibana的搜索,為什(shen)么是kibana中(zhong)搜索呢?因為我(wo)們的大部分請(qing)求(qiu),可(ke)能(neng)來自同一個(ge)kibana。
緩存策略:
并(bing)非所有的分片級查詢都會被緩存(cun)。
緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)策(ce)略指(zhi)哪些類(lei)(lei)型(xing)(xing)的(de)查(cha)(cha)詢需要(yao)緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun),哪些類(lei)(lei)型(xing)(xing)的(de)緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)無需緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)。IndicesService#canCache 方法中定義了(le)某個請求是(shi)否可以被(bei)緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun),簡(jian)單的(de)可以理解(jie)成只有(you)客戶端查(cha)(cha)詢請求中 size=0的(de)情況下才會(hui)被(bei)緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun),其(qi)他不被(bei)緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)的(de)條件還(huan)包括 scroll、設置了(le) profile屬性,查(cha)(cha)詢類(lei)(lei)型(xing)(xing)不是(shi) QUERY_THEN_FETCH,以及設置了(le) requestCache=false等(deng)。另外一些存(cun)(cun)(cun)(cun)在不確(que)定性的(de)查(cha)(cha)詢例如:范圍查(cha)(cha)詢帶有(you)now,由于(yu)它是(shi)毫秒級別的(de),緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)下來沒有(you)意義,類(lei)(lei)似的(de)還(huan)有(you)在腳本查(cha)(cha)詢中使用了(le) Math.random() 等(deng)函數的(de)查(cha)(cha)詢也不會(hui)進行緩(huan)(huan)(huan)(huan)(huan)(huan)存(cun)(cun)(cun)(cun)。

查(cha)詢(xun)結果中被(bei)緩(huan)存的內容主要包括(kuo):aggregations(聚合結果)、hits.total、以及 suggestions等。
由于 Request Cache 是分(fen)片(pian)(pian)級別的(de)(de)緩(huan)存(cun)(cun),當有新的(de)(de) segment 寫入到分(fen)片(pian)(pian)后,緩(huan)存(cun)(cun)會失(shi)效(xiao),因為(wei)之(zhi)前(qian)的(de)(de)緩(huan)存(cun)(cun)結(jie)果(guo)(guo)已經無法代(dai)表整個分(fen)片(pian)(pian)的(de)(de)查詢(xun)結(jie)果(guo)(guo)。所以分(fen)片(pian)(pian)每次 refresh之(zhi)后,緩(huan)存(cun)(cun)會被清除。
緩存設置:
indices.requests.cache.size:默認堆內存的(de)1%
index.requests.cache.enable:是否開啟(qi)緩存,默認(ren)開啟(qi)
node-level query cache
介紹:
node-level query cache 是(shi) Lucene 層面實(shi)現的(de)(de),封裝在 LRUQueryCache 類中(zhong),默認開啟。一個ES的(de)(de)查(cha)詢會(hui)先被parse 成一系列的(de)(de)Lucene 的(de)(de)phrase,這些(xie)phrases 中(zhong)的(de)(de)filter語(yu)句(ju),如果對于查(cha)詢條件(jian)是(shi)一樣(yang)的(de)(de)時候,其實(shi)結果集是(shi)已(yi)定的(de)(de),那么這些(xie)phrase 其實(shi)就(jiu)是(shi)可以(yi)存放在一個地(di)方當做cache用,這個就(jiu)是(shi) query cache
緩存策略:
并非所(suo)有的 filter 查詢都會(hui)被(bei)緩存下來(lai)。
QueryCache策(ce)(ce)略決定某個(ge)查詢要(yao)(yao)不要(yao)(yao)緩存(cun)。ES 使用 UsageTrackingQueryCachingPolicy作為默認的緩存(cun)策(ce)(ce)略,在這個(ge)策(ce)(ce)略中,判斷某個(ge)查詢要(yao)(yao)不要(yao)(yao)緩存(cun),主要(yao)(yao)關注兩點:
某些(xie)類型的(de)查詢,永遠不(bu)會緩(huan)存,目(mu)前(qian) shouldNeverCache 方(fang)法(fa)中定義了(le)以下(xia)類型:

某條 query 的 訪問頻率大于等于特定閾值之后,該 query結果才會被緩存。對于訪問頻率,主要分為2類,一類是訪問2次就會被緩存,包括: MultiTermQuery、MultiTermQueryConstantScoreWrapper、TermInSetQuery、PointQuery 在 isCostly方法中定義。其余類型的查詢訪問5次會被緩存。
最(zui)(zui)近(jin)(jin)使用次(ci)數如何統(tong)計的(de)?lucene 里維(wei)護一個大小(xiao)為256的(de)環(huan)形(xing)緩(huan)(huan)沖(chong),最(zui)(zui)近(jin)(jin)使用過的(de) query 會做一下 hash 保存到這個緩(huan)(huan)沖(chong)里,當緩(huan)(huan)沖(chong)滿的(de)時候(hou)直(zhi)接覆蓋最(zui)(zui)后一個,被訪(fang)(fang)問一次(ci)也不會調整(zheng)他在(zai)緩(huan)(huan)沖(chong)里的(de)順序。因此“最(zui)(zui)近(jin)(jin)訪(fang)(fang)問頻率”可以理解成(cheng):在(zai)最(zui)(zui)近(jin)(jin)的(de)256個歷史記(ji)錄(lu)里,query 被訪(fang)(fang)問的(de)次(ci)數。
緩存設置:
indices.queries.cache.count:默認(ren)緩(huan)存10000個子查詢的(de)結(jie)果
indices.queries.cache.size:緩存(cun)大小默認為堆內存(cun)的(de)10%
參(can)考://www.elastic.co/guide/en/elasticsearch/reference/current/query-cache.html
//www.elastic.co/guide/en/elasticsearch/reference/current/shard-request-cache.html