文章目录
- 概述
- 1. 背景:主副本同时 Unassigned,reroute 依然失败
- 2. 问题表现:Too many open files 触发系统级崩溃
- 文件句柄耗尽 → ES 无法打开 segment 文件
- 进一步导致:
- 3. ES 分片恢复的底层机制:stale primary vs empty primary
- 3.1 allocate_stale_primary
- 3.2 allocate_empty_primary
- 4. 工程化恢复流程(从系统修复到分片恢复)
- Step 0:修复系统文件句柄限制(关键)
- Step 1:冻结集群分片分配(避免自动迁移)
- Step 2:检查磁盘上的 shard 目录
- Step 3:查看 allocation explain
- Step 4:根据策略表为每个分片执行 stale 或 empty 恢复
- Step 5:恢复自动分片分配
- Step 6:等待 replica 自动重建
- 5. 逐分片恢复策略表
- 逐分片恢复策略表
- 6. 策略表:按图索骥
- 7. 恢复后的校验、压测与加固建议
- 7.1 校验数据一致性
- 7.2 强制段合并(可选)
- 7.3 集群压测
- 7.4 加固措施
- 8. 结语:灾难恢复能力,是搜索系统的核心韧性
概述
现代业务系统对 ElasticSearch(简称 ES) 的依赖已经到了深水区,一旦集群分片出现主副本同时 unassigned的情况,往往意味着搜索、查询、分析、写入全面瘫痪。
本周某客户现场线上ES集群部分索引健康状态red,接下来来看看我是如何在磁盘上仍存在数据文件的情况下,使用 ElasticSearch 的底层能力进行分片级数据恢复。
1. 背景:主副本同时 Unassigned,reroute 依然失败
某生产 ES 集群中,RED状态的5个核心业务索引均采用:
- 5 个 Primary shard
- 1 个 Replica shard
(其中两个索引5个shard都未分配, 三个索引有1个shard未分配)
一次系统级事件导致 ES 节点出现大量:
too manyopenfiles系统文件句柄被用尽,影响包括:
- ES 无法打开 segment 文件
- 无法读取 shard metadata
- 无法加载 translog
- 无法验证安全性 → 导致分片 unassigned
事后虽然尝试了 reroute, 但仍然失败,显示分片不可分配。 然而 ——磁盘上的 shard 数据目录依然存在。
这类情况非常典型:
ES 认为分片不安全,但物理数据其实还在,可恢复。
要想救回数据,就需要走“磁盘级恢复”路线。
2. 问题表现:Too many open files 触发系统级崩溃
too many open files看似常见,却会直接影响 ES 的核心:
文件句柄耗尽 → ES 无法打开 segment 文件
segment 是 Lucene 的基本存储单位,一旦无法被打开:
- metadata 校验失败
- CRC 校验失败
- ES 无法确认 shard 是否一致
- 自动恢复与 reroute 都会失败
进一步导致:
- primary → unassigned
- replica → unassigned
- allocation explain 显示无法恢复
- 分片数据“存在但不可用”
所有问题最终汇聚为一句话:
ES 会拒绝恢复那些无法被安全验证的分片,即使它们在磁盘上。
这时,工程师必须介入,进行手动分片级恢复。
3. ES 分片恢复的底层机制:stale primary vs empty primary
ElasticSearch 通过_cluster/reroute提供两种分片恢复方式:
3.1 allocate_stale_primary
allocate_stale_primary:使用磁盘上的旧分片恢复 primary(可能回滚数据)场景:
- shard 目录存在
- segment 完整
- ES 标记为 stale(陈旧但可用)
- 紧急情况下允许数据回滚
这是真正的“从磁盘恢复”。
3.2 allocate_empty_primary
allocate_empty_primary:清空该分片,建立一个全新的 primary(数据不可恢复)场景:
- shard 目录不存在
- 数据损坏无法读取
- 必须保证索引继续可用
只要磁盘数据存在且可读,永远优先 stale。
empty 是最后一步,等同于“放弃治疗”。
4. 工程化恢复流程(从系统修复到分片恢复)
Step 0:修复系统文件句柄限制(关键)
设置:
/etc/security/limits.conf * soft nofile 65536 * hard nofile 65536systemd:
[Service]LimitNOFILE=65536当前ES进程的使用情况
curl-XGET"localhost:9200/_cat/nodes?v&h=name,file_desc.current,file_desc.percent,file_desc.max"以上请检查,确保可用的fd数量,尽量保持50%的余量。 线上65536 , 当前使用率40%左右。 较为安全。可进行下一步。
Step 1:冻结集群分片分配(避免自动迁移)
PUT _cluster/settings{"transient":{"cluster.routing.allocation.enable":"none"}}实际操作,并没有执行这一步,不过建议考虑
Step 2:检查磁盘上的 shard 目录
路径:
/xxxxx/elasticsearch/nodes/0/indices/<index_uuid>/<shard_id>需要看到:
_state/index/*.cfs*.si
多个节点的话,早一个数据最大的 (可能意味着更新)。
Step 3:查看 allocation explain
GET _cluster/allocation/explain?pretty特别关注:
"stored_shard":"stale"意味着可恢复。
Step 4:根据策略表为每个分片执行 stale 或 empty 恢复
示例:
POST _cluster/reroute{"commands":[{"allocate_stale_primary":{"index":"index_name",#需要恢复的所以明"shard":2,"node":"node-1",#(集群的节点名称 ,elasticsearch.yml里配置的,也可以用node的id)"accept_data_loss":true}}]}如果有多个,循环往复,多次执行,查看状态。 亲测可用。
校验
GET _cat/shards?v GET<index>/_count GET<index>/_search?size=10Step 5:恢复自动分片分配
PUT _cluster/settings{"transient":{"cluster.routing.allocation.enable":"all"}}配合step 1
Step 6:等待 replica 自动重建
重建期间 ES 负载较高,请保持稳定。
5. 逐分片恢复策略表
这张表用于决定每个 shard 是用:
allocate_stale_primary(从磁盘恢复)allocate_empty_primary(重建空分片)
核心判定规则:
只要 shard 目录存在且 segment 文件完好 → 使用 stale。
仅当目录不存在或损坏 → 使用 empty。
逐分片恢复策略表
| Shard | 目录存在 | segment 完整 | allocation explain | 恢复方式 | 说明 |
|---|---|---|---|---|---|
| 0 | ✔/✘ | ✔/✘ | stale/empty/unknown | stale/empty | —— |
| 1 | ✔/✘ | ✔/✘ | stale/empty/unknown | stale/empty | —— |
| 2 | ✔/✘ | ✔/✘ | stale/empty/unknown | stale/empty | —— |
| 3 | ✔/✘ | ✔/✘ | stale/empty/unknown | stale/empty | —— |
| 4 | ✔/✘ | ✔/✘ | stale/empty/unknown | stale/empty | —— |
6. 策略表:按图索骥
| Shard | 目录存在 | segment 完整 | allocation explain | 恢复方式 | 说明 |
|---|---|---|---|---|---|
| 0 | ✔ | ✔ | stale | allocate_stale_primary | 可恢复 |
| 1 | ✔ | ✔ | stale | allocate_stale_primary | 可恢复 |
| 2 | ✔ | ✔ | stale | allocate_stale_primary | 可恢复 |
| 3 | ✔ | ✔ | stale | allocate_stale_primary | 可恢复 |
| 4 | ✔ | ✔ | stale | allocate_stale_primary | 可恢复 |
如果某个分片目录损坏,比如 shard 3:
| Shard | 恢复方式 |
|---|---|
| 0 | stale |
| 1 | stale |
| 2 | stale |
| 3 | empty |
| 4 | stale |
7. 恢复后的校验、压测与加固建议
恢复不是结束,以下操作决定能否彻底恢复正常业务。
7.1 校验数据一致性
- count 对比
- 随机文档抽查
- 业务侧搜索验证
7.2 强制段合并(可选)
提升健康度:
POST<index>/_forcemerge?max_num_segments=17.3 集群压测
使用 rally 或 jmeter 构建写入/查询压力测试。
7.4 加固措施
- 提升系统 nofile
- 设置 JVM heap 与 memlock
- 配置 shard allocation awareness
- 增加 replica(如果业务要求高可用)
8. 结语:灾难恢复能力,是搜索系统的核心韧性
ElasticSearch 虽然强大,但恢复机制背后的设计哲学始终明确:
ES 宁可拒绝恢复,也不会冒险使用可能损坏的数据。
因此,工程师必须掌握磁盘级恢复与 stale 分片重建的技术。
- 分片恢复原理
- allocate_stale_primary 与 allocate_empty_primary 的判定逻辑
- 逐分片恢复策略表
- 完整恢复手册
都可以作为你的 ES 灾难恢复知识库的重要组成部分。
真正的韧性不是避免灾难,而是在灾难发生后仍能恢复如常。