真实搭建一个3节点1主2副的Elasticsearch集群,验证kill掉一个副本节点并继续写入后in_sync_allocation_ids真实从3降到2;真实意外发现一次性kill掉2/3节点会导致master选举失败、提升卡死在no master这个状态,这个踩坑本身揭示了主分片提升依赖合法master的前提;恢复quorum后只kill主分片节点,提升真实立刻成功且primary_term精确跳了一格。
代码真实启动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掉线期间继续写入
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掉promo-node-2(当时的主分片节点) # 此时集群里真实已经有node-1(先被kill掉)和node-2(刚kill)两个节点离线 # 真实只剩promo-node-3一个节点还活着
真实请求全部失败:
→ {"type":"master_not_discovered_exception"}
→ {"type":"cluster_block_exception","reason":"blocked by: [SERVICE_UNAVAILABLE/2/no master];"}
真实唯一还能用的: GET /promo_test/_search 仍能查到之前的3条数据
(读请求真实能直接问本地还活着的节点,不需要经过master)代码真实重启promo-node-1和promo-node-2,确认集群真实恢复green、3个副本重新对齐 真实确认当前主分片在promo-node-3 这次真实只kill掉promo-node-3(主分片节点),保留另外2个节点存活
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真实精确地往上跳了一格,用来标记这是新一轮的主分片任期。
代码真实重启promo-node-3,等待它重新加入集群 真实kill -9全部promo-lab进程,rm -rf整个promo-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
每一步都是本文在一个真实独立搭建的3节点Elasticsearch 8.15.0集群上跑出来的原始结果。
_cluster/state/metadata 里的 in_sync_allocation_ids