真实停掉一个独立节点,直接用python往真实的Lucene segment文件中间写入乱码模拟数据损坏,重启后集群变red,allocation/explain真实精确捕获到checksum校验失败的CorruptIndexException;试标准的retry_failed=true没用,再试allocate_empty_primary接受数据丢失又真实卷进新的失败卡在max_retry;最后发现直接DELETE整个索引反而最干净,立刻把集群拉回green,印证了snapshot才是对付真正数据损坏的真实解药这条结论。
代码真实停掉corrupt-lab节点 真实用python打开segment文件,定位到文件中间,写入一段乱码字节: .../indices/.../0/index/_2.cfs 真实写入: b"CORRUPTED_BY_DRILL_TEST_XXXXXXXX"
代码真实重启节点 GET /_cluster/allocation/explain {"index":"corrupt_test","shard":0,"primary":true}
status: "red", unassigned_shards: 1 真实的根因: org.apache.lucene.index.CorruptIndexException: "checksum failed (hardware problem?) : expected=f11be086 actual=896fa487" allocate_explanation: "Elasticsearch can't allocate this shard because all the copies of its data in the cluster are stale or corrupt. ... If no such node is available, restore this index from a recent snapshot." last_allocation_status: "no_valid_shard_copy"
这个真实结果说明Lucene对数据完整性真实有一道硬性的checksum校验:每个段文件在被读取、打开的时候都真实会校验一次内容的checksum跟文件末尾记录的checksum是否一致,本次真实写进去的那段乱码直接导致了checksum不匹配,Lucene真实立刻判定这份数据已经损坏,不会尝试"带着错误数据硬跑",而是真实直接拒绝打开这个shard。
代码POST /_cluster/reroute?retry_failed=true
retry_failed=true → {"acknowledged":true}
真实2秒后再查: status依然是"red"代码POST /_cluster/reroute {"commands":[{"allocate_empty_primary":{ "index":"corrupt_test","shard":0,"node":"corrupt-node-1","accept_data_loss":true }}]}
真实这次操作本身又触发了新的恢复失败: → IndexShardRecoveryException: "failed to fetch index version after copying it over" → 真实自动重试了5次后,被max_retry这道decider拦住,不再继续重试
代码DELETE /corrupt_test
DELETE /corrupt_test → {"acknowledged":true}
真实立刻查: status: "green", unassigned_shards: 0这组真实对比给出了一个朴素但真实有效的经验:当某个shard真实确认是因为数据损坏而无法打开、又没有可用的snapshot或者健康副本能顶上去的时候,相比在原地纠结各种"修复"手段,直接把这个索引删掉、重新从业务侧补数据或者从snapshot恢复,反而真实是风险最低、最快能让集群恢复健康的办法——这正是本系列前面反复强调的"snapshot才是对付真正数据损坏的真实解药,replica解决不了这类问题"这条结论的又一次真实印证。
每一步都是本文在一个真实独立搭建的Elasticsearch 8.15.0节点上跑出来的原始结果,测完即销毁。
_cluster/reroute 的 retry_failed 与 allocate_empty_primary 命令