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