[Solr Wiki] New SolrCloud Design

http://wiki.apache.org/solr/NewSolrCloudDesign

NewSolrCloudDesign (last edited 2012-05-1919:45:07 by Mark Miller)

注:这个wiki页面更新于Solr4.0发布之前,现在 (2014) Solr已经发布到4.10.1版本了,这份文档能帮助理解最初SolrCloud的设计思路。


新的SolrCloud设计思想

这只是一些想法的草稿记录,并不作为– 这个页面不描述SolrCloud被实现的设计,它的存在出于历史的原因。

 

1. 什么是SolrCloud?

SolrCloud对已有的Solr来说,是对管理和操作作为云搜索服务的Solr的一大改进。

 

2.术语表(Glossary)

Cluster:Cluster是作为独立单位管理的一组Solr节点。整个集群必须有唯一的schema和solrconfig

Node:一个运行Solr的JVM实例

Partition:一个partition是整个文档集合的一个子集。一个partition被以这样的方式创建,它的所有文档可以被包含在一个单独的索引中

Shard:一个partition需要在多个节点中存储,由replication因子(factor)来指定。所有这些节点共同构成一个shard. 一个节点可能是多个shards的一部分

Leader:每个Shard有一个节点确认为它的leader.所有属于一个partition的文档的写操作应该被路由到leader

Replication Factor:由集群维护的文档的最小复制数

Transaction Log:每个节点维护的只可追加的写操作日志

Partition Version:由每个Shard维护的一个计数器,在每个写操作时增加,并且发送到同等节点

Cluster Lock:一个全局锁,必须获取才能改变range->partition或partition->node的映射

3. 指导原则(Guiding Principles)

。任何操作都可以在集群的任何节点上调用

。没有不可恢复的单点故障

。集群应该是可伸缩的

。写操作必须从不会丢失,即确保持久性

。写的顺序应该被保持

。如果两个客户端同时发送文档”A”到两个不同的replicas,其中一个总是”赢”过其他所有replicas

。集群配置应该被集中管理,并且可以通过集群中的任何节点更新。除了本地的值,如端口、索引/日志存放位置,不应要求按节点配置

。读的自动故障恢复

。写的自动故障恢复

。在节点故障事件时,自动地获得repliaction factor.

4. Zookeeper

Zookeeper集群作为以下用途:

。Solr集群的集中式配置存储

。需要分布式同步的操作的协调器

。集群拓扑的记录系统

5.分区(Partitioning)

集群配置了一个固定的max_hash_value(设置为一个相当大的值,如1000)’N’. 每个文档的hash计算为:

hash = hash_function(doc.getKey()) % N

hash值按范围(range)分配到各partions,并存储到Zookeeper.例如我们有一个range到partition的映射如下

range  : partition
------  ----------
0 - 99 : 1
100-199: 2
200-299: 3

 

这个hash值被作为一个索引字段添加并且是不可变的,这也以用在索引split中。

 

Hash函数是可插入的。它可以接收一个文档并返回一致的正整数hash值。系统提供一个默认的hash函数,使用一个配置的、必要且不可变域(默认是unique_key域)的值来计算hash值。

 

 

使用全部的hash范围 (Using full hash range)

或者,不需要任何max_hash_value – 因为不管怎样每个shard将有一个范围的hash值,可以使用全部的32位hash值。避免可配置的max_hash_value使客户端更容易得到相互之间的hash值。例如,在一个邮件搜索应用中,可能如下构造hashcode:

(hash(user_id)<<24) |(hash(message_id)>>>8)

 

Hashcode的高8位从user_id生成,确保了任何的用户邮件都在集群的相同的第256部分(注:被256整除)。在搜索时,这个信息只能用于搜索集群的那一部分。

 

为了表达超出的范围(跨越最大值和最小值)我们可能也会将hash空间视为一个环(类似于consistent hasing)。

 

shard命名 (shard naming)

当根据hash code来做分区(partitioning)时,与其单独维护一个shard到hash范围的映射,不如让shard名成为hash范围(即,shard”1-1000”将包含hashcode为1到1000的文档集)。

 

当前solr-core的命名约定是它匹配集合名(假定solr服务中一个集合对应一个core)。当一个集合有多个cores时,我们还需要一个好的命名模式。

 

6. Shard分配 (Shard Assignment)

只有当一个节点获得Zookeeper中的Cluster Lock时,才能改变node -> partition的映射。因此当一个节点加入进来,它首先尝试去获取cluster lock,等到获得锁然后确定它可以订阅到哪一个partition.

节点到shard的分配 (Node to a shard assignment)

一个尝试发现新节点的节点应该先获得cluster lock。shard的leader首先被确定。在所有可用的节点中,拥有最小shard数目的节点被选择。如果有多个,最小shard数的leader被选择。如果还有多个,随机选择一个节点。

 

7.启动引导 (Boot Strapping)

集群启动

一个节点启动时指向一个Zookeeper主机和端口。集群中的第一个节点可能以集群配置和集群的schema/config文件启动。第一个节点将上传配置到Zookeeper并且引导集群启动。集群被视为”引导”(”bootstrap”)状态,此状态下,node -> partition 映射不被计算并且集群不接受任何读/写请求,除了clusteradmin命令。

 

在初始节点集启动以后,管理员发出一个clusteradmin命令(TBD description). 这个命令接收一个整型”partitions”参数,并按下面的步骤进行:

1.获得Cluster Lock

2.分配”partitions”数

3.为每个partition获得nodes

4.更新ZooKeeper中的node->partition映射。

5.释放Cluster Lock

6.通知所有节点强制从ZooKeeper更新它们自己的node->partition映射。

 

节点启动

节点启动时,检查ZooKeeper看它是否是已经存在的shard的一个部分。如果ZooKeeper没有关于这个节点的记录或这个节点不是任何shard的一部分,按<新节点>步骤启动,否则按<节点重启>的步骤。

新节点

新节点是从未加入过集群的节点,被新加入以增加集群的容量。

 

如果”auto_add_new_nodes”这个集群属性是false,新节点在ZooKeeper中注册为”idle”,并且等到其他节点唤醒它加入。否则,如下处理:

 

1. 获取Cluster Lock

2. 选择一个合适的源组(node,partition):

2.1 扫描可用的partitions列表,找到节点数少于”replication_factor”的partition. 如果找到多个,最少节点的nodes被选择。依然有多个,则随机选择。

2.2 如果所有的partitions都有足够的replicas,扫描节点,找到包含最多partitions的节点。如果有多个,有最多文档的节点被选择。如果还有多个,选择随机partition上的随机节点。

2.3 如果为当前node选择(node,partition)组,会降低集群的最大数目的partition:node比率,此选择被返回。否则,没有选择并且算法终止。

2.4 在ZooKeeper中更新node->partition映射

3. 这个节点在ZooKeeper中的状态被更新为”recovery”

4. 释放Cluster Lock

5. 被选择partition的节点leader被初始化为“recovery”

6. 在recovery完成以后,ClusterLock被获得

7. 在ZooKeeper中的源(node,partition)被移除

8. Cluster Lock被释放

9. 源节点被指示强制从ZooKeeper更新node->parition

10. Goto 第1步

 

节点重启

一个节点重启,意味着下列事件之一:

。JVM崩溃并且被手动或自动重启

。节点在临时网络中断时,在一段时间内,或不能访问ZooKeeper(被认为dead),或不能接收来自Leader的更新,节点在节点失败时重启。

。一个写操作的生命周期在这个场景意味着网络的移除

。一个硬件失败或维护窗口导致节点从集群移除,并且节点又被启动来重新加入集群。

 

节点读取它所在的partitions,对每个partition,分别从每个partition的leader启动一个recovery处理。然后,节点按新节点启动步骤,而不检查auto_add_new_nodes属性。这确保了集群从由客户端的写操作带来的不平衡状态中以Solr标准更新格式恢复。一个写操作可以被发送到集群的任何节点。节点使用hash_function,和rang-partition映射来定位文档属于哪个partition。通过一个ZooKeeper查询定位到shard的leader,并且将操作传递过去。对SolrJ的改进可能使它能直接发送到leader。

 

Leader节点为操作分配一个Partition版本,并且将操作写到事务日志,并且将document + version + hash传递到属于这个shard的其他节点。这些节点将document+hash写到索引,并且将操作记录到事务日志。如果至少min_writes数目的节点返回”OK”, leader节点返回”OK”.集群属性的min_writes可以被请求中指定的参数覆盖。

 

云模式不会提供任何显示commit或rollback操作。Commits操作由leader在间隔时间(commit_within)通过auto-commits来管理,并且在shard所有成员上触发一个commit.节点最近的可用版本在commit时被记录。

 

8.事务日志(Transaction Log)

。事务日志记录了commits之间在索引上的所有操作

。每个commit发起一个新的事务日志,因为一个commit确保之前操作的持久性

。同步是可调的,例如flush vs fsync 默认下可以进行JVM崩溃保护,但不能断电保护并且更快

9.恢复(Recovery)

恢复在下列情形触发:

。启动引导

。Partition切分

。Cluster负载均衡

 

节点从设置状态为’recovering’开始。在这期间,节点不会接收任何读请求,但会接收所有应该被写入独立事务日志的新的写请求。节点查看索引版本,并且从’leader’查询最近的partition版本。Leader响应并返回需要在节点与shard内其他节点同步前进行的操作的集合。

 

这可能涉及到根据节点位置先拷贝索引并重演事务日志,这是最新的技术。如果索引拷贝被请求了,索引文件先被复制到本地索引,然后按事务日志(记录的操作)重新操作。事务日志重演不过是一系列常规的写请求。在这期间,节点可能已经积累了一些新的应对索引进行的写操作。在到达最近的commit点的时刻,它使自身成为’ready’。在这个点,节点可以处理读请求。

 

处理节点失败

节点之间或节点和ZooKeeper之间可能存在网络临时中断。集群在均衡数据之前应该等待一段时间。

Leader节点失败

任何shard的leader失败,其他节点成员会发起一个leader选举处理。在新leader选举出来之前,这个partition的写操作不被接受。然后按非leader节点失败步骤处理。

非leader节点失败

Leader在确定一个新节点是shard的一部分之前会等待min_reaction_time的时间。Leader获得ClusterLock,并且使用node-shard分配算法来确定一个节点为本shard的新成员。Node->partition映射在ZooKeeper中被更新,再释放cluster lock. 新节点被强制从ZooKeeper更新node->partition映射表。

10.切分分区(Splitting partitions)

分区切分可以由显示的cluster admin命令或由Solr的切分策略自动地进行。一个显示的切分命令可能给出指定分区用于切分。

 

假定hash范围100-199的分区’X’,被确定为分成X(100-149)和一个新partition Y(150,199). X的leader会在ZooKeeper中记录此切分行为,及X和Y要求的范围值。这个行为或新分区的存在不会通知到任何节点。

 

1. X的leader,获取集群锁并且确认可以被分配到Y的节点(算法待定),并告知它们新的分区并且更新partition->node映射。X的leader等待节点回应,一旦检查到新分区已准备好接收命令,进行如下处理:

2. X的leader在切分完成前挂起所有commits

3. X的leader在最近commit点(称为版本V)打开IndexReader,并通知peer节点做同样的事情

4. X的leader开始传输版本V后hash范围为150-199的事务日志到Y的leader

5. Y的leader仅仅在它的事务日志中记录所有在#2发送的请求,即不在索引上操作

6. X的leader在第2步后打开的IndexReader上发起一个索引切分

7. 第5步创建的索引被发送到Y的leader,并被安装

8. Y的leader通知它的peer节点开始recovery处理. 同时,在索引上开始按事务日志操作

a. 一旦Y分区的所有成员到达版本V(进行如下操作):

b. Y的leader通知X的leader在#2创建的Reader上准备一个FilterIndexReader,它包含所有属于100-149范围的文档。

c. 一旦X的leader确认完成了#8a的请求,Y的leader获取集群锁并修改range->partition映射,以开始接受来自整个集群的search/write请求

d. Y的leader要求X的leader开始使用#8a创建的FilteredIndexReader用于搜索请求

e. Y的leader要求X的leader强制从ZooKeeper更新range->partition映射。此处,确保#3发起的事务日志传输将停止

9. X的leader将删除所有hash值不属于它的partition的文档,commit并在最近的commit点打开searcher

10. 此时,分区被认为已完成,并且X的leader根据commit_within参数重新开始commit。

 

注意:

。被切分的分区在切分操作完成前,不被设置commit_within参数

。在#8b开始到#8c结束之间进行的分布式搜索操作,可能返回不一致的结果,即返回的搜索结果数可能出错

11.集群均衡(Cluster Re-balancing)

集群可以通过一个显示的集群管理命令被重新平衡。

TBD (To Be Determined )

12.监控(Monitoring)

TBD

13.配置

solr_cluster.properties

这是常规Solr配置外的属性集合,可适用于集群所有节点:

replication_factor:集群一个文档的复制数

min_writes:一个写操作被为成功前的最少(节点)写成功数。这可能基于每次的写操作被覆盖

commit_within :写操作可被搜索的最长时间

hash_function :计算给定文档hash值的算法

max_hash_value : hash_function输出的最大值。理论上,这也是集群可以拥有的最大partitions数

min_reaction_time :一个节点加入和离开后,开始重新分配/切分的时间(秒)

min_replica_for_reaction :如果replica节点数小于这个阀值,即便min_reaction_time时间未到也会触发切分操作

auto_add_new_nodes :布尔标识。True,新节点自动作为读复制加入已经存在的分区,否则,除非集群需要新节点状态为idle

14.集群管理命令

所有集群管理命令在所有节点上以给定path运行(如/cluster_admin). 所有节点都能接收相同的命令并且进行相同的行为。这里是所有用户可以用来管理集群的公开命令:

init_cluster :(params:partition) 这个命令在初始节点集启动后被发出。在这条命令被发出前,集群不会接收任何读/写命令

split_partition : (params:partition 可选) 这个分区被切分成两半。如果partition参数未提供,有最多文档的partition被候选

add_idle_nodes :如果auto_add_new_nodes=false这个参数可用,触发所有’idle’的节点加入到集群

move_partition : (params: partition, from, to).将partition从一个节点到另一个节点

command_status :(params: completion_id 可选).上面所有的命令都是异步的并且返回一个completion_id.此命令可用于查看指定或全部当前运行命令的状态

status :(params:partition 可选) 显示所有或各partition的如下信息:

。leadernode

。nodeslist

。doccount

。averagereads/sec

。averagewrites/sec

。averagetime/read

。averagetime/write

15.从Solr迁移到SolrCloud

当迁移到cloud后少数功能可能变得多余或不被支持。我们应继续支持包含所有已存功能的非cloud版本。

。Replication 这个功能不再需要了

。CoreAdmin 命令,对cores的显示操作不被允许。因此cores可能存在在内部并且被隐式管理

。Multiple schema 支持?我们应该从1.0版本简单的删除?

。solr.xml. 在cloud模式还有任何必要吗?

16.集群锁的代替(Alternative to a Cluster Lock)

拥有一个通过leader选择建立的协调节点(coordinator node)可能会更简单(我们避免使用Master术语,因为它跟传统的索引复制有关联)。按这种模式允许未来更多的灵活性:”信任”ZooKeeper的状态并且节点根据状态的改变做出反应(如允许一个外部的管理工具直接改变ZooKeeper状态来控制集群)。有一个协作器(对比每次都获得锁)也更具可扩展性。而集群锁只在特定环境下使用的混合模式也值得考虑。

 

17.单节点最简单的使用情况

我们应该能很容易的启动一个单节点并且开始索引文档。在之后的一个时间点,能启动第二个节点并使它加入集群。

1. 启动一个单节点,上传它的配置(第一次)到zookeeper,创建并分配节点到shard1

。在缺乏其他信息的情况下创建配置,一个单节点shard系统被认定

2. 索引一些文档。

3. 启动另外一个节点并传入一个参数表明“如果你未被分配,将你自己分配到任何有最少replicas的shard,并启动recovery处理”

。如果可能,避免在同一个主机上进行复制

。此后, kill这个节点并重启动它应能继续原来的角色(只要它能在ZooKeeper中看到自己)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值