replica shard包含有和primary shard同样的数据。如下面两幅图所示,第一幅,master把需要初始化replica shard c0的ClusterState广播到整个集群;第二幅,node2探测到自己被分配了一个新的shard
当replica shard分配完成后,需要理解的很重要的一点是,我们会从primary shard复制所有缺失的数据到replica shard,数据复制完成后,master才会把replica shard的状态标注为”started”,并且向集群中广播一个新的ClusterState。如下面动图所示
场景二、 是时候移动shard了
有时你的集群可能需要在集群内部移动已经存在的shard。这可能会有很多原因
1. 用户配置
这方面最常见的一个例子就是Hot/Warm配置,当数据老化时,会根据Hot/Warm配置把数据移动到访问速度较慢的磁盘上。如下图所示
2. 用户使用命令显式移动shard
用户通过cluster re-route命令来使得elasticsearch将shard从一个地方移到另一个地方
3. 磁盘相关的配置
存在与磁盘使用空间相关的以下两个设置,分配决定器会根据这些设置的阈值来移动shard
- cluster.routing.allocation.disk.watermark.low
- cluster.routing.allocation.disk.watermark.high
超过低水位阈值时,elasticsearch将阻止我们写入新的shard。同样,超过高水位阈值时,elasticsearch会把此节点上shard重新分配到其他节点上,直到当前节点的磁盘占用低于高水位阈值。如下图所示
4. 集群添加节点
可能你的集群已经达到最大容量,于是你添加了一个新的节点,此时elasticsearch会重新平衡(rebalance)整个集群。如下图所示
Shard可能会包含很多G的数据,因此,在集群间移动它们可能产生极大的性能影响。为使这个过程对用户透明,移动shard必须在后台运行。也就是尽可能的降低移动shard对elasticsearch其他方面的影响。为此,引入了一个抑制参数(indices.recovery.max_bytes_per_sec/cluster.routing.allocation.node_concurrent_recoveries) ),以保证移动shard期间依然可以继续向这些shard索引数据。如下图所示
记住:elasticsearch的所有数据都是通过Lucene存储的。Lucene使用被称为segment的一组文件来存储一组倒排索引。给定的tokens/words时,倒排索引结构可以方便的告诉你这些tokens/words包含在哪些文档中,出现在文档中的什么位置。当Lucene索引文档时,文档暂存于内存中的indexing buffer。当indexing buffer满或,elasticsearch发出refresh操作(从而引发lucene flush)时,indexing buffer中的数据就被强制写入被称为segment的倒排索引中。如下图所示
随着我们继续索引文档,我们会用同样的方式创建新的segment。关于segment,一个重要的事情就是segment是不可变的(immutable)。这意味着,一旦写了一个segment,这个segment就永远不会改变了。如果你发出删除或任何改变,这些动作将发生在新的segment上,在新的segment上同样发生合并过程。如下图所示
既然数据是存储在内存的,理论上在数据提交到segment文件之前(译注:即使已写入segment也可能会丢失,因为segment写入filesystem时,只是写入了内存即filesystem cache,只有调用filesystem的fsync后,内容才真正写入了磁盘。而出于性能考虑,filesystem是周期性而不是实时的调用fsync的),数据是有可能丢失的。elasticsearch使用transaction log来缓解这种情况。每当文档索引进Lucene时,文档也会被写入transaction log。如下图所示
Transaction log是顺序写入的,最后一个请求位于文件的末尾。借助transaction log,我们就可以恢复尚未写入Lucene中的文档。elasticsearch的持久化模型如下图所示
生成segment时可能并未执行fsync,此时segment会暂存于filesystem cache内存中,OS会暂缓刷新数据到磁盘。这么作是出于性能原因,因此,必须要把filesystem cache内存中的segment写入到磁盘,同时清空transaction log,这个工作是通过elasticsearch flush来完成的
当发出elasticsearch flush(从而引发lucene commit)命令时,会做两件事情
- 把indexing buffer中的数据写入磁盘,从而生成一个新的segment
- 遍历所有的segment文件,请求filesystem使用fsync将所有segment写入磁盘
执行elasticsearch flush就把内存中所有数据(即indexing buffer中的数据以及filesystem cache内存中的segment),统统写入了磁盘,并且清空了transaction log,这确保我们不会丢失任何数据。对于重新安置(relocation)shard,如果我们捕获并保存一组给定的segment,则我们得到一个时间点一致且数据不可变的数据快照
译注:参考Elasticsearch: 权威指南–>持久化变更了解文档写入过程。梗概总结如下图所示
以下面动图为例,集群想要把node4上的a0移动到node5,于是master标注a0为正在从node4重新安置到node5,node5收到请求后在node5上初始化一个shard。对这个行为,有一个非常重要的事情需要注意,当进行重新平衡时,看起来replica shard正在从node4移动到node5,但事实上,重新安置shard时总是从primary shard复制数据的(即:node1上的a0)
以下面动图为例,我们来演示“把node1上的primary shard重新安置到node5”。记住我们前面所说的两种数据存储机制,transaction log和lucene segment
此例中node5是空节点,node1上有primary shard。全部步骤如下
- master向node5发送了一个modified ClusterState,master要求node5初始化一个新的shard
- node5探测到自己被分配了一个新的shard
- node5向node1(node1上有primary shard)发送请求,请求开始恢复过程
- node1收到node5的请求,然后,node1验证它自己知道node5发送的请求
- node1验证通过,于是在node1上,elasticsearch固定tra