Skip to content

Shrink原理分析

索引分片数量一般在模板中统一定义,在数据规模比较大的索引中,索引分片数一般也大一些,同时按天 生成新的索引,使用别名关联。但是,并非每天的索引数据量都很 大,小数据量的索引同样有较大的分片数。在 ES 中,主节点管理分 片是很大的工作量,降低集群整体分片数量可以减少recovery时间, 减小集群状态的大小。因此,可以使用Shrink API缩小索引分片数。 当索引缩小完成后,源索引可以删除。

Shrink API是ES 5.0之后提供的新功能,其可以缩小主分片数 量。但其并不对源索引直接进行缩小操作,而是使用与源索引相同的 配置创建一个新索引,仅降低分片数。由于添加新文档时使用对分片 数量取余获取目的分片的关系,新索引的主分片数必须是源索引主分 片数的因数。例如,8个分片可以缩小到4、2、1个分片。如果源索引 的分片数为素数,则目标索引的分片数只能为1。

准备源索引

创建索引:my_source_index,包括5个主分片和1个副分片,并写入几条测试数据

通过下面的命令,将索引标记为只读,且所有分片副本都迁移到名为node-idea的节点上。注意,“所有分片副本”不指索引的全部分片,无论主分片还是副 分片,任意一个就可以。分配器也不允许将主副分片分配到同一节点。

选项index.blocks.write设置为true来禁止对索引的写操作。但 索引的metadata可以正常写。

缩小索引

待分片迁移完毕,我们就可以执行执行Shrink操作了:

以上代码将创建含有一个主分片和一个副分片的目的索引 my_target_index。

Shrink的工作原理

引用官方手册对Shrink工作过程的描述:

  • 以相同配置创建目标索引,但是降低主分片数量。
  • 从源索引的Lucene分段创建硬链接到目的索引。如果系统不支 持硬链接,那么索引的所有分段都将复制到新索引,将会花费大量时 间。
  • 对目标索引执行恢复操作,就像一个关闭的索引重新打开时一 样。

创建新索引

使用旧索引的配置创建新索引,只是减少主分片的数量,所有副 本都迁移到同一个节点。显然,创建硬链接时,源文件和目标文件必须在同一台主机。

创建硬链接

从源索引到目的索引创建硬链接。如果操作系统不支持硬链接, 则复制Lucene分段。

为什么一定要硬链接,不使用软链接? Linux的文件系统由两部分组成(实际上任何文件系统的基本概念 都相似):inode和block。block用于存储用户数据,inode用于记录 元数据,系统通过inode定位唯一的文件。

  • 硬链接:文件有相同的inode和block。
  • 软链接:文件有独立的inode和block,block内容为目的文件路 径名。

那么为什么一定要硬链接过去呢?从本质上来说,我们需要保证 Shrink之后,源索引和目的索引是完全独立的,读写和删除都不应该 互相影响。如果软链接过去,删除源索引,则目的索引的数据也会被 删除,硬链接则不会。满足下面条件时操作系统才真正删除文件:

文件被打开的fd数量为0且硬链接数量为0。 使用硬链接,删除源索引,只是将文件的硬链接数量减1,删除源 索引和目的索引中的任何一个,都不影响另一个正常读写。

由于使用了硬链接,也因为硬链接的特性带来一些限制:不能交 叉文件系统或分区进行硬链接的创建,因为不同分区和文件系统有自 己的inode

不过,既然都是链接,Shrink 完成后,修改源索引,目的索引会 变吗?答案是不会。虽然链接到了源分段,Shrink 期间索引只读,目 标索引能看到的只有源索引的当前数据,Shrink 完成后,由于 Lucene中分段的不变性,“write once”机制保证每个文件都不会被更 新。源索引新写入的数据随着refresh会生成新分段,而新分段没有链 接,在目标索引中是看不到的。如果源索引进行merge,对源分段执 行删除时,只是硬链接数量减1,目标索引仍然不受影响。因此, Shrink完毕后最终的效果就是,两个索引的数据看起来是完全独立 的。

经过链接过程之后,主分片已经就绪,副分片还是空的,通过 recovery将主分片数据复制到副分片。

硬链接过程源码分析

硬链接过程在目标索引 my_target_index 的恢复流程中,入口 为 IndexShard#startRecovery,有下列几种类型的recovery:

· EXISTING_STORE, 主分片从translog恢复;
· PEER, 副分片从主分片远程拉取;
· SNAPSHOT, 从快照中恢复;
· LOCAL_SHARDS, 从同一个节点的其他分片恢复Shrink使用这种恢复类型。

shrink index 时 的 恢 复 类 型 为 LOCAL_SHARDS , 执 行 storeRecovery.recoverFromLocalShards。在addIndices中,调 用 Lucene 中 的 org.apache.lucene.store.HardlinkCopyDirectoryWrapper 实 现 硬链接。

addIndices将整个源索引的全部shard链接到目标路径: addIndices ( RecoveryState.Index indexRecoveryStats, Directory target, Directory... sources)

Released under the MIT License.