Solr缓存介绍

转自:http://www.blogjava.net/conans/articles/380684.html

本文将介绍Solr查询中涉及到的Cache使用及相关的实现。Solr查询的核心类就是SolrIndexSearcher,

每个core通常在 同一时刻只由当前的SolrIndexSearcher供上层的handler使用

(当切换SolrIndexSearcher时可能会有两个同时提供服务),而Solr的各种Cache是依附于SolrIndexSearcher的,SolrIndexSearcher在则Cache 生,SolrIndexSearcher亡则Cache被清空close掉。

Solr中的应用Cache有filterCache、 queryResultCache、documentCache等,这些Cache都是SolrCache的实现类,

并且是 SolrIndexSearcher的成员变量,各自有着不同的逻辑和使命,下面分别予以介绍和分析。

1、SolrCache接口实现类

Solr提供了两种SolrCache接口实现类:solr.search.LRUCache和solr.search.FastLRUCache。

FastLRUCache是1.4版本中引入的,其速度在普遍意义上要比LRUCache更fast些。

1.1、solr.search.LRUCache

LRUCache可配置参数如下:

1)size:cache中可保存的最大的项数,默认是1024
2)initialSize:cache初始化时的大小,默认是1024。
3)autowarmCount:
当切换SolrIndexSearcher时,可以对新生成的SolrIndexSearcher做autowarm(预热)处理。
autowarmCount表示从旧的SolrIndexSearcher中取多少项来在新的SolrIndexSearcher中被重新生成,

如何重新生成由CacheRegenerator实现。在当前的1.4版本的Solr中,这个autowarmCount只能取预热的项数,

将来的4.0版本可以指定为已有cache项数的百分比,以便能更好的平衡autowarm的开销及效果。

如果不指定该参数,则表示不做autowarm处理。实现上,LRUCache直接使用LinkedHashMap来缓存数据,

由initialSize来限定cache的大小,淘汰策略也是使用LinkedHashMap的内置的LRU方式,

读写操作都是对map的全局锁,所以并发性效果方面稍差。

1.2、solr.search.FastLRUCache

在配置方面,FastLRUCache除了需要LRUCache的参数,还可有选择性的指定下面的参数:

1)minSize:当cache达到它的最大数,淘汰策略使其降到minSize大小,默认是0.9*size。
2)acceptableSize:当淘汰数据时,期望能降到minSize,但可能会做不到,则可勉为其难的降到acceptableSize,

默认是0.95*size。

3)cleanupThread:相比LRUCache是在put操作中同步进行淘汰工作,FastLRUCache可选择由独立的线程来做,

也就是配置cleanupThread的时候。当cache大小很大时,每一次的淘汰数据就可能会花费较长时间,

这对于提供查询请求的线程来说就不太合适,由独立的后台线程来做就很有必要。实现上,

FastLRUCache内部使用了ConcurrentLRUCache来缓存数据,它是个加了LRU淘汰策略的ConcurrentHashMap,

所以其并发性要好很多,这也是多数Java版Cache的极典型实现。

2、filterCache

filterCache存储了无序的lucene document id集合,该cache有3种用途:

1)filterCache
存储了filter queries(“fq”参数)得到的document id集合结果。Solr中的query参数有两种,即q和fq。如果fq存在,

Solr是先查询fq(因为fq可以多个,所以多个fq查询是个取结果交集 的过程),之后将fq结果和q结果取并。

在这一过程中,filterCache就是key为单个fq(类型为Query),value为documentid集合(类型为DocSet)的cache。

对于fq为range query来说,filterCache表现出其有价值的一面。
2)filterCache
还可用于facet查询(http://wiki.apache.org/solr/SolrFacetingOverview),facet查询中各
facet的计数是通过对满足query条件的document
id集合(可涉及到filterCache)的处理得到的。因为统计各facet计数可能会涉及到所有的doc
id,所以filterCache的大小需要能容下索引的文档数。
3)如果solfconfig.xml中配置了<useFilterForSortedQuery/>,

那么如果查询有filter(此filter是一需要过滤的DocSet,而不是fq,我未见得它有什么用),

则使用filterCache。

对于是否使用filterCache及如何配置filterCache大小,需要根据应用特点、统计、效果、经验等各方面来评估。

对于使用fq、facet的应用,对filterCache的调优是很有必要的。

4)客户端使用

使用filterQuery之后的查询代码:

SolrQuery query = new SolrQuery(); 
query.addFilterQuery("status:0 AND biz_type:1 AND class_id:1");  
query.setQuery("xxx:123");  
QueryResponse response = qyeryServer.query(query);  
 

经过测试这样优化之后,查询的RT会明显减小,QPS会有明显提升。

使用filterquery过程中需要注意点:

●不能在filterQuery 上重复出现query中的查询参数,如果上面的filterquery调用方法如下所示:

  1. query.addFilterQuery("status:0 AND biz_type:1 AND class_id:1 AND xxx:123");  
  2. query.setQuery("xxx:123");  

 如上,条件xxx:123 在filterQuery和query上都出现了,这样的写法非但起不到查询优化的目的,而且还会增加查询的性能开销。

●尽量减少调用addFilterQuery方法的次数

query.addFilterQuery("status:0 ");  
query.addFilterQuery("biz_type:1 ");  
query.addFilterQuery("class_id:1 ");  
query.setQuery("xxx:123");  

如上,将status:0 AND biz_type:1 AND class_id:1 这个组合查询条件,分三次调用filterQuery方法来完成,这样的调用方法虽然是正确的,并且能起到性能优化的效果,优化性能没有调用一次addFilterQuery方法来得高,原因是多调用了两次addFilterQuery,就意味着最后需要多进行两次结果集的求交运算,虽然结果集求交运算速度很快,但毕竟是有性能损耗的。

不过从内存开销的角度来说,调用三次addfilterQuery方法这样可以有效降低内存的使用量,这个是肯定的。所以在是否调用多次addFilterQuery方法的原则是,在内存开销允许的前提下,将量将所有filterQuery条件,通过调用有限次数的addFilterQuery方法来完成。

3、queryResultCache

顾名思义,queryResultCache是对查询结果的缓存(SolrIndexSearcher中的cache缓存的都是document id set),
这个结果就是针对查询条件的完全有序的结果。 
因为查询参数是有start和rows的,所以某个QueryResultKey可能命中了cache,但start和rows却不在cache的
document id set范围内。当然,document id
set是越大命中的概率越大,但这也会很浪费内存,这就需要个参数:queryResultWindowSize来指定document id set的大小。
<queryResultWindowSize>50</queryResultWindowSize>
相比filterCache来说,queryResultCache内存使用上要更少一些,但它的效果如何就很难说。
就索引数据来说,通常我们只是在索引上存储应用主键id,再从数据库等数据源获取其他需要的字段。
这使得查询过程变成,首先通过solr得到document id set,再由Solr得到应用id集合,
最后从外部数据源得到完成的查询结果。如果对查询结果正确性没有苛刻的要求,可以在Solr之外独立的缓存完整的
 
查询结果(定时作废),这时queryResultCache就不是很有必要,否则可以考虑使用queryResultCache。当然,如果发现在
queryResultCache生命周期内,query重合度很低,也不是很有必要开着它。 

4、documentCache

又顾名思义,documentCache用来保存<doc_id,document>对的。如果使用documentCache,就尽可能开大

些,至少要大过<max_results> *<max_concurrent_queries>,否则因为cache的淘汰,

一次请求期间还需要重新获取document一次。也要注意document中存储的字段的多少,避免大量的内存消耗。

5、User/Generic Caches 

Solr支持自定义Cache,只需要实现自定义的regenerator即可

6、The Lucene FieldCache 

lucene中有相对低级别的FieldCache,Solr并不对它做管理,所以,lucene的FieldCache还是由lucene的IndexSearcher来搞。 

7、autowarm

上面有提到autowarm,autowarm触发的时机有两个,一个是创建第一个Searcher时(firstSearcher),一个是创建个新

Searcher(newSearcher)来代替当前的Searcher。在Searcher提供请求服务前,Searcher中的各个Cache可以

做warm处理,处理的地方通常是SolrCache的init方法,而不同cache的warm策略也不一样。

1)filterCache:filterCache注册了下面的CacheRegenerator,就是由旧的key查询索引得到新值put到新cache中。

 2)queryResultCache:queryResultCache的autowarm不在SolrCache的init(也就是说,不是去遍历已

 有的queryResultCache中的query key执行查询),而是通过SolrEventListener接口的void

newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher

currentSearcher)方法,来执行配置中特定的query查询,达到显示的预热lucene FieldCache的效果。

3)documentCache:因为新索引的document id和索引文档的对应关系发生变化,所以documentCache没有warm的过程,

落得白茫茫一片真干净。尽管autowarm很好,也要注意autowarm带来的开销,这需要在实际中检验其warm的开销,

也要注意Searcher的切换频率,避免因为warm和切换影响Searcher提供正常的查询服务。

猜你喜欢

转载自haiziwoainixx.iteye.com/blog/2095473
今日推荐