Elasticsearch 集群健康排查:分步指南

遇到黄色或红色 Elasticsearch 集群?诊断未分配分片、磁盘压力、节点丢失及安全恢复方案。

Elasticsearch 集群健康排查:分步指南

黄色或红色 Elasticsearch 集群并非神秘状态。它通常意味着 Elasticsearch 无法将一个或多个分片放置到期望的位置。任务是找出哪个分片卡住、分配被阻止的原因,以及正确的修复方法是等待、释放资源、恢复节点、从快照恢复,还是有意接受数据丢失。

我将集群健康视为分诊信号,而非诊断本身。绿色表示每个主分片和副本分片都已分配。黄色表示所有主分片已分配,因此搜索和写入通常可以继续,但至少缺少一个副本。红色表示至少一个主分片未分配,因此至少一个索引的部分数据不可用。红色可能立即影响应用程序的读取或写入。

首先获取简单视图:

GET /_cluster/health?pretty
GET /_cat/health?v

查看 statusnumber_of_nodesactive_primary_shardsunassigned_shardsinitializing_shardsrelocating_shards。如果在节点重启后看到初始化或迁移中的分片,集群可能正在恢复。在了解 Elasticsearch 是否正在执行工作之前,不要开始更改分配设置。

然后列出未分配的分片:

GET /_cat/shards?v&h=index,shard,prirep,state,node,unassigned.reason&s=state,index,shard

prirep 列很重要。p 分片是主分片。红色集群总是至少有一个未分配的主分片。r 分片是副本分片。黄色集群通常只有未分配的副本分片。

在这种情况下最有用的 API 是分配解释:

GET /_cluster/allocation/explain?pretty

对于特定分片,要明确指定:

GET /_cluster/allocation/explain?pretty
{
  "index": "logs-2026.05.24",
  "shard": 0,
  "primary": false
}

阅读 can_allocate 答案和节点级别的决策。Elasticsearch 通常会准确告诉你哪个规则阻止了分配:磁盘水位线、分配过滤、同分片规则、节点离开后的延迟分配、缺少主分片数据、版本不兼容或节点角色不匹配。

当集群为黄色时

黄色在小集群中很常见。典型情况是单节点开发集群,number_of_replicas: 1。Elasticsearch 无法将副本放在与其主分片相同的节点上,因此副本永远保持未分配状态。这在笔记本电脑环境中并非紧急情况。这是配置不匹配。

检查副本数量:

GET /my-index/_settings?filter_path=*.settings.index.number_of_replicas

对于单节点非生产集群,将副本设置为零:

PUT /my-index/_settings
{
  "index": {
    "number_of_replicas": 0
  }
}

对于生产环境,除非你故意接受较低的冗余度,否则不要通过减少副本来隐藏问题。如果索引应该有一个副本,你至少需要两个合格的数据节点。如果有两个副本,你至少需要三个合格的数据节点。分层可能使这一点不那么明显:如果分配规则要求温节点,温索引的副本无法分配到仅热节点。

磁盘压力是下一个常见的黄色原因。检查节点磁盘使用情况:

GET /_cat/allocation?v
GET /_cat/nodes?v&h=name,roles,disk.used_percent,disk.avail,heap.percent,cpu,load_1m

Elasticsearch 使用磁盘水位线来避免填满节点。默认值因版本和配置而异,因此检查你的实际集群设置:

GET /_cluster/settings?include_defaults=true&flat_settings=true&filter_path=**cluster.routing.allocation.disk.watermark**

如果节点超过高水位线,Elasticsearch 将避免在那里分配更多分片。如果达到洪水水位线,Elasticsearch 可能会将受影响的索引置于写阻塞状态以保护节点。持久的修复方法是删除旧数据、将数据移动到更多节点、增加磁盘、缩小过大的分片数量或调整 ILM 保留策略。临时提高水位线可以争取时间,但不应该是你的首选操作。

一个实用的清理序列如下:

GET /_cat/indices?v&s=store.size:desc
GET /_cat/shards?v&s=store:desc

找到大的旧索引,与所属团队确认保留预期,如果需要则创建快照,然后仅删除允许删除的数据:

DELETE /old-logs-2025.12.*

释放空间后,分配可能会自动恢复。如果没有,重新运行分配解释。旧的原因可能仍在你脑海中缓存,但集群现在可能被不同的规则阻止。

分配过滤是另一个常见的黄色原因,尤其是在硬件迁移后。可能有人设置了索引要求一个不再存在的节点属性:

GET /my-index/_settings?flat_settings=true&filter_path=*.settings.index.routing.allocation*
GET /_cluster/settings?flat_settings=true&filter_path=**routing.allocation**

如果规则错误,删除或更新它:

PUT /my-index/_settings
{
  "index.routing.allocation.require.box_type": null,
  "index.routing.allocation.include._name": null,
  "index.routing.allocation.exclude._name": null
}

使用设置中显示的确切键。不要将广泛的重置粘贴到生产环境中而不阅读;分配规则有时存在是有充分理由的,例如将某些数据保留在合规控制的层上。

当集群为红色时

红色需要更慢的操作和更好的记录。第一个问题是丢失的主分片是否在某处有可恢复的副本。

列出未分配的主分片:

GET /_cat/shards?v&h=index,shard,prirep,state,unassigned.reason | grep ' p UNASSIGNED'

然后检查哪些节点存在:

GET /_cat/nodes?v&h=name,ip,roles,master,uptime,heap.percent,disk.avail

如果节点丢失,最好的恢复路径通常是恢复该节点。检查缺失节点的服务、磁盘挂载、主机网络、证书和日志。失去数据路径访问权限的节点可能作为不同的空节点启动,这无助于恢复主分片。

在 Elasticsearch 节点上,日志通常比 API 更早显示真正的故障。查找有关分片锁定失败、索引文件损坏、主节点发现、TLS 握手错误、磁盘只读文件系统或节点角色更改的消息。一个常见的实际故障是节点在磁盘以不同路径重新挂载后重启。Elasticsearch 启动,但数据路径为空,因此集群仍然缺少所需的分片副本。

为主分片运行分配解释:

GET /_cluster/allocation/explain?pretty
{
  "index": "orders-2026.05.24",
  "shard": 2,
  "primary": true
}

如果解释说找不到有效的分片副本,在执行任何破坏性操作之前停止并检查快照:

GET /_snapshot/_all
GET /_snapshot/my-repository/_all?verbose=false

从快照恢复通常比分配空主分片更安全。空主分片会为该分片 ID 创建一个新的空白分片。这不是修复操作。它告诉 Elasticsearch,“我接受该分片的旧数据已丢失。”

最后的手段命令如下:

POST /_cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "orders-2026.05.24",
        "shard": 2,
        "node": "es-data-03",
        "accept_data_loss": true
      }
    }
  ]
}

仅在确认没有可用的节点副本且没有可恢复的快照后使用。在事故中,记录谁批准了该选择以及受影响的索引和分片。当数据丢失决策明确时,未来的调试会容易得多。

看似分配问题但实际上是集群问题的情况

有时分片未分配是因为集群无法保持稳定的成员资格。如果主节点候选节点无法相互通信,选举的主节点可能会频繁更改,分配将波动或暂停。检查主节点稳定性:

GET /_cat/master?v
GET /_cat/nodes?v&h=name,roles,master,ip

如果主节点频繁更改,检查网络可靠性、DNS、节点证书和发现设置。对于现代 Elasticsearch 集群,cluster.initial_master_nodes 用于初始集群引导,而不是永远保留为通用发现拐杖的设置。discovery.seed_hosts 应指向适当的种子主机,并且所有节点必须使用相同的集群名称和兼容的安全设置。

高 JVM 压力也可能导致分配症状。长时间垃圾收集暂停的数据节点可能从主节点的角度离开并重新加入集群。这可能会创建未分配的分片,即使机器从未完全崩溃。

检查堆和垃圾收集日志:

GET /_cat/nodes?v&h=name,heap.percent,ram.percent,cpu,load_1m,node.role
GET /_nodes/stats/jvm?filter_path=nodes.*.jvm.mem,nodes.*.jvm.gc

如果堆持续较高,不要盲目增加堆。Elasticsearch 通常在堆为文件系统缓存留出足够内存时表现最佳。查找过大的聚合、大量 fielddata 使用、过多分片、激进索引或需要更好映射的查询。

分片数量可能是许多健康问题的潜在原因。具有许多小分片的集群花费太多精力跟踪元数据和移动分片。使用:

GET /_cat/indices?v&h=index,pri,rep,docs.count,store.size,pri.store.size&s=pri:desc
GET /_cluster/stats?filter_path=indices.shards,indices.count,nodes.count

如果每个每日日志索引都有许多主分片但数据很少,修复未来索引的索引模板。然后考虑对现有数据进行收缩、滚动或重新索引计划。

实用的分诊顺序

当有人说“Elasticsearch 是红色”时,我使用以下顺序:

  1. 使用 _cluster/health 确认健康状态。
  2. 使用 _cat/shards 列出未分配的分片。
  3. 区分主分片故障和副本分片故障。
  4. 在一个代表性分片上运行 _cluster/allocation/explain
  5. 检查所有预期节点是否存在。
  6. 检查磁盘水位线和分配规则。
  7. 对于红色主分片,在考虑空主分片分配之前,尝试恢复缺失的节点或从快照恢复。
  8. 集群变为绿色后,找到最初导致不健康的原因。

最后一步很重要。集群在添加磁盘、重启节点或减少副本后可能变为绿色,但如果 ILM 保留策略错误、分片数量过高、节点规模不足或部署过程不断更改节点属性,相同的事故将再次发生。

集群健康故障排除与其说是记住一个神奇的命令,不如说是拒绝猜测。Elasticsearch 公开了分配决策。阅读它,根据节点和索引设置验证它,并选择与实际阻塞器匹配的最小修复。

集群再次变为绿色后

不要仅仅因为颜色改变就关闭事故。绿色仅意味着分片现在已分配。它不能证明集群足够健康以应对下一个流量高峰、磁盘增长周期或节点重启。我喜欢在细节仍然清晰时捕获一个简短的事后记录:哪些索引受到影响,哪些节点涉及,哪个分配规则阻止了恢复,以及哪个命令或基础设施更改修复了它。

检查修复是否创造了新的风险。如果你减少了副本以将黄色变为绿色,记录该索引现在具有较少的冗余。如果你提高了磁盘水位线,添加提醒在添加容量后降低它们。如果你从快照恢复,验证恢复的索引具有预期的别名和写入设置,然后应用程序恢复正常写入。

一些快速检查有助于发现未完成的工作:

GET /_cat/recovery?v&active_only=true
GET /_cat/pending_tasks?v
GET /_cat/aliases?v
GET /_cluster/health?wait_for_status=green&timeout=30s

pending_tasks 不应无限增长。恢复最终应清空。别名很重要,因为以不同名称恢复索引可能导致应用程序写入旧的损坏目标或仅读取部分预期数据。

此外,在磁盘事件后检查写入阻塞:

GET /*/_settings?filter_path=*.settings.index.blocks*

如果 Elasticsearch 设置了洪水阻塞,仅在磁盘压力修复后移除它:

PUT /my-index/_settings
{
  "index.blocks.read_only_allow_delete": null
}

最有用的预防工作通常是枯燥的:工作快照、测试恢复、现实的 ILM 保留、足够的磁盘余量以及与集群大小匹配的分片数量。具有可靠快照和合理分片大小的集群比具有巧妙紧急命令且无恢复路径的集群更容易恢复。

健康事故期间不应做的事情

不要同时重启所有节点。当集群看起来不健康时,这很诱人,但滚动、观察的方法更安全。重启健康节点可能会移除 Elasticsearch 恢复所需的分片副本。如果必须重启,一次一个节点,并等待集群在步骤之间稳定。

不要禁用分配然后忘记它。临时分配更改在维护期间很常见,但遗忘的设置可能在维护窗口结束后很长时间内使副本保持未分配状态。始终检查持久和瞬态设置:

GET /_cluster/settings?flat_settings=true&include_defaults=false

不要仅根据大小删除索引。大索引可能对业务至关重要。小索引可能安全删除。将清理与保留策略、快照和应用程序所有权联系起来。在实际中断中,最快的安全清理通常是删除已知过期的日志或指标索引,而不是从排序的大小列表中猜测。

不要假设 Kibana 和 Elasticsearch 使用相同的语言描述问题。Kibana 可能显示广泛的红色状态,而 Elasticsearch API 显示精确的未分配分片。使用 UI 进行可见性,但使用 API 进行决策。