Solr之缓存篇
原文出自:http://my.oschina.net/u/1026644/blog/123957
Solr在Lucene之上开发了很多Cache功能,从目前提供的Cache类型有:
(1)filterCache
(2)documentCache
(3)fieldvalueCache
(4)queryresultCache
而每种Cache针对具体的查询请求进行对应的Cache。本文将从几个方面来阐述上述几种Cache在Solr的运用,具体如下:
(1)Cache的生命周期
(2)Cache的使用场景
(3)Cache的配置介绍
(4)Cache的命中监控
1 Cache生命周期
所有的Cache的生命周期由SolrIndexSearcher来管理,如果Cache对应的SolrIndexSearcher被重新构建都代表正在运行的Cache对象失效,而SolrIndexSearcher是否重新打开主要有几个方面影响。
(1)增量数据更新后提交DirectUpdateHandler2.commit(CommitUpdateCommand cmd),该方法代码如下:
if (cmd.optimize) {
optimizeCommands.incrementAndGet();
} else {
commitCommands.incrementAndGet();
if (cmd.expungeDeletes) expungeDeleteCommands.incrementAndGet();
}
Future[] waitSearcher = null;
if (cmd.waitSearcher) {//是否等待打开SolrIndexSearcher,一般新的Searcher会做一些预备工作,比如预热Cache
waitSearcher = new Future;
}
boolean error=true;
iwCommit.lock();
try {
log.info("start "+cmd);
if (cmd.optimize) {//是否优化索引,一般增量数据不优化
openWriter();
writer.optimize(cmd.maxOptimizeSegments);
} else if (cmd.expungeDeletes) {
openWriter();
writer.expungeDeletes();//一般对于标记删除的文档进行物理删除,当然优化也能将标记删除的doc删除,
//但是该方法会比优化快很多
}
closeWriter();//关闭增量打开的Writer对象
callPostCommitCallbacks();
if (cmd.optimize) {//如果有listener的话会执行这部分代码
callPostOptimizeCallbacks();
}
// open a new searcher in the sync block to avoid opening it
// after a deleteByQuery changed the index, or in between deletes
// and adds of another commit being done.
core.getSearcher(true,false,waitSearcher);//该方法是重新打开Searcher的关键方法,
//其中有重要参数来限定是否new open 或者reopen IndexReader.
// reset commit tracking
tracker.didCommit();//提供Mbean的一些状态监控
log.info("end_commit_flush");
error=false;
}
finally {//commlit后将一些监控置0
iwCommit.unlock();
addCommands.set(0);
deleteByIdCommands.set(0);
deleteByQueryCommands.set(0);
numErrors.set(error ? 1 : 0);
}
// if we are supposed to wait for the searcher to be registered, then we should do it
// outside of the synchronized block so that other update operations can proceed.
if (waitSearcher!=null && waitSearcher != null) {
try {
waitSearcher.get();//等待Searcher经过一系列操作,例如Cache的预热。
} catch (InterruptedException e) {
SolrException.log(log,e);
} catch (ExecutionException e) {
SolrException.log(log,e);
}
}
}
其中最重要的方法
core.getSearcher(true,false,waitSearcher);
再展开来看参数含义,
参数1 boolean forceNew,是否打开新的searcher对象
参数2 boolean returnSearcher,是否返回最新的searcher对象
参数3 final Future[] waitSearcher 是否等待searcher的预加工动作,也就是调用该方法的线程将会等待这个searcher对象的预加工动作,如果该searcher对象管理很多的 Cache并设置较大的预热数目,该线程将会等待较长时间才能返回。(预热,也许会很多人不了解预热的含义,我在这里稍微解释下,例如一个Cache已经 缓存了比较多的值,如果因为新的IndexSearcher被重新构建,那么新的Cache又会需要重新累积数据,那么会发现搜索突然会在一段时间性能急 剧下降,要等到Cache重新累计了一定数据,命中率才会慢慢恢复。所以这样的情形其实是不可接受的,那么我们可以做的事情就是将老Cache对应的
key,在重新构建SolrIndexSearcher返回之前将这些已经在老Cache中Key预先从磁盘重新load Value到Cache中,这样暴露出去的SolrIndexSearcher对应的Cache就不是一个内容为空的Cache。而是已经“背地”准备好 内容的Cache)
getSearcher()关于Cache有2个最重要的代码段,其一,重新构造新的SolrIndexSearcher:
newestSearcher = getNewestSearcher(false);
String newIndexDir = getNewIndexDir();
File indexDirFile = new File(getIndexDir()).getCanonicalFile();
File newIndexDirFile = new File(newIndexDir).getCanonicalFile();
// reopenReaders在solrconfig.xml配置,如果为false,每次都是重新打开新的IndexReader
if (newestSearcher != null && solrConfig.reopenReaders
&& indexDirFile.equals(newIndexDirFile)) {
IndexReader currentReader = newestSearcher.get().getReader();
IndexReader newReader = currentReader.reopen();//如果索引目录没变则是reopen indexReader
if (newReader == currentReader) {
currentReader.incRef();
}
tmp = new SolrIndexSearcher(this, schema, "main", newReader, true, true);//构建新的SolrIndexSearcher
} else {//根据配置的IndexReaderFactory来返回对应的IndexReader
IndexReader reader = getIndexReaderFactory().newReader(getDirectoryFactory().open(newIndexDir), true);
tmp = new SolrIndexSearcher(this, schema, "main", reader, true, true);//返回构建新的SolrIndexSearcher
}
在看看创建SolrIndexSearcher构造函数关于Cache的关键代码:
if (cachingEnabled) {//如果最后的参数为true代表可以进行Cache
ArrayList clist = new ArrayList();
fieldValueCache = solrConfig.fieldValueCacheConfig==null ? null : solrConfig.fieldValueCacheConfig.newInstance();
if (fieldValueCache!=null) clist.add(fieldValueCache);//如果solrconfig配置
页:
[1]