天天看点

ES Cache: Node Cache

描述

NodeCache也称为QueryCache, 是在Node(机器)级别缓存的, 同一个节点上的多个shards共用的一个Node Cache.

Node Cache是段级别的, 段在进行段合并而销毁的时候, 其对应的NodeCache会失效, 没有warmup.

缓存内容

缓存的是filter query(用在filter context中的query).

Term query不会被缓存.

缓存的一些特殊设置值

具有比较复杂的缓存条件, 受以下因素影响:

LRUQueryCache

  • maxSize: 使用LRU策略清空旧缓存时最大保存的query的数量(这里的query与segment无关, 是在IndexSearcher内全局的)
  • maxRamBytesUsed: 使用LRU策略清空旧缓存时最大保存的query内存占用bytes(这里的query与segment无关, 是在IndexSearcher内全局的)
  • leavesToCache.minSize: 每个segment若要启用缓存则该segment的文档数必须>=minSize.
  • leavesToCache.minSizeRatio: 每个segment若要启用缓存则"该segment的文档数/IndexSearcher总文档数"必须>=minSizeRatio.
  • skipCacheFactor: 对于BooleanQuery, 首先计算一个leadCost代表用作lead的链表的cost, 然后一个Boolean条件要缓存的话, 需要满足cost/skipCacheFactor>leadCost, 其中cost为需要确定的这个Boolean条件的cost.

UsageTrackingQueryCachingPolicy

  • historySize: 追踪的Query使用情况的总Query数量. 注意当追踪的Query数量>historySize时, 这里使用的并不是LRU策略, 而是FIFO策略, 即最先被记录的Query当容量满了以后总是最先被淘汰的.

可配置项

  1. 给特定的index开启/关闭.
  2. 设置最大可用内存.

源码

涉及类

IndexSearcher.search ->

IndexSearcher.createWeight ->

IndexSearcher.queryCache= OptOutQueryCache (nested)-> IndicesQueryCache (nested)-> IndicesQueryCache$ElasticsearchLRUQueryCache.

IndexSearcher.queryCachingPolicy=UsageTrackingQueryCachingPolicy.           

复制

Q&A

Lucene

  • QueryCache是怎样集成到搜索中的?

IndexSearcher会绑定一个LRUQueryCache和一个UsageTrackingQueryCachingPolicy, 在为query生成weight阶段, 如果发现query不需要打分, 就会在生成的weight外套一个CachingWrapperWeight, CachingWrapperWeight相当于原query的一个代理, 会在生成scorer的时候处理缓存的存储和读取.

  • BooleanQuery的多个条件如何缓存的?

是分别缓存的, 只要顶层BooleanQuery是不需要分数的, 那么顶层BooleanQuery和其所有子Query都会分别单独缓存.

不过要注意的是在CachingPolicy里有个特殊处理, BooleanQuery的缓存查询数阈值为正常阈值-1, 也就是说如果只反复查询同一个BooleanQuery, 最终只会缓存这个BooleanQuery本身, 其他子query会处于要缓存的阈值.

  • LRU的lru算法怎么实现的?

LRUQueryCache.evictIfNecessary()

  • Node Cache如何递归实现的多层query的缓存?

通过Weight.scorerSupplier()方法的递归调用实现.

ES

  • ES filter context 是如何使用QueryCache的?

被包裹在filter context中的query实际上是被包裹了一个ConstantScoreQuery, 而ConstantScoreQuery在createWeight时会调用被包裹query的createWeight, 调用被包裹query的createWeight时传入的打分模式是ScoreMode.COMPLETE_NO_SCORES, 因此相当于在这里给被包裹query的weight先包裹了一个CachingWrapperWeight, 这样就实现了缓存的应用.

  • Solr Filter Cache的存储粒度是shard(某一个index在当前节点的shard), ES Node Cache的存储粒度是什么?

segment.

  • ES Node Cache与Solr的Filter Cache的warm up 区别.

Solr Cache处理缓存问题是在一个新searcher被打开后, 当前searcher继续提供服务, 新searcher开始预热它的缓存, 新searcher使用老searcher的缓存重新执行来填充自己的缓存.

ES的Node Cache是以段为单位的, 当添加新段的时候, 老段的缓存不受影响, 当执行段合并的时候, 被销毁的段的NodeCache会直接失效, 没有warmup.

Ref

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-cache.html

ES源码(7.13.0)