2018.09.05,深夜,最近因为各种事情,心烦意乱,睡不着,索性翻身起来,写一些没有营养的的东西。

个人认为,solr的分布式存在两种:

  • 伪分布式,即单shard但存在主从。
  • 真正的分布式

因为我认为真正意义上的分布式,不光是分流量,同样需要做到计算的分布式。但是呢,无论是哪一种,但凡涉及到数据的一致性的系统,基本都会考虑只允许主写,solr也是一样,只允许shard leader进行索引的索引的写入,再由主向从写入。

作为一个和数据打交道的分布式应用,solr还得考虑数据的分片,换个角度来说就是文档的路由。

所以下面分别说说solr中的文档分片,以及文档索引的简单流程。

文档路由

在分布式系统中应用的性能取决于那块短板,也就是如果各个分片上的数据严重不均匀的话,那搜索的性能将取决于数据最大的那个分片。为了保证性能最优,大部分情况下,我们希望各个分片上的数据是均匀的,当然在有些场景下,我们也会刻意让数据不均匀,比如我们就是希望热点数据在一个分片上,当时相对于全局的数据而言,正如二八法则所说,热点数据只是很少的那部分。

那么下面我们就讨论一下solr的文档路由策略,一旦一个collection确定好分片数量之后,solr就会给每个分片分配一个32位的散列值。在文档提交时,默认情况下solr会使用文档中唯一字段的值计算散列值,然后计算该散列值落在那个分片的散列值区间。

文档的索引

一旦确定好文档给哪个分片,那么剩下的事情就交给该分片上的leader进行处理了。shard leader接受到文档会怎么处理呢?

  1. 本地文档索引
  • 写tlog
  • 为每个文档分配新的版本号,并验证新老版本号。
  1. 主通过distribut update并行写从
  • 对于处于recovery状态的从节点而言,接受到更新请求,会暂时先将更新请求写入Transaction log
  1. 等待从节点返回

commit

这里顺便提一下solr的commit,solr有两种commit:

  • soft commit
  • hard commit

这两种提交策略,实际上在solrconfig.xml中也有提到:

<updateHandler class="solr.DirectUpdateHandler2">

  <updateLog>
    <str name="dir">${solr.ulog.dir:}</str>
  </updateLog>
  
  <autoCommit>
    <maxTime>30000</maxTime>
  </autoCommit>

  <autoSoftCommit>
    <maxTime>10000</maxTime>
  </autoSoftCommit>

</updateHandler>

Hard commits are about durability, soft commits are about visibility.

上面这句话解释的非常好,即硬提交关心的持久化(写硬盘),而软提交则关心索引的可见性(写内存)。其实也不必担心只做了soft commit索引数据就会丢,其实不会因为还有tlog作保证。

这里贴一篇很有趣的文章:《Understanding Solr Soft Commits and Data Durability

NRTDirectory

既然上面已经提到了soft commit,那么这里有必要再说一说近实时搜索,软提交相对于硬提交成本低的方面在于不要写硬盘,而是将索引写入NRTDirectory维护的内存中,但是不得不说的是,既然soft commit可以让文档可见,那么也必然会打开新的searcher,打开新的searcher同样会引入其它一些事情,缓存频繁失效,还需要缓存预热,查询预热等等。
如果有频繁更新,并且soft commit时间设置过短的话,那么就会产生多个searcher。
另外还需要注意,soft commit时间设置的过短,还会产生很多小的segment。

写着写着发现有好多东西要写,后面一篇文章,我将详细说明tlog、recovery以及soft/hard commit。