推迟分片分配 (Delaying Shard Allocation)edit

正如我们在 水平扩容 讨论过的, Elasticsearch 将自动在可用节点间进行分片均衡,包括新节点的加入和现有节点的离线。

从理论上来说,这是最好的做法,我们想要提拔副本分片来尽快恢复丢失的主分片。 我们同时也希望保证资源在整个集群的均衡,以防出现热点。

然而,在实践中,立即的再均衡所造成的问题会比其解决的更多。例如,考虑一下这种情况:

  1. 节点 node-19 在网络中失联了(某个家伙踢到了电源线)
  2. Master 立即注意到了这个节点的离线,它决定在集群内提拔其他拥有 node-19 上面的主分片对应的副本分片为主分片
  3. 在副本分片被提拔为主分片以后,master 节点开始执行恢复操作来重建缺失的副本。 集群中的节点之间互相拷贝分片数据,网卡压力剧增,集群状态尝试变绿。
  4. 由于目前集群处于非平衡状态,这个过程还有可能会触发小规模的分片移动。 其他不相关的分片将在主机间迁移来达到更好的平衡状态

与此同时,那个踢到电源线的倒霉管理员,把电源线插好。node-19 重新启动并加入集群。 不幸的是,这个节点被告知当前的数据已经没有用了,数据已经在其他节点上重新分配了。 所以 node-19 把本地的数据进行删除,然后重新开始恢复集群的其他分片(然后这又导致了一个新的再平衡)

如果这一切听起来是不必要的且开销极大,那就对了。 是的,不过前提是你知道这个节点会很快回来。 如果节点 node-19 真的丢了,上面的流程确实正是我们想要发生的。

为了解决这种瞬时中断的问题,Elasticsearch 有了推迟分片分配的能力。 这使集群有时间查看节点是否会在开始重新平衡之前重新加入。

修改默认延时edit

默认情况,集群会等待一分钟来查看节点是否会重新加入。 如果这个节点在计时器过期之前重新加入,重新加入的节点会保持其现有的分片数据,不会发生分片分配。

默认等待时间可以全局设置,也可以在索引级别进行修改,都是修改配置delayed_timeout:

PUT /_all/_settings 
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m" 
  }
}

通过使用 _all 索引名,我们可以为集群里面的所有的索引使用这个参数

默认时间被修改成了 5 分钟

这个配置是动态的,可以在运行时进行修改。 如果你希望分片立即分配而不想等待,你可以设置参数: delayed_timeout: 0.

延迟分配不会阻止副本被提拔为主分片。集群还是会进行必要的提拔来让集群回到 yellow 状态。缺失副本的分配是唯一被延迟的过程。

自动取消分片迁移edit

如果节点在超时之后再回来,且集群还没有完成分片的移动,会发生什么事情呢? 在这种情形下,Elasticsearch 会检查该机器磁盘上的数据和主分片上的当前活(live)的数据是不是一样 — 如果两者匹配, 说明没有进来新的文档,修改和删除 — 那么 master 将会取消正在进行的再平衡,并恢复该机器磁盘上的数据。

之所以这样做是因为本地磁盘的恢复永远要比网络间传输要快,并且因为我们可以保证分片上的数据是一样的,这个过程就是双赢的。

如果分片已经产生了分歧(比如:节点离线之后又索引了新的文档),则恢复进程将继续如常进行。重新加入的节点会删除本地的、过时的分片,然后获取一份新的。