lucene索引的新设计:DWPT,充分利用系统资源

翻译原文:[url]http://blog.jteam.nl/2011/04/01/gimme-all-resources-you-have-i-can-use-them/[/url]
注:本文属个人爱好和英语学习,很多地方翻译的不好,如果需要了解真实内容,请阅读原文。

ps:lucene4.0的并发索引号称提高了265%的写速度,对系统资源的利用也很充分,下面这篇文章主要讲并发写的一个实现原理以及测试结果对比。


[b]在使用Apache Lucene时利用所有的IO和CPU并发来进行索引[/b]

去年lucene发布了很大数量的一些改进,比如提升100倍的[url="http://blog.mikemccandless.com/2011/03/lucenes-fuzzyquery-is-100-times-faster.html"]FuzzyQueries[/url]、[url="http://blog.mikemccandless.com/2010/12/using-finite-state-transducers-in.html"]新的词(term)字典的实现[/url]、[url="http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html"]提高了段(segment)的合并[/url]还有著名的[url="http://blog.mikemccandless.com/2010/10/fun-with-flexible-indexing.html"]灵活索引(Flexible-indexing)API[/url]。最近我开始了另一个工作[url="https://issues.apache.org/jira/browse/LUCENE-2324"]DocumentsWriterPerThread[/url],这对[color=gray]IndexWriter[/color]做了一个较大的重构:索引的性能不再因用户的并发交互而有影响。下面作下简单的介绍:

lucene在索引时,会先构建一个内存的索引,然后再flush到持久化存储中。在内存内部,会有多个小的段(segment),在需要flush的时候,才会合并到一起;这些小的段,可以并行的提供索引服务(即并发)。[color=gray]IndexWrite[/color]使用[color=gray]DocumentsWriter[/color]将索引数据通过一个私有线程写入到段中。见下图:
[img]http://dl.iteye.com/upload/attachment/480664/bddcc998-ccf2-3285-9f90-7f4b534a5d3f.png[/img]
这个模式允许CPU并发执行;但是,当需要将内存中的段flush(通过一个抽象的java文件接口)到硬盘中时,并发的方式就行不通了。当lucene将段写入硬盘时,我们需要停掉所有的线程并一直等到flush线程处理结束。这个实现在lucene3.0里是stop-the-world模式,用来防止索引线程在flush的时候作处理的;但是在较慢的IO系统或者大数据量的索引时,这个限制将成为严重的瓶颈。

[color=gray]DocumentsWriterPerThread(DWPT)[/color]的重构,当前在该[url="http://svn.apache.org/repos/asf/lucene/dev/branches/realtime_search/"]分支[/url]上开发;旨在尝试删除这个限制来让CPU和IO都到达并发索引的目的。替代合并内存数据然后写入到一个单独段的方式,改为每个DWPT将每个段写入自有的段中。这种方式允许我们并发的索引数据而不受到影响:
[img]http://dl.iteye.com/upload/attachment/480691/bb6a11ec-5715-3fc1-a6a0-5c6bae12b1bd.png[/img]

这个想法最初是由Michael Busch在实时搜索中提出并在2010.6提交了分支。我最近跟Mike McCandless一起添加了一个[url="https://issues.apache.org/jira/browse/LUCENE-2573"]missing pieces[/url]来开始基准测试并最终将它合并到了主干上。一周前我提交了一个新的[color=gray]FlushPolicy[/color]用来控制DWPT如何flush段到硬盘中。目的是控制[color=gray]DocumentsWriter[/color] 何时需要flush;如果DWPT必须flush [color=gray]DocumentsWriter[/color]的交换数据,则会使用一个新的DWPT并且开始刷新段。

对于Lucene的默认策略[color=gray]FlushPolicy[/color],我们只标记最大数据来写入,比如活跃的索引大小超出了RAMbuffer 大小时,将它移出活跃索引区,并准备flush。

使用这个模式我们保证会有足够的DWPT可用,即使是在写硬盘时也不会被阻塞。看起来很爽,下面来看一下我们的测试数据吧!

[b]Benchmarking Lucene Indexing[/b]
围绕lucene我们使用了一个apache的扩展工具名叫[url="http://code.google.com/a/apache-extras.org/p/luceneutil/"]luceneUtil[/url]来做性能测试以确保我们的修改对查询的性能并没有任何的负面影响。测试中我添加了一些统计信息,比如吞吐率、flush的团吐量等来展示DWPT。

我们照例使用维基英文xml文档来导出一个21G未压缩的文本文件。然后使用lucene的主干分支中的Realtimebranch作为本次的竞争者。我拿出1千万的文档数进行索引,机器配置为2*6 core XeonBox、24GRAM、500G Hitachi HDD,索引这1千万的文档,用了13分40秒,很好。

[img]http://dl.iteye.com/upload/attachment/481904/61030b4c-0fdc-3b2f-b3bf-d401e58e1c18.png[/img]
上图中,在50s-200s中,有一个很好的性能吞吐率,每秒大概处理40K的文档;但是在刷新到硬盘中时,没有做任何处理;刷新会占用一些时间并且使系统IO处于繁忙状态。我知道trunk上的这次测试有什么问题;看图就知道,其实它可以更快。问题是如何能更好的利用系统的资源。
使用DWPT测试只用了6分15秒,跟trunk比,降低了不只50%!
[img]http://dl.iteye.com/upload/attachment/481947/d929da24-ec33-3fdb-b2c3-eedcd70d8d2b.png[/img]
非常惊人的结果,多线程在后台不断地添加文档数据到索引中。峰值较trunk比稍微有些下降,这是因为在后台flush索引时,会有一些的线程切换。

[img]http://dl.iteye.com/upload/attachment/482078/93d62e26-76ab-3bb5-85ae-8c1b5e6c77d0.png[/img]
通过该图可以看出,在并发flush时,系统IO的利用率很高。DWPT在并发flush数据时会有一些小的重叠,这让磁盘不能一直刷新某一块;这也解释了图4中的问题,如果多线程刷新时,有IO重叠,则不会继续处理,进而影响吞吐量。

总体来说,DWPT还是很惊人的,我们甚至不需要进行优化。我很好奇如果这个提升跟hadoop结合到一起(使用[url="https://issues.apache.org/jira/browse/LUCENE-2373"]AppendingCodec[/url]直接写入到HDFS)会怎样?并发索引做了一个很好的改进。请继续关注。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值