1. 概述

Solr 是最流行的基于 Lucene 的搜索解决方案之一。它具备快速、分布式、健壮、灵活等特性,背后还有活跃的开发者社区支持。SolrCloud 是 Solr 的新一代分布式版本

其核心特性之一是近实时(NRT)搜索,即文档一旦被索引就能立即用于搜索。

2. SolrCloud 中的索引机制

Solr 中的集合(Collection)由多个分片(Shard)组成,每个分片又有多个副本(Replica)。创建集合时,每个分片会选举一个副本作为该分片的领导者(Leader):

  • 当客户端尝试索引文档时,文档会根据其 id 的哈希值被分配到特定分片
  • 客户端从 ZooKeeper 获取该分片领导者的 URL,最终向该 URL 发送索引请求
  • 分片领导者先将文档在本地索引,再将其发送给副本
  • 当领导者收到所有活跃和恢复中副本的确认后,向索引客户端返回成功确认

**在 Solr 中索引文档时,文档不会直接写入索引,而是先写入所谓的 tlog(事务日志)**。Solr 使用事务日志确保系统崩溃时未提交的文档不会丢失。

如果系统在事务日志中的文档提交(持久化到磁盘)前崩溃,重启时会重放事务日志,实现零数据丢失。

每个索引/更新请求都会记录到事务日志,该日志会持续增长直到执行提交操作

3. SolrCloud 中的提交机制

提交操作意味着完成变更并将变更持久化到磁盘。SolrCloud 提供两种提交方式:硬提交(Commit)和软提交(Soft Commit)。

3.1. 硬提交(Commit)

硬提交指 Solr 将事务日志中所有未提交文档刷写到磁盘。活动事务日志被处理后,会开启新的事务日志文件

同时会刷新名为搜索器(Searcher)的组件,使新提交的文档可被搜索。搜索器可视为索引中所有已提交文档的只读视图。

客户端可通过调用 commit API 显式执行硬提交:

String zkHostString = "zkServer1:2181,zkServer2:2181,zkServer3:2181/solr";
SolrClient solr = new CloudSolrClient.Builder()
  .withZkHost(zkHostString)
  .build();
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField("id", "123abc");
doc1.addField("date", "14/10/2017");
doc1.addField("book", "To kill a mockingbird");
doc1.addField("author", "Harper Lee");
solr.add(doc1);
solr.commit();

也可在 solrconfig.xml 中配置为 autoCommit 自动执行(见 3.4 节)。

3.2. 软提交(SoftCommit)

软提交是 Solr 4 引入的特性,主要用于支持 SolrCloud 的 NRT 功能。它通过跳过硬提交的高成本操作,实现文档的近实时可搜索。

软提交期间事务日志不会被截断,而是继续增长。但会开启新的搜索器,使自上次软提交以来的文档可被搜索。同时 Solr 的部分顶级缓存会失效,因此并非完全无开销的操作。

当设置软提交的 maxTime 为 1000 时,表示文档在索引后最多 1 秒内即可被查询到

该特性赋予 SolrCloud 近实时搜索能力,新文档无需提交即可被搜索。软提交只能通过在 solrconfig.xml 中配置 autoSoftCommit 触发(见 3.4 节)。

3.3. 自动提交与自动软提交

solrconfig.xml 是 SolrCloud 最重要的配置文件之一,在集合创建时生成。要启用 autoCommitautoSoftCommit,需更新文件中的以下配置:

<autoCommit>
  <maxDocs>10000</maxDocs>
  <maxTime>30000</maxTime>
  <openSearcher>true</openSearcher>
</autoCommit>

<autoSoftCommit>
  <maxTime>6000</maxTime>
  <maxDocs>1000</maxDocs>
</autoSoftCommit>

maxTime: 自最早未提交更新后的毫秒数,达到该值后触发下一次提交/软提交。

maxDocs: 自上次提交后的更新次数,达到该值后触发下一次提交/软提交。

openSearcher: 该属性告诉 Solr 提交后是否开启新搜索器。**若为 true,提交后旧搜索器关闭,新搜索器开启,使提交的文档可被搜索**;若为 false,提交后文档不可被搜索。

4. 近实时搜索

Solr 通过结合硬提交和软提交实现近实时搜索。如前所述,文档添加到 Solr 后,只有提交到索引才能在搜索结果中可见。

普通硬提交成本较高,因此软提交很有用。但软提交不持久化文档,我们仍需根据预期负载设置合理的自动提交 maxTime 间隔(或 maxDocs)。

4.1. 实时获取(Real-Time Gets)

Solr 还提供另一项真正实时的特性——get API。该 API 能返回尚未软提交的文档

若在索引中找不到文档,它会直接在事务日志中搜索。因此我们可以在索引调用返回后立即执行 get API,仍能获取到文档。

但⚠️,所有过于完美的功能都有陷阱:get API 调用中必须传入文档的 id。当然可以同时提供其他过滤查询,但缺少 id 则调用无效:

http://localhost:8985/solr/myCollection/get?id=1234&fq=name:baeldung

5. 总结

Solr 在调整 NRT 能力方面提供了相当大的灵活性。要获得最佳服务器性能,需根据用例和预期负载,对提交和软提交的参数进行实验调优。

提交间隔不宜过长,否则事务日志会增长到过大尺寸。但软提交也不宜过于频繁。

建议上线前进行充分的性能测试,验证文档能否在期望的时间窗口内变为可搜索状态。


原始标题:Commits and NRT Search in SolrCloud