美文网首页程序员
Bleve scorch索引引擎源码解析

Bleve scorch索引引擎源码解析

作者: 贺大伟 | 来源:发表于2018-09-10 23:03 被阅读272次

    Bleve支持两个索引引擎,一个是upsidedown,一个是scorch。Upsidedown底层依赖KV存储引擎,可以是各种KV存储引擎,目前官方支持的包括:boltdb,goleveldb,gtreap,metrics,moss,另外作者在blevex中提供了额外的KV引擎支持:cznicb,leveldb,preload,rocksdb。而scorch是一个类Lucene的索引引擎,同样采用segment分段存储。

    Scorch包括两部分kv存储+file store,其中kv存储采用boltdb,主要用于存储internal KV以及segment的元数据,用于重启时的恢复。File store存储倒排索引和文档。

    启动

    我们先看看scorch的定义

    nextSegmentID: 下一个segment的ID,每次分配之后自增1.

    unsafeBatch: 如果是true,不等待文档落盘即返回给客户端结果

    root: 所有的segement的根,总入口

    rootPersisted: 等待文档落盘的通知队列

    nextSnapshotEpoch: 快照的下一个版本

    eligibleForRemoval: 可以安全GC的快照版本列表

    numSnapshotToKeep: 支持保留的快照数量,通过配置指定,默认是1

    introductions: segment添加队列,新的segment需要加入到这个队列等待后续处理

    persists: 等待flush到磁盘的segment队列

    merges: 合并segment的任务队列

    introducerNotifier: segment处理通知队列,epoch变化后发送通知

    revertToSnapshot: 恢复到指定快照任务通知通道

    persisterNotifier: segment flush 到磁盘通知队列

    rootBolt: boltDB

    pauseCount: 暂停引用计数

    首先scorch会open boltdb,recover segment。

    然后会启动三个异步任务:主任务(mainLoop),持久化任务(persisterLoop),合并任务(mergerLoop)。

    写文档

    Scorch将所有的写API(update,delete,batch)都转化成batch处理。

    Batch的执行过程根Upsidedown不太一样

    1. 会添加一个特殊的field _id,用来存储docID,因为是使用文件系统存储,因此必须把docID也作为特殊的field存储才方便。这里的docID并没有像Lucene那样映射成Sequence Number,而是直接存储了。

    2. 创建分词任务加入分词任务队列,异步处理文档分词

    3. 等待分词结束

    4. 根据分词结果创建一个segmentBase

    5. prepareSegment准备segment处理

    如上图,我们看看segmentbase的创建过程:

    1. 首先从一个pool取出一个临时计算对象处理这个过程,主要的目的就是复用buffer,减少内存的频繁申请和GC。

    2. CountHashWriter是一个可以在写入过程中实时计算CRC的writer。

    3. Convert()会将文档,倒排索引转化成二进制流写入内存中。稍后我们看看这个过程。

    4. InitSegmentBase()初始化segmentBase,核心就是初始化segmentBase,记录各个类型数据的存储偏移位置,这个信息是维护在内存中的,不会flush到磁盘,并且把docValueReader加载到内存中,也就是在scorch中实现了docValue的支持,而upsidedown是不支持docValue的。

    如上图,首先根据field name映射field ID,并且field _id 的ID是0,从这里可以看出,scorch是每一个segment进行一次这样的转换,如果schema并不是实时变化的,那么这个做的意思不大,严重影响性能(或者有其他的考量,暂时未知)。

    然后处理dicts,即倒排索引的存储。如下图,核心流程就是生成postlist

    接下来就是处理文档自身的存储,如下图:

    至此segmentBase已经生成,需要添加到新segment队列中等待进一步处理,如下图:

    如果不等待文档落盘就返回,那么可以通过配置unsafeBatch为true这样写的性能会比较差,实际的测试结果是很差。

    遍历所有的segment,以ids查找对应的postList,把docID相同的文档存入一个bitmap存储delta,记录在新的introduction的obsoletes对象中,表示这些文档在旧的segment可以删除了(这个流程对于delete doc同样的合理的)。然后写入后续处理队列introductions等待处理完成。

    Segment file持久化

    Main Loop中会对新生成的segment进行进一步处理,如下图:

    如上图,scorch会遍历每一个segment,这里为什么要再次check delete docs呢,是因为存在并发写,导致部分segment没有更新delete doc list,这里补充处理。

    如上图,scorch需要把原来的segment复制一份到新的快照中,当然并不会已经持久化到磁盘上的文件,而是把内存中的信息复制一份,不过从这个角度讲,scorch的写仍然是一个很重的操作,每次都要copy一次全部的segment。好处就是写入即可读,不存在ES的准实时问题,不过代价很大。

    如上图所示,Internal的KV都copy到新的快照中,内存存储。

    如上图,将segment flush通知接收通道加入到rootPersisted中,等待后续的merge落盘处理后通知完成,接着更新快照的epoch,替换旧的快照。这种情况下如果进程crash,那么数据是会丢失的,因此才有那个unsafeBatch开关,scorch并没有Transfer Log。这种情况下只能恢复到上一个持久化的快照点。

    接下来我们看看segment 持久化是如何实现的

    Scorch启动一个异步任务持续监测是否触发segment持久化。

    如果配置了flush间隔,scorch将定时检查是否需要持久化segment,scorch会一直等待直到磁盘上的segment数量小于配置的门限,从这里看出persister Loop主要是做内存segment的合并。

    notifyMergeWatchers()会及时给哪些低版本的epoch的watcher返回persister结果,避免等待时间过长。

    这里会进行persister snapshot。

    如果scorch没有暂停,首先处理内存segment的merge,否则直接处理snapshot,即persistSnapshotDirect().

    先看内存segment merge

    首先找出所有的内存segment(segmentBase),如果数量大于默认的merge门限(2)触发merge segmentbase

    如上图,这里会open一个新的zap文件,把merge的结果写入这个文件

    如下图,然后重新打开这个segment文件,创建一个merge任务添加到merge任务队列中等待merge完成


    Segment file合并

    首先看看scorch是如何处理的merge segment任务的

    Main Loop循环干的事情太多了,并且是串行的,这也客观上导致了写的性能下降。

    如上图,这里主要是处理delete docs。

    如上图,这里主要是把暂时还不需要merge 的segment都copy到新的segment snapshot。

    如上图,完成新的segment snapshot的构建。

    Scorch还有一个后台任务专门生成segment merge任务

    它只负责已经持久化的segment的merge任务生成。

    Merge完成后写入merges队列等待scorch将segment的快照信息写入boltdb,这样下次重启可以恢复最新的segment snapshot。

    Search支持

    Scorch的倒排索引存储在FST结构的字典树中,同时bleve封装了索引接口,这部分逻辑比较简单,核心就是FST,postList。

    总结

    scorch的优点在于实时读写以及比较优秀的search性能,但是缺点就是写性能很差,主要的原因在我们解析源码的时候也基本都提及了,核心就是segment太琐碎,一次写入会生成一个segment,导致后续merge的时候频繁的copy。不过我们也看到存在很大的优化空间,毕竟scorch给我们提供了基本的几乎文件的索引存储引擎,我们在工程层面上窥看了这种引擎的实现逻辑和技巧以及注意事项,值得学习和借鉴。

    相关文章

      网友评论

        本文标题:Bleve scorch索引引擎源码解析

        本文链接:https://www.haomeiwen.com/subject/ptnegftx.html