节点离开时延迟分配

编辑

当一个节点由于任何原因(有意或无意)离开集群时,主节点会通过以下方式做出反应:

  • 将副本分片提升为主分片,以替换该节点上的任何主分片。
  • 分配副本分片以替换丢失的副本(假设有足够的节点)。
  • 在剩余节点之间均匀地重新平衡分片。

这些操作旨在通过确保每个分片都尽快完全复制来保护集群免受数据丢失的影响。

尽管我们在节点级别集群级别都限制了并发恢复,但这种“分片洗牌”仍然会对集群造成额外的负载,如果丢失的节点很可能很快返回,这可能是不必要的。想象一下以下场景:

  • 节点 5 失去网络连接。
  • 主节点将节点 5 上的每个主分片的副本分片提升为主分片。
  • 主节点将新的副本分配给集群中的其他节点。
  • 每个新的副本都会通过网络制作主分片的完整副本。
  • 更多的分片被移动到不同的节点以重新平衡集群。
  • 节点 5 在几分钟后返回。
  • 主节点通过将分片分配给节点 5 来重新平衡集群。

如果主节点只是等待几分钟,那么丢失的分片可以以最少的网络流量重新分配给节点 5。对于已被自动刷新的空闲分片(未接收索引请求的分片),此过程甚至更快。

由于节点离开而变为未分配状态的副本分片的分配可以使用 index.unassigned.node_left.delayed_timeout 动态设置来延迟,该设置的默认值为 1m

可以在活动的索引(或所有索引)上更新此设置。

resp = client.indices.put_settings(
    index="_all",
    settings={
        "settings": {
            "index.unassigned.node_left.delayed_timeout": "5m"
        }
    },
)
print(resp)
response = client.indices.put_settings(
  index: '_all',
  body: {
    settings: {
      'index.unassigned.node_left.delayed_timeout' => '5m'
    }
  }
)
puts response
const response = await client.indices.putSettings({
  index: "_all",
  settings: {
    settings: {
      "index.unassigned.node_left.delayed_timeout": "5m",
    },
  },
});
console.log(response);
PUT _all/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m"
  }
}

启用延迟分配后,上述场景将变为如下所示:

  • 节点 5 失去网络连接。
  • 主节点将节点 5 上的每个主分片的副本分片提升为主分片。
  • 主节点记录一条消息,表明未分配分片的分配已延迟,以及延迟多长时间。
  • 集群保持黄色状态,因为存在未分配的副本分片。
  • 节点 5 在几分钟后返回,在 timeout 过期之前。
  • 丢失的副本将被重新分配给节点 5(并且同步刷新的分片几乎立即恢复)。

此设置不会影响将副本提升为主分片,也不会影响分配之前未分配的副本。特别地,在完全集群重启后,延迟分配不会生效。此外,在发生主节点故障转移的情况下,经过的延迟时间会被遗忘(即重置为初始的完整延迟)。

取消分片重新定位

编辑

如果延迟分配超时,主节点会将丢失的分片分配给另一个将开始恢复的节点。如果丢失的节点重新加入集群,并且其分片仍与主分片具有相同的同步 ID,则将取消分片重新定位,并且将使用同步分片进行恢复。

因此,默认的 timeout 设置为仅一分钟:即使分片重新定位开始,取消恢复而选择同步分片也是代价很小的。

监控延迟的未分配分片

编辑

可以使用 集群健康 API 查看已通过此超时设置延迟分配的分片数量。

resp = client.cluster.health()
print(resp)
response = client.cluster.health
puts response
const response = await client.cluster.health();
console.log(response);
GET _cluster/health 

此请求将返回一个 delayed_unassigned_shards 值。

永久删除节点

编辑

如果某个节点不会返回,并且您希望 Elasticsearch 立即分配丢失的分片,只需将超时更新为零即可:

resp = client.indices.put_settings(
    index="_all",
    settings={
        "settings": {
            "index.unassigned.node_left.delayed_timeout": "0"
        }
    },
)
print(resp)
response = client.indices.put_settings(
  index: '_all',
  body: {
    settings: {
      'index.unassigned.node_left.delayed_timeout' => '0'
    }
  }
)
puts response
const response = await client.indices.putSettings({
  index: "_all",
  settings: {
    settings: {
      "index.unassigned.node_left.delayed_timeout": "0",
    },
  },
});
console.log(response);
PUT _all/_settings
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "0"
  }
}

一旦丢失的分片开始恢复,您就可以重置超时。