集群健康度
集群健康度:Green / Yellow / Red 意味着什么、怎么办
一、三种颜色的定义与判定条件
Elasticsearch 的集群健康状态通过 GET /_cluster/health 查询,返回 status 字段,只有三个可能值:
| 状态 | 含义 | 判定条件 | 是否影响读写 | 是否影响高可用 |
|---|---|---|---|---|
| Green | 一切正常 | 所有分片(主分片 + 副本分片)均已分配 | 否 | 否 |
| Yellow | 警告 | 所有主分片已分配,但至少一个副本分片未分配 | 否(写入正常) | 是——节点宕机会丢数据 |
| Red | 紧急 | 至少一个主分片未分配 | 是——该索引部分数据不可读写 | 是 |
核心原则:主分片决定能不能用,副本分片决定安不安全。
GET /_cluster/health
返回示例:
{
"cluster_name" : "my-cluster",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 42,
"active_shards" : 78,
"unassigned_shards" : 6,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0
}
二、Yellow:原因分析与修复
2.1 常见原因
- 单节点集群:ES 默认
number_of_replicas = 1,单节点无法分配副本到同一节点(ES 不会把主分片和副本分片放在同一节点上,因为这样没有容灾意义)。 - 节点数不足:节点数量少于
number_of_replicas + 1。 - 节点刚刚重启:分片正在恢复中,通常几秒到几分钟自动恢复。
- 磁盘水位线触发:当磁盘使用超过
cluster.routing.allocation.disk.watermark.low(默认 85%),ES 停止向该节点分配分片。 - 分片分配过滤规则限制了可选节点。
2.2 修复步骤
场景一:开发/测试环境的单节点集群
# 临时方案:将副本数设为 0
PUT /_all/_settings
{
"index": {
"number_of_replicas": 0
}
}
# 更规范的做法:只在特定索引上设置
PUT /my_index/_settings
{
"index": {
"number_of_replicas": 0
}
}
场景二:生产环境节点不足
增加数据节点,或者在现有节点上调整副本数:
PUT /my_index/_settings
{
"index": {
"number_of_replicas": 2
}
}
注意:副本数不能超过 数据节点数 - 1。
场景三:磁盘水位线触发
# 检查磁盘使用情况
GET /_cat/allocation?v
# 临时调高水位线(治标不治本)
PUT /_cluster/settings
{
"transient": {
"cluster.routing.allocation.disk.watermark.low": "95%",
"cluster.routing.allocation.disk.watermark.high": "97%"
}
}
根本解决办法:扩容磁盘或清理过期数据。
三、Red:应急处理流程
红意味着业务数据不可读写,必须立即响应。 处理原则:先止血(止损),再修复(找根因)。
3.1 应急止血——5 分钟快速排查
Step 1:确认集群状态
GET /_cluster/health
Step 2:找到未分配的主分片
GET /_cat/shards?v&h=index,shard,prirep,state,unassigned.reason,node
关注 state 为 UNASSIGNED 且 prirep 为 p 的行。
更精确的查询:
GET /_cat/shards?v&s=state:desc
这会把未分配的分片排在最前面。
Step 3:查看未分配原因
GET /_cluster/allocation/explain
返回示例(解读关键字段):
{
"index" : "orders-2026",
"shard" : 2,
"primary" : true,
"current_state" : "unassigned",
"unassigned_info": {
"reason" : "NODE_LEFT",
"last_allocation_status": "no_attempt"
},
"explanation" : "cannot allocate because 3 nodes have left the cluster..."
}
常见 unassigned.reason:
| reason | 说明 | 应急处理 |
|---|---|---|
NODE_LEFT |
持有该分片的节点离线 | 检查节点状态,尝试恢复节点 |
ALLOCATION_FAILED |
尝试分配但失败(通常是磁盘问题) | 检查磁盘空间 |
REPLICA_ADDED |
新建的副本等待分配 | 通常是短暂的,等待即可 |
CLUSTER_RECOVERED |
集群恢复中 | 等待恢复完成 |
DANGLING_INDEX_IMPORTED |
导入游离索引 | 检查 import 过程 |
INDEX_CREATED |
新索引等待分配 | 正常现象 |
3.2 三种最常见的 Red 应急场景
场景一:节点宕机导致主分片丢失
# 确认哪些节点离线
GET /_cat/nodes?v&h=name,ip,node.role,heap.percent,ram.percent
# 尝试重启离线节点(运维层面)
# 如果是永久性节点丢失,绝望方案:强制分配空主分片
# 警告:这会导致数据丢失!仅在确认无法恢复节点时使用
POST /_cluster/reroute
{
"commands": [
{
"allocate_empty_primary": {
"index" : "orders-2026",
"shard" : 2,
"node" : "node-3",
"accept_data_loss": true
}
}
]
}
场景二:磁盘满了
磁盘满了会导致分片无法分配,已有的分片也可能变为只读。
# 检查磁盘
GET /_cat/allocation?v
# 如果索引已变为只读
PUT /_all/_settings
{
"index.blocks.read_only_allow_delete": null
}
# 紧急扩容或删除数据
DELETE /old_index_name
场景三:分片损坏(corruption)
# 查看是否有损坏的分片
GET /_cluster/health?level=shards
# 如果确定分片损坏,force allocate 或从快照恢复
POST /_cluster/reroute
{
"commands": [
{
"allocate_stale_primary": {
"index" : "my_index",
"shard" : 0,
"node" : "node-2",
"accept_data_loss": true
}
}
]
}
3.3 reroute 常用命令
# 将未分配分片分配到指定节点
POST /_cluster/reroute
{
"commands": [
{
"allocate_replica": {
"index" : "my_index",
"shard" : 0,
"node" : "node-3"
}
}
]
}
# 将分片从一个节点迁移到另一个节点
POST /_cluster/reroute
{
"commands": [
{
"move": {
"index" : "my_index",
"shard" : 0,
"from_node" : "node-1",
"to_node" : "node-2"
}
}
]
}
# 取消未完成的分片分配
POST /_cluster/reroute?retry_failed=false
四、监控告警策略
不要等到用户报故障才看集群状态。 建议的告警规则:
| 状态 | 告警级别 | 条件 |
|---|---|---|
| Yellow | P2 - 警告 | 持续超过 5 分钟(给分片恢复留时间) |
| Red | P0 - 紧急 | 立即告警(1 分钟内未恢复) |
| 节点离线 | P1 - 严重 | 任意数据节点离线超过 2 分钟 |
| 磁盘使用 | P2 - 警告 | 超过 80%(预留操作空间) |
使用 Elasticsearch Watcher 或 Prometheus + Alertmanager 实现:
# Watcher 示例:Yellow 超过 5 分钟触发告警
PUT _watcher/watch/cluster_yellow_watch
{
"trigger": { "schedule": { "interval": "1m" } },
"input": {
"http": {
"request": {
"host": "localhost",
"port": 9200,
"path": "/_cluster/health",
"method": "GET"
}
}
},
"condition": {
"script": {
"source": "return ctx.payload.status == 'yellow' || ctx.payload.status == 'red'"
}
},
"actions": {
"log_alert": {
"logging": { "text": "Cluster status is {{ctx.payload.status}}" }
}
}
}
五、踩坑案例
案例: 某电商团队 3 节点集群,一台数据节点因磁盘满挂掉,集群变 Red。
运维同事发现后,手动调高水位线 + 清理日志,节点恢复后分片自动重新分配,5 分钟后变回 Green。但因为没配监控,从 Red 发现到处理完成已经过了 25 分钟——期间订单搜索功能完全不可用。
教训: Red 状态必须配置即时告警。5 分钟对于在线业务就是一次事故。
六、小结
| 颜色 | 行动 |
|---|---|
| Green | 保持,持续监控 |
| Yellow | 尽快修复(副本分配),防止升级为 Red |
| Red | 立即响应,先止血(reroute / 恢复节点),再找根因 |