在使用 solrcloud 的时候,很多人都会使用主从同步实现负载均衡与索引的容错性,当索引经过修改,删除或者新增了数据后,索引的段数会不断增多,累积得越多,索引的搜索速度越慢.这时很多人都会提出使用 optimize 优化索引.没错,这一个的确是一个相当重要的手段,而且 solrcloud 也提供了相关的功能即可.本来看似很简单就能解决的问题,深究下去,还是有点意思的.再来一种情况就是,有时候需要把几个 code 合并成一个大的 core ,当然了solrcloud 也有提供相关的功能.但似乎实际用起来并非这么的顺手.出现很多类似时间超时,连接超时等一大堆的问题.
所以我们使用了 lucene 的 misc 包提供的叫 IndexMergeTool 的工具类,在 solrcloud 的官方文件中也有提及,此类除了用于合并索引后,其实还可以用于优化索引,原理都相似.
问题的发现
最近在一次的索引优化中,我们设想就是一个 leader 完成索引优化后,索引发生改变了,其他的 replica 则会把优化后的索引同步过去,我是使用 IndexMergeTool 去优化索引的.但当优化后,其他的 replica 并没有执行同步,我尝试重启 leader , replica 同样没有同步的操作,而看日志的确也没有发生同步.到底是怎么回事?
问题的根源
我开始以为是版本有问题,就尝试更换到 solrcloud 4.7.1 ,我发现把replica关闭,然后先写到 leader 再重启 replica 数据的确能同步,我通过 solrcloud 后台的 optimize 索引后,同样能正常同步.现在的问题看似是因为我使用了 IndexMergeTool 作为合并的工具而导致了不能同步了.
对比情况
我用 IndexMergeTool 合并完的索引与 solrcloud 后台操作优化索引对比了一下,大小与结构上差别不大,而且两份索引搜索出来的结果是相同的,证明索引是没有因为优化而损坏.通过 solrcloud 后台对比后有了一个发现,
正常能同步的索引显示
而通过IndexMergeTool 后,索引版本成为
看来,因为是版本问题导致了索引并不能正常同步成功了.再查看 solrcloud 优化的 handle 的源码后,恍然大悟,原来 solrcloud在优化索引后做了一些额外的处理
// 此类为 DirectUpdateHandler2 类,的 commit(CommitUpdateCommand cmd) 方法里面.
IndexWriter writer = iw.get();
if (cmd.optimize) {
// 普通的索引优化处理,跟IndexMergeTool 处理是一样的.
writer.forceMerge(cmd.maxOptimizeSegments);
} else if (cmd.expungeDeletes) {
writer.forceMergeDeletes();
}
if (!cmd.softCommit) {
synchronized (solrCoreState.getUpdateLock()) { // sync is currently needed to prevent preCommit
// from being called between preSoft and
// postSoft... see postSoft comments.
if (ulog != null) ulog.preCommit(cmd);
}
// SolrCore.verbose("writer.commit() start writer=",writer);
// 这里却添加在索引合并完后,添加了这一个对合并完操作后的版本时间写入
if (writer.hasUncommittedChanges()) {
final Map<String,String> commitData = new HashMap<String,String>();
commitData.put(SolrIndexWriter.COMMIT_TIME_MSEC_KEY,
String.valueOf(System.currentTimeMillis()));
writer.setCommitData(commitData);
writer.commit();
} else {
log.info("No uncommitted changes. Skipping IW.commit.");
}
通过源码可以看到,除了做合并后,最后还向索引中添加了一个叫"commitTimeMSec"的时间点,经后面发现那个时间点跟显示的 version 为一致的,说明就是那个时间点作为同步的依据了.同时查看了 msic 包下面的 IndexMergerTool 源码,因为本来就是 lucene 的包,所以不会象 solrcloud 再做这样子的处理了,后面添加上后,索引版本号就能正常显示也能正常同步了.
解决方案
修改IndexMergerTool 代码,红色框中所显示的
欢迎连载,但请注明出处及作者
http://kernaling-wong.iteye.com/blog/2066793
by kernaling.wong