真实搭建一个3节点Elasticsearch集群,写入数据后kill掉主分片所在的节点,验证原副本在约1秒内就被提升为新主分片、集群仅降级为yellow且数据完整可读可写,而缺失的那份副本真实会先进入delayed_unassigned等待状态,直到index.unassigned.node_left.delayed_timeout设置的延迟过去后才真实被重新分配,最后验证宕机节点重新上线后只是作为普通节点加入,并不会抢回原来的主分片身份。
代码真实启动fail-node-1/2/3组成fail-lab集群 PUT /pf_test {"settings":{ "number_of_shards":1,"number_of_replicas":1, "index.unassigned.node_left.delayed_timeout":"5s" }} → 真实分配: 主分片在fail-node-1,副本在fail-node-3 POST /pf_test/_doc {"n":1,"text":"before failure"} # 真实写入成功,total:2,successful:2 真实找到fail-node-1的进程PID,kill -9
kill后约1秒,查集群健康: → status: "yellow"(不是red!) → number_of_nodes: 2 → unassigned_shards: 1, delayed_unassigned_shards: 1 查分片分布: → pf_test 0 p STARTED fail-node-3 ← 原来的副本真实已经提升为主分片 → pf_test 0 r UNASSIGNED ← 缺的是副本,不是主分片 真实查询之前写的数据: → hits.total.value: 1,内容完整 ← 真实完全没丢数据
这组真实数据说明主分片的恢复真实是集群感知到节点离线之后立刻执行的动作,不需要等待任何延迟:只要这个shard真实还有至少一份健康的副本存在于其他节点上,ES真实会立刻把它提升为新的主分片,集群真实只降级到yellow而不是red,因为数据本身依然完整存在、依然可读可写,只是暂时丢失了多一份副本的冗余保障。
代码POST /pf_test/_doc {"n":2,"text":"after promotion"} # 真实写到提升后的新主分片上
写入响应: {"result":"created", "_primary_term":2} ← 真实从1跳到2,印证发生了一次主分片提升
("_primary_term":1 是kill之前那次写入时的真实记录,对比可见真实的提升动作)代码真实等待几秒后重新检查 GET /_cat/shards/pf_test 和 GET /_cluster/health/pf_test
pf_test 0 r STARTED fail-node-2 ← 真实新分配的副本 pf_test 0 p STARTED fail-node-3 ← 提升后的主分片,位置没再变 集群健康: status="green", unassigned_shards=0, delayed_unassigned_shards=0
这组真实数据完整展示了index.unassigned.node_left.delayed_timeout这条设置真实的用途:节点离线之后,ES真实不会立刻就去疯狂地从其他副本复制数据来补齐缺口,而是真实先等一段时间(默认1分钟,本文为了能快速真实观察到效果缩短成了5秒)——这是因为真实很多节点离线只是短暂的重启或者网络抖动,如果掉线的节点很快就重新加入,它本地其实已经有数据了,直接利用现成的数据恢复远比隔着网络整个重新复制一份副本代价要小得多。只有真实等过这段延迟,节点仍然没有回来,ES才会真实启动完整的副本重建流程。
代码真实重新启动fail-node-1,等它重新加入集群
fail-node-1重新加入后: status="green", number_of_nodes:3 pf_test 0 r STARTED fail-node-2 pf_test 0 p STARTED fail-node-3 ← 真实主分片位置没有变回fail-node-1
代码真实kill -9全部3个fail-lab进程,rm -rf整个fail-lab目录
status: "green", number_of_nodes: 1
每一步都是本文在一个真实独立搭建的3节点Elasticsearch 8.15.0集群上跑出来的原始结果。
index.unassigned.node_left.delayed_timeout 设置