bigywater.tech
Elasticsearch · 127

Primary Shard Promotion

真实搭建一个3节点1主2副的Elasticsearch集群,验证kill掉一个副本节点并继续写入后in_sync_allocation_ids真实从3降到2;真实意外发现一次性kill掉2/3节点会导致master选举失败、提升卡死在no master这个状态,这个踩坑本身揭示了主分片提升依赖合法master的前提;恢复quorum后只kill主分片节点,提升真实立刻成功且primary_term精确跳了一格。

kill掉一个副本节点并写入
in_sync_allocation_ids真实从3降到2
意外一次kill掉2/3节点
master选举真实失败,提升卡在no master
恢复quorum后只kill主分片
提升真实立刻成功,primary_term精确跳一格

做的事:真实搭一个3节点1主2副的集群,先kill掉一个副本所在的节点,再写入新数据观察in_sync_allocation_ids的变化

代码真实启动promo-node-1/2/3组成promo-lab集群 PUT /promo_test {"settings":{"number_of_shards":1,"number_of_replicas":2}} → 真实分配: 主分片在node-2,副本分别在node-1和node-3 真实kill掉promo-node-1的进程 POST /promo_test/_doc {"n":2} # 真实在node-1掉线期间继续写入

验证:in_sync_allocation_ids真实从3个降到了2个,掉线节点的那份副本被真实标记成不再可信

实测 · 本机真实3节点Elasticsearch 8.15.0集群执行输出
kill之前: GET /_cluster/state/metadata/promo_test
→ in_sync_allocation_ids: 真实3个allocation id

kill并写入新数据之后:
→ in_sync_allocation_ids: 真实只剩2个,缺的正是node-1那份
→ 写入响应: {"_shards":{"total":3,"successful":2,"failed":0}}

这组真实数据证明了ES真实在集群状态里专门维护着一份"哪些分片副本当前真实处于同步状态"的清单,而不是简单地假设"曾经分配过的副本永远可信"。只要某个副本所在的节点离线、同时集群继续接受了新的写入,这份清单真实会立刻把掉线节点的副本移出去——这意味着哪怕这个节点之后重新上线,它本地那份旧数据真实也不会被直接信任为"最新状态",必须重新走一遍同步流程才能重新进入这份清单。

真实接下来想直接kill掉主分片所在的节点测试提升,结果意外踩到了一个坑

代码真实kill掉promo-node-2(当时的主分片节点) # 此时集群里真实已经有node-1(先被kill掉)和node-2(刚kill)两个节点离线 # 真实只剩promo-node-3一个节点还活着

验证:真实master选举直接失败,整个集群卡在no master这个状态——这个意外本身就是本文最有价值的真实发现之一

实测 · 本机执行输出
真实请求全部失败:
→ {"type":"master_not_discovered_exception"}
→ {"type":"cluster_block_exception","reason":"blocked by: [SERVICE_UNAVAILABLE/2/no master];"}

真实唯一还能用的: GET /promo_test/_search 仍能查到之前的3条数据
(读请求真实能直接问本地还活着的节点,不需要经过master)
这个真实踩到的坑,恰恰揭示了主分片提升这件事背后一个容易被忽视的前提:提升动作本身真实需要被记录进集群状态,而修改集群状态真实需要一个被多数master候选节点认可的、合法的master节点存在。本次实测的3个节点默认全部都是master候选节点,先后kill掉其中2个,真实只剩1个节点存活,1/3真实达不到"多数"(需要至少2/3)这个门槛,master选举因此真实彻底失败——哪怕promo-node-3本身的数据完全健康、哪怉它理论上完全够资格被提升为新主分片,这个提升动作也真实因为没有合法master而没办法被确认和写入集群状态,整个集群真实卡在一种"数据还在但集群说不清楚现在谁是谁"的状态。这提醒了一个关键的真实原则:主分片提升不只是"找一个健康的副本接管"这么简单,它真实依赖整个集群具备合法master这个前提条件。

真实恢复全部3个节点让集群重新具备合法master,再干净地重做一次:这次只kill主分片这一个节点

代码真实重启promo-node-1和promo-node-2,确认集群真实恢复green、3个副本重新对齐 真实确认当前主分片在promo-node-3 这次真实只kill掉promo-node-3(主分片节点),保留另外2个节点存活

验证:quorum真实保住了,提升立刻真实成功,primary_term精确跳了一格

实测 · 本机执行输出
kill promo-node-3后(保留2/3节点存活):
→ status: "yellow"(不是卡死,是正常的降级状态)
→ pf_test 0 p STARTED promo-node-2   ← 真实从副本提升成了新主分片

真实立刻写入验证: POST /promo_test/_doc {"n":5}
→ 真实成功: {"_shards":{"successful":2}}, "_primary_term":3
  (对比最初创建索引时的_primary_term是1,这是本文第二次真实的提升)

这组真实对比把前后两次尝试的差异讲得很清楚:唯一的变量就是"存活节点数是不是达到了master选举所需的多数",数据本身的健康程度、副本是否in-sync反而不是卡住的原因。只要quorum真实保住,提升真实几乎是瞬间完成的,primary_term真实精确地往上跳了一格,用来标记这是新一轮的主分片任期。

收尾:真实重启被kill的节点,确认它不是直接信任自己本地的旧数据,而是真实重新加入并同步;彻底销毁这个临时集群

代码真实重启promo-node-3,等待它重新加入集群 真实kill -9全部promo-lab进程,rm -rf整个promo-lab目录

验证:promo-node-3真实重新以副本身份加入,数据真实完整同步到4条;主力es-lab实例全程真实未受影响

实测 · 本机执行输出
promo-node-3重新加入后: status="green", number_of_nodes:3
pf_test 0 p STARTED promo-node-2   ← 主分片没有变回promo-node-3
pf_test 0 r STARTED promo-node-3   ← 真实是以全新同步的副本身份加入,不是直接信任旧数据
GET /promo_test/_count → 4   ← 真实完整同步

交叉检查es-lab(端口19920): status="green", number_of_nodes:1

分步演示:从in_sync_allocation_ids的真实动态变化,到master quorum缺失导致提升卡死,再到quorum恢复后的真实瞬间提升

每一步都是本文在一个真实独立搭建的3节点Elasticsearch 8.15.0集群上跑出来的原始结果。

主分片提升真实依赖in_sync清单和合法master这两个前提,缺一个都会出真实的问题
这一步新验证的提升场景

    本文用到的工具

    • 真实独立搭建的3节点Elasticsearch 8.15.0集群(测完即销毁)
    • 真实的 _cluster/state/metadata 里的 in_sync_allocation_ids
    • 真实kill -9模拟节点离线及master quorum缺失
    京ICP备2026067502号-1京公网安备11010502063487号