--- title: "索引分片正在恢复异常 (index_shard_recovering_exception) 错误排查与解决" date: 2026-03-03 lastmod: 2026-03-03 description: "index_shard_recovering_exception 表示尝试对正在进行恢复的分片执行不允许的操作,需要等待恢复完成或取消恢复。" tags: ["分片恢复", "快照", "数据迁移"] summary: "为什么这个错误发生 # index_shard_recovering_exception 表示尝试对正在进行恢复(recovering)的分片执行不允许的操作。当分片处于恢复状态时,某些操作(如再次启动恢复)会被拒绝。 这个错误可能由以下原因引起: 分片正在恢复:分片当前正在执行恢复操作 并发恢复请求:同时发起了多个恢复请求 分片处于恢复后状态:分片处于 POST_RECOVERY 状态 节点重启后:节点重启后分片正在进行恢复 副本恢复:副本分片正在从主分片恢复数据 快照恢复:从快照恢复分片时发生 ** relocation 过程**:分片正在迁移到另一个节点 恢复未完成:之前的恢复操作尚未完成 如何修复这个错误 # 1. 检查分片状态 # # 查看分片当前状态 GET /_cat/shards?v&h=index,shard,prirep,state,node # 查看特定索引的分片状态 GET /<index>/_shard_stores?status=recovering # 查看分片恢复状态 GET /<index>/_recovery?active_only=true 2. 等待恢复完成 # # 等待当前恢复操作完成 GET /_cat/recovery?v # 查看恢复进度 GET /_cat/recovery?v&h=index,shard,bytes,bytes_pct,stage # 等待集群状态变为绿色 GET /_cluster/health?wait_for_status=green&timeout=300s 3. 取消恢复(如果卡住) # # 如果恢复卡住,可以尝试取消并重新分配 POST /_cluster/reroute { "commands": [ { "cancel": { "index": "<index>", "shard": 0, "node": "<node_name>" } } ] } # 然后重新分配 POST /_cluster/reroute { "commands": [ { "allocate_replica": { "index": "<index>", "shard": 0, "node": "<node_name>" } } ] } 4." --- ## 为什么这个错误发生 `index_shard_recovering_exception` 表示尝试对正在进行恢复(recovering)的分片执行不允许的操作。当分片处于恢复状态时,某些操作(如再次启动恢复)会被拒绝。 这个错误可能由以下原因引起: 1. **分片正在恢复**:分片当前正在执行恢复操作 2. **并发恢复请求**:同时发起了多个恢复请求 3. **分片处于恢复后状态**:分片处于 POST_RECOVERY 状态 4. **节点重启后**:节点重启后分片正在进行恢复 5. **副本恢复**:副本分片正在从主分片恢复数据 6. **快照恢复**:从快照恢复分片时发生 7. ** relocation 过程**:分片正在迁移到另一个节点 8. **恢复未完成**:之前的恢复操作尚未完成 ## 如何修复这个错误 ### 1. 检查分片状态 ```bash # 查看分片当前状态 GET /_cat/shards?v&h=index,shard,prirep,state,node # 查看特定索引的分片状态 GET //_shard_stores?status=recovering # 查看分片恢复状态 GET //_recovery?active_only=true ``` ### 2. 等待恢复完成 ```bash # 等待当前恢复操作完成 GET /_cat/recovery?v # 查看恢复进度 GET /_cat/recovery?v&h=index,shard,bytes,bytes_pct,stage # 等待集群状态变为绿色 GET /_cluster/health?wait_for_status=green&timeout=300s ``` ### 3. 取消恢复(如果卡住) ```bash # 如果恢复卡住,可以尝试取消并重新分配 POST /_cluster/reroute { "commands": [ { "cancel": { "index": "", "shard": 0, "node": "" } } ] } # 然后重新分配 POST /_cluster/reroute { "commands": [ { "allocate_replica": { "index": "", "shard": 0, "node": "" } } ] } ``` ### 4. 强制分配分片 ```bash # 如果恢复失败,可以尝试强制分配 POST /_cluster/reroute { "commands": [ { "allocate_stale_primary": { "index": "", "shard": 0, "node": "", "accept_data_loss": true } } ] } ``` ### 5. 从快照恢复 ```bash # 如果恢复失败,可以从快照重新恢复 POST /_snapshot///_restore { "indices": "", "include_global_state": false } # 查看可用的快照 GET /_snapshot//_all ``` ### 6. 重启节点 ```bash # 在承载问题分片的节点上重启服务 sudo systemctl restart easysearch # 等待节点加入集群 GET /_cat/nodes?v ``` ### 7. 删除并重建索引 ```bash # 如果没有重要数据,可以删除并重建索引 DELETE / # 重新创建索引 PUT / # 从数据源重新导入数据 ``` ### 8. 检查恢复配置 ```yaml # 在 easysearch.yml 中调整恢复配置 cluster.routing.allocation.node_initial_primaries_recoveries: 4 cluster.routing.allocation.node_concurrent_recoveries: 2 indices.recovery.max_bytes_per_sec: 50mb ``` ### 9. 查看恢复详情 ```bash # 查看详细的恢复信息 GET //_recovery?active_only=true&detailed=true # 查看所有分片的恢复状态 GET /_recovery?human&detailed=true ``` ### 10. 检查磁盘空间 ```bash # 确保有足够的磁盘空间进行恢复 GET /_cat/allocation?v # 查看磁盘使用 df -h /path/to/easysearch/data ``` ### 11. 增加恢复并发数 ```yaml # 如果有很多分片需要恢复,可以增加并发数 PUT /_cluster/settings { "transient": { "cluster.routing.allocation.node_concurrent_recoveries": 6, "cluster.routing.allocation.node_initial_primaries_recoveries": 8 } } ``` ### 12. 限制恢复带宽 ```yaml # 避免恢复占用过多带宽 PUT //_settings { "index": { "recovery": { "max_bytes_per_sec": "20mb" } } } ``` ### 13. 检查节点日志 ```bash # 查看恢复相关错误日志 grep -i "recover\|restore" /path/to/easysearch/logs/easysearch.log | tail -100 # 查看分片相关日志 grep -i "shard.*error" /path/to/easysearch/logs/easysearch.log | tail -50 ``` ### 14. 重置分片分配 ```bash # 重新启用分片分配 PUT /_cluster/settings { "transient": { "cluster.routing.allocation.enable": "all" } } # 触发重新分配 POST /_cluster/reroute?retry_failed=true ``` ### 预防措施 - 优雅关闭节点(避免强制终止) - 保持足够的磁盘空间 - 配置合理的恢复速度限制 - 监控恢复进度 - 使用快照备份重要数据 - 避免频繁的分片迁移 - 配置足够的副本数 - 监控集群健康状态 - 在低峰期执行节点维护 - 使用滚动重启而非同时重启多个节点