拆分索引 API编辑

将现有索引拆分为具有更多主分片的新索引。

response = client.indices.split(
  index: 'my-index-000001',
  target: 'split-my-index-000001',
  body: {
    settings: {
      'index.number_of_shards' => 2
    }
  }
)
puts response
POST /my-index-000001/_split/split-my-index-000001
{
  "settings": {
    "index.number_of_shards": 2
  }
}

请求编辑

POST /<index>/_split/<target-index>

PUT /<index>/_split/<target-index>

先决条件编辑

  • 如果启用了 Elasticsearch 安全功能,则您必须对该索引具有 manage 索引权限
  • 在拆分索引之前

您可以使用 添加索引块 API 通过以下请求使索引变为只读

PUT /my_source_index/_block/write

无法拆分数据流上的当前写入索引。要拆分当前写入索引,必须先对数据流进行 滚动,以便创建一个新的写入索引,然后才能拆分之前的写入索引。

描述编辑

拆分索引 API 允许您将现有索引拆分为新索引,其中每个原始主分片在新索引中拆分为两个或更多个主分片。

索引可以拆分的次数(以及每个原始分片可以拆分的最大分片数)由 index.number_of_routing_shards 设置决定。路由分片的数量指定了内部用于通过一致性哈希在分片之间分配文档的哈希空间。例如,一个具有 5 个分片的索引,其 number_of_routing_shards 设置为 305 x 2 x 3),可以按 23 的因子进行拆分。换句话说,它可以按如下方式拆分

  • 51030(先按 2 拆分,再按 3 拆分)
  • 51530(先按 3 拆分,再按 2 拆分)
  • 530(按 6 拆分)

index.number_of_routing_shards 是一个 静态索引设置。您只能在索引创建时或在 关闭的索引 上设置 index.number_of_routing_shards

索引创建示例

以下 创建索引 API 创建 my-index-000001 索引,其 index.number_of_routing_shards 设置为 30

response = client.indices.create(
  index: 'my-index-000001',
  body: {
    settings: {
      index: {
        number_of_routing_shards: 30
      }
    }
  }
)
puts response
PUT /my-index-000001
{
  "settings": {
    "index": {
      "number_of_routing_shards": 30
    }
  }
}

index.number_of_routing_shards 设置的默认值取决于原始索引中的主分片数。默认值旨在允许您按 2 的因子进行拆分,最多可达 1024 个分片。但是,必须考虑原始主分片的数量。例如,使用 5 个主分片创建的索引可以拆分为 10、20、40、80、160、320 或最多 640 个分片(通过一次拆分操作或多次拆分操作)。

如果原始索引包含一个主分片(或者多分片索引已 收缩 为一个主分片),则该索引可以拆分为任意数量大于 1 的分片。然后,默认路由分片数的属性将应用于新拆分的索引。

拆分的工作原理编辑

拆分操作

  1. 创建一个新的目标索引,其定义与源索引相同,但具有更多数量的主分片。
  2. 将源索引中的段硬链接到目标索引。(如果文件系统不支持硬链接,则所有段都将复制到新索引中,这是一个更加耗时的过程。)
  3. 在创建低级文件后,再次对所有文档进行哈希处理,以删除属于不同分片的文档。
  4. 恢复目标索引,就像它是一个刚刚重新打开的已关闭索引一样。

为什么 Elasticsearch 不支持增量重新分片?编辑

N 个分片到 N+1 个分片,也称为增量重新分片,确实是许多键值存储所支持的功能。添加一个新的分片并将新数据推送到这个新的分片是不可行的:这可能会成为索引瓶颈,并且根据文档的 _id 确定文档属于哪个分片(这对于获取、删除和更新请求是必要的)将变得相当复杂。这意味着我们需要使用不同的哈希方案重新平衡现有数据。

键值存储有效地做到这一点的最常见方法是使用一致性哈希。当分片数量从 N 增加到 N+1 时,一致性哈希只需要重新定位 1/N 的键。然而,Elasticsearch 的存储单元(分片)是 Lucene 索引。由于其面向搜索的数据结构,获取 Lucene 索引的很大一部分(即使只有 5% 的文档),删除它们并将它们索引到另一个分片,通常比使用键值存储的成本要高得多。当按上述部分所述的乘法因子增加分片数量时,此成本保持在合理的范围内:这允许 Elasticsearch 在本地执行拆分,这反过来又允许在索引级别执行拆分,而不是重新索引需要移动的文档,以及使用硬链接进行高效的文件复制。

对于仅追加数据,可以通过创建一个新索引并将新数据推送到该索引来获得更大的灵活性,同时添加一个涵盖旧索引和新索引的别名以用于读取操作。假设旧索引和新索引分别有 MN 个分片,那么与搜索一个具有 M+N 个分片的索引相比,这样做没有任何开销。

拆分索引编辑

要将 my_source_index 拆分为一个名为 my_target_index 的新索引,请发出以下请求

response = client.indices.split(
  index: 'my_source_index',
  target: 'my_target_index',
  body: {
    settings: {
      'index.number_of_shards' => 2
    }
  }
)
puts response
POST /my_source_index/_split/my_target_index
{
  "settings": {
    "index.number_of_shards": 2
  }
}

一旦目标索引被添加到集群状态,上述请求就会立即返回,而不会等待拆分操作开始。

只有满足以下要求的索引才能进行拆分

  • 目标索引必须不存在
  • 源索引必须比目标索引具有更少的主分片。
  • 目标索引中的主分片数必须是源索引中主分片数的倍数。
  • 处理拆分过程的节点必须有足够的可用磁盘空间来容纳现有索引的第二个副本。

_split API 类似于 创建索引 API,并接受目标索引的 settingsaliases 参数

response = client.indices.split(
  index: 'my_source_index',
  target: 'my_target_index',
  body: {
    settings: {
      'index.number_of_shards' => 5
    },
    aliases: {
      my_search_indices: {}
    }
  }
)
puts response
POST /my_source_index/_split/my_target_index
{
  "settings": {
    "index.number_of_shards": 5 
  },
  "aliases": {
    "my_search_indices": {}
  }
}

目标索引中的分片数。这必须是源索引中分片数的倍数。

_split 请求中不能指定映射。

监控拆分过程编辑

可以使用 _cat recovery API 监控拆分过程,或者可以使用 集群运行状况 API 通过将 wait_for_status 参数设置为 yellow 来等待所有主分片都已分配。

_split API 在目标索引被添加到集群状态后立即返回,此时还没有分配任何分片。此时,所有分片都处于 unassigned 状态。如果由于任何原因无法分配目标索引,则其主分片将保持 unassigned 状态,直到可以在该节点上分配它为止。

一旦分配了主分片,它就会进入 initializing 状态,并且拆分过程开始。当拆分操作完成时,分片将变为 active 状态。此时,Elasticsearch 将尝试分配任何副本,并可能决定将主分片重新定位到另一个节点。

等待活动分片编辑

由于拆分操作会创建一个新的索引来将分片拆分到其中,因此索引创建时的 等待活动分片 设置也适用于拆分索引操作。

路径参数编辑

<index>
(必填,字符串)要拆分的源索引的名称。
<target-index>

(必填,字符串)要创建的目标索引的名称。

索引名称必须符合以下标准

  • 仅限小写
  • 不能包含 \/*?"<>|、` `(空格字符)、,#
  • 7.0 之前的索引可以包含冒号(:),但这已被弃用,并且在 7.0+ 中不再受支持
  • 不能以 -_+ 开头
  • 不能是 ...
  • 不能超过 255 个字节(注意,它是字节,因此多字节字符将更快地达到 255 个字节的限制)
  • . 开头的名称已被弃用,但 隐藏索引 和由插件管理的内部索引除外

查询参数编辑

wait_for_active_shards

(可选,字符串)在继续操作之前必须处于活动状态的分片副本数。设置为 all 或任何正整数,最大值为索引中的分片总数(number_of_replicas+1)。默认值:1,即主分片。

请参阅 活动分片

master_timeout
(可选,时间单位)等待主节点的时间。如果在超时到期之前主节点不可用,则请求失败并返回错误。默认为 30s。也可以设置为 -1 以指示请求永不超时。
timeout
(可选,时间单位)等待响应的时间。如果在超时到期之前未收到响应,则请求失败并返回错误。默认为 30s

请求正文编辑

aliases

(可选,对象的集合)结果索引的别名。

aliases 对象的属性
<alias>

(必填,对象)键是别名。索引别名支持 日期数学

对象正文包含别名的选项。支持空对象。

<alias> 的属性
filter
(可选,查询 DSL 对象)用于限制别名可以访问的文档的查询。
index_routing
(可选,字符串)用于将索引操作路由到特定分片的值。如果指定,则会覆盖索引操作的 routing 值。
is_hidden
(可选,布尔值)如果为 true,则别名将被 隐藏。默认为 false。该别名的所有索引必须具有相同的 is_hidden 值。
is_write_index
(可选,布尔值)如果为 true,则该索引是该别名的 写入索引。默认为 false
routing
(可选,字符串)用于将索引和搜索操作路由到特定分片的值。
search_routing
(可选,字符串)用于将搜索操作路由到特定分片的值。如果指定,则会覆盖搜索操作的 routing 值。
settings
(可选,索引设置对象)目标索引的配置选项。请参阅 索引设置