#Scaling Lucene#
怎样在Lucene之上构建一个分布式、高度伸缩、接近实时的搜索引擎呢?
+ building blocks
+ partitioning 分区策略最佳的将lucene的索引文档分割到多个分布式的分片中去
+ replication 分区复制方式保证系统的高可用性以及提高搜索的吞吐
+ transaction log 事务日志保证数据一致性
##Building Blocks##
当我们要构建一个分布式接近实时的搜索引擎,并且要让lucene可伸缩扩展,必须首先知道lucene的关键概念一个他们于我们要达成目标的一些局限性。
###Directory###
Lucene Directory是一个抽象的文件系统的接口,用来允许你读写文件,不管lucene的索引是存放在内存中还是物理磁盘上,他都是通过lucene的Directory抽象层来访问和维护的。
###IndexWriter###
IndexWriter用来添加、删除、更新lucene里面的索引文档。这些操作是在内存中完成以保证更好的性能,但是如果要保证这些操作的持久化,这些操作是需要flush到磁盘的。并且,flush操作或者显失的commit提交开销都是很大的,因为这些操作通常需要处理很多的文件,而处理这些文件有涉及到大量的磁盘IO。
此外,每次只能有一个IndexWriter对象来对一个索引目录进行索引操作,并且创建这个对象开销很大,所以次序尽可能去重用这个对象。
###Index Segmentgs###
lucene索引被分解为很多段(segments)。每个索引段实际上时一个功能完整的lucene索引,一旦一个索引段创建完成,他将是不可变的,并且不能删除段里面的索引文档。commit提交操作用来往索引段里面添加一个新段。lucene内部会来对这段进行合并,所以我们必须要有策略来控制这些合并。(MergePolisy, MergeScheuler, … etc)。Because segments need to be kept at bay they are being merged continuously by internal Lucene processes (MergePolisy, MergeScheuler, … etc).
因为这些段是不可变的,所以可以用来作缓存(caching)是一个很好的选择,你可以加载所有的term词条并且创建一个跳跃列表(skip lists),或者用来构造FieldCache,如果段没有变化,你就不需要重新加载。
###IndexReader###
IndexReader用来执行搜索索引。这个对象通过IndexWriter来提供,并且创建代价也是比较高。一旦IndexReader打开之后,他就不能够发现打开之后的索引变化,如果要知道这些由IndexWriter产生的索引变化,除非刷新IndexReader对象(当然前提需要flush操作)。搜索操作在内部其实是按段来进行的(每次一个段)。
###Near Real-Time Search###
获取一个新的IndexReader开销很大,所以也是我们不能每次已有索引操作就真得去获取一个新的IndexReader,你可以隔一段时间去刷新以下,比如每隔一秒钟等。这也是在这里称之为接近实时(near real-time)的原因。
###可能用来伸缩Lucene的途径(Possible approach to Scale Lucene)###
####Distributed Directory####
其中一种途径用来伸缩Lucene就是使用分布式文件系统,大文件会被拆分成chunks块并且会保存到分布式文件系统(比如Coherence、Terracata、Gigapaces or Infinispan等等)。这样,IndexWriter和IndexReader都是工作在一个自定义的Directory分布式实现上,每个操作后面其实是分不了很多个节点,每个节点上面存储了索引文件的一部分。
但是这种方案会有一些问题:
+ 产生密集的网络流量。
+ 大的索引必然会时IndexReader变的无法分布式
+ 索引操作也会变得非常困难,因为只有一个单一的IndexWriter能够写索引。
##Partitioning##
有两种通过将数据分区方式来scale搜索引擎:基于文档(Document based partitioning)和基于词条(Term based partitioning),ES使用的基于文档的分区方式。
###基于文档的分区###
每一个文档只存在一个分区,每个分区持有整个文档集的一个子集,分区时一个功能完整的索引。
###基于词条的分区###
##Replication##
分布式系统的另外一个方面就是复制(replication)了,通过复制可以得到2个主要的好处:
+ High Availability (HA高可用性)
+ scalability (可伸缩性)
一般有两种方式来实现复制:Push Replication (推模式)和Pull Replication(拉模式)。ES使用的是推模式。
###Push Replication###
###Pull Replication###
##Transaction Log##
如前面所述,索引提交(commit)的开销是在太大,但是我们由必须通过提交操作来保证数据被可靠的持久化,如果拥有数据的节点突然崩溃的话,那么最后一个提交操作之后产生的数据操作将会丢失。
###数据可靠性(Data Persistency)###
####Shared gateway snapshot(快照)####
####peer shared recovery(分片恢复)####
####shared “Hot”relocation(分片热迁移)####
怎样在Lucene之上构建一个分布式、高度伸缩、接近实时的搜索引擎呢?
+ building blocks
+ partitioning 分区策略最佳的将lucene的索引文档分割到多个分布式的分片中去
+ replication 分区复制方式保证系统的高可用性以及提高搜索的吞吐
+ transaction log 事务日志保证数据一致性
##Building Blocks##
当我们要构建一个分布式接近实时的搜索引擎,并且要让lucene可伸缩扩展,必须首先知道lucene的关键概念一个他们于我们要达成目标的一些局限性。
###Directory###
Lucene Directory是一个抽象的文件系统的接口,用来允许你读写文件,不管lucene的索引是存放在内存中还是物理磁盘上,他都是通过lucene的Directory抽象层来访问和维护的。
###IndexWriter###
IndexWriter用来添加、删除、更新lucene里面的索引文档。这些操作是在内存中完成以保证更好的性能,但是如果要保证这些操作的持久化,这些操作是需要flush到磁盘的。并且,flush操作或者显失的commit提交开销都是很大的,因为这些操作通常需要处理很多的文件,而处理这些文件有涉及到大量的磁盘IO。
此外,每次只能有一个IndexWriter对象来对一个索引目录进行索引操作,并且创建这个对象开销很大,所以次序尽可能去重用这个对象。
###Index Segmentgs###
lucene索引被分解为很多段(segments)。每个索引段实际上时一个功能完整的lucene索引,一旦一个索引段创建完成,他将是不可变的,并且不能删除段里面的索引文档。commit提交操作用来往索引段里面添加一个新段。lucene内部会来对这段进行合并,所以我们必须要有策略来控制这些合并。(MergePolisy, MergeScheuler, … etc)。Because segments need to be kept at bay they are being merged continuously by internal Lucene processes (MergePolisy, MergeScheuler, … etc).
因为这些段是不可变的,所以可以用来作缓存(caching)是一个很好的选择,你可以加载所有的term词条并且创建一个跳跃列表(skip lists),或者用来构造FieldCache,如果段没有变化,你就不需要重新加载。
###IndexReader###
IndexReader用来执行搜索索引。这个对象通过IndexWriter来提供,并且创建代价也是比较高。一旦IndexReader打开之后,他就不能够发现打开之后的索引变化,如果要知道这些由IndexWriter产生的索引变化,除非刷新IndexReader对象(当然前提需要flush操作)。搜索操作在内部其实是按段来进行的(每次一个段)。
###Near Real-Time Search###
获取一个新的IndexReader开销很大,所以也是我们不能每次已有索引操作就真得去获取一个新的IndexReader,你可以隔一段时间去刷新以下,比如每隔一秒钟等。这也是在这里称之为接近实时(near real-time)的原因。
###可能用来伸缩Lucene的途径(Possible approach to Scale Lucene)###
####Distributed Directory####
其中一种途径用来伸缩Lucene就是使用分布式文件系统,大文件会被拆分成chunks块并且会保存到分布式文件系统(比如Coherence、Terracata、Gigapaces or Infinispan等等)。这样,IndexWriter和IndexReader都是工作在一个自定义的Directory分布式实现上,每个操作后面其实是分不了很多个节点,每个节点上面存储了索引文件的一部分。
但是这种方案会有一些问题:
+ 产生密集的网络流量。
+ 大的索引必然会时IndexReader变的无法分布式
+ 索引操作也会变得非常困难,因为只有一个单一的IndexWriter能够写索引。
##Partitioning##
有两种通过将数据分区方式来scale搜索引擎:基于文档(Document based partitioning)和基于词条(Term based partitioning),ES使用的基于文档的分区方式。
###基于文档的分区###
每一个文档只存在一个分区,每个分区持有整个文档集的一个子集,分区时一个功能完整的索引。
###基于词条的分区###
##Replication##
分布式系统的另外一个方面就是复制(replication)了,通过复制可以得到2个主要的好处:
+ High Availability (HA高可用性)
+ scalability (可伸缩性)
一般有两种方式来实现复制:Push Replication (推模式)和Pull Replication(拉模式)。ES使用的是推模式。
###Push Replication###
###Pull Replication###
##Transaction Log##
如前面所述,索引提交(commit)的开销是在太大,但是我们由必须通过提交操作来保证数据被可靠的持久化,如果拥有数据的节点突然崩溃的话,那么最后一个提交操作之后产生的数据操作将会丢失。
###数据可靠性(Data Persistency)###
####Shared gateway snapshot(快照)####
####peer shared recovery(分片恢复)####
####shared “Hot”relocation(分片热迁移)####