前言
正常来讲,Elasticsearch 的集群状态status
属性应该显示为green
,但在 ES 的使用过程中,我们经常会遇到这么一个问题——集群状态显示为yellow
或red
。
为什么集群状态会显示不正常?
要回答这个问题,我们需要先回忆下status
字段的三种颜色各自代表的含义:
- green:所有的主分片和副本分片都正常运行
- yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行
- red:存在主分片未正常运行
通过回顾我们将得出一个结论:若集群状态显示为yellow
或red
,那么必定是因为——集群中存在分片未分配!
那么为什么会有分片没有分配?
可能的原因很多,在查阅大量文章后,我发现这或许是由以下问题引起的:
- 版本不一致
- 磁盘空间不足
- 已禁用分片分配
- 防火墙或 SELinux 问题
- 集群中分片数据已不存在
- 单节点集群的副本数设置非零
- 副本分片数过多而 ES 节点数不足
那么下面,本文将对以上问题进行详细描述并附带可行的解决方案。
源与解
版本不一致
若不同的节点上运行了不同版本的 ES,那么从较新版本到以前版本的分片复制将不起作用,因此最好保持 ES 的版本一致。
当然,若你确实需要升级 ES 的版本,也可以参考 ElasticSearch 官网——滚动升级。
磁盘空间不足
从 ES 官方文档——基于磁盘的分片分配[1]中得知:若启用了磁盘分配决策器,则在决定是否为节点分配新的分片或者主动将分片从该节点迁移之前,Elasticsearch 会考虑节点上的可用磁盘空间。
因此,若磁盘的空间超过了 ES 的默认配置,分片的分配将会存在一定限制,这些重要配置项包括:
cluster.routing.allocation.disk.threshold_enabled
:是否开启磁盘分配决策器,默认值 truecluster.routing.allocation.disk.watermark.low
:控制磁盘使用的低水位线,默认值为 85% ,这意味着一旦磁盘使用率超过 85% ,ES 将不会为该节点分配新的分片(该设置对新创建的索引的主分片没有影响,但是会阻止它们的副本被分配)cluster.routing.allocation.disk.watermark.high
:控制高水位线,默认为 90% ,这意味着若节点磁盘使用率超过 90% ,ES 会尝试将分片重新定位到另一个节点(该设置影响所有分片的分配,无论以前是否分配)cluster.info.update.interval
:ES 多久检查每个节点的磁盘用量的频率,默认值 30scluster.routing.allocation.disk.include_relocations
:默认值 true,说明略(暂未研究。。。)
因此,如果你使用的 ES 所在服务器磁盘超出了规定的限制,可能会导致分片无法分配。
为了排查分片未分配是否由于磁盘问题引起的,你可以通过以下两种方式输入对应命令来查看当前 ES 所在磁盘情况:
- 在浏览器:
http://ip:9200/_cat/allocation?v&pretty
- 在服务器:
curl -XGET 'http://localhost:9200/_cat/shards?v&pretty'
如果你的磁盘使用情况差不多是如下情况(disk.percent
超 90%),那么你不得不需要考虑扩充磁盘了:1
2
3
4shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
297 84mb 18.1gb 1.4gb 19.5gb 92 10.57.30.22 10.57.30.22 node-2
1 229.6kb 18gb 1.5gb 19.5gb 92 10.57.30.21 10.57.30.21 node-1
0 0b 18.6gb 983.4mb 19.5gb 95 10.57.30.23 10.57.30.23 node-3
扩展——调优
如果你的节点具有较大的磁盘容量,则 85% 的低水位置可能太低,此时可以相关 API 进行更改:
1 | curl -XPUT 'localhost:9200/_cluster/settings' -d |
如果你希望配置更改在集群重新启动时保持不变,请将transient
替换为persistent
,或更新配置文件中的这些值。
当然也可以选择使用字节值更新这些设置,但请务必记住 Elasticsearch 官方文档中的这一重要提示:百分比值是指已用磁盘空间,而字节值是指可用磁盘空间。
已禁用分片分配
在 ES 官网文档——集群级分片分配[1]的描述中,集群分片如何分配的设置是由cluster.routing.allocation.enable
属性进行控制的,其取值包括:
all
:允许分片分配所有类型的分片(默认值)primaries
:只允许主分片分配分片new_primaries
:只允许为新索引的主分片分配分片none
:不允许对任何索引的任何类型的分片进行分配
综上可知,默认情况下的 ES 集群是允许分片分配所有类型的分片,因此若cluster.routing.allocation.enable
属性被修改,分片有可能无法分配。
那么我们可以通过http://ip:9200/_cluster/settings
看一下该配置,默认情况下是这样的:1
2
3
4{
persistent: { },
transient: { }
}
但是,如果你禁用了分片分配(也许您进行了滚动重启并忘记了重新启用它),设置可能会是这样的:1
2
3
4
5
6
7
8
9
10
11
12{
persistent: { },
transient: {
cluster: {
routing: {
allocation: {
enable: "none"
}
}
}
}
}
此时你可以修改该配置,以重新启用分片自动分配到节点:1
2
3
4
5curl -XPUT 'localhost:9200/_cluster/settings' -d'
{ "transient":
{ "cluster.routing.allocation.enable" : "all"
}
}'
防火墙或 SELinux 问题
防火墙
由于 ES 集群间需要通过相关端口(默认9300
)进行通信交换数据(分片的分配也在其中),因此若防火墙开启了却未开放相关端口,此时分片是无法进行分配的。
为了规避该问题可考虑关闭防火墙或者开放对应端口。
SELinux
SELinux,即安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统,主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。
简单来讲,SELinux 是一款为了提高系统安全性的软件:对系统服务,文件权限,网络端口访问有极其严格的限制,
在 SELinux 中,若对一个文件没有正确安全上下文配置, 即使你是 root 用户,你也不一定能启动某服务。
这鬼东西咋用俺也不知道!如果不是专业运维还是把这东西关了吧。。。
集群中分片数据已不存在
有时索引的主分片 0 是未分配的。它可能在没有任何副本的节点上创建,并且在其他节点可以复制数据之前离开集群。
Master 在全局集群状态文件中检测到shard,但是无法在集群中找到分配的数据。
另一种可能性是节点在重新启动时可能遇到问题。通常,当一个节点重新连接到集群时,它会将有关其磁盘分片的信息转发给主节点,然后主节点将这些分片从“未分配”转换为“已分配/已启动”。但是由于某种原因(例如,节点的存储已被损坏)导致此进程失败时,分片可能保持未分配状态。
在这种情况下,可以进行如下处理:
- 尝试让原始节点恢复并重新加入集群
- 使用 Reroute API 强制重新分配分片
- 从备份数据中使用原始数据源重建索引丢失的数据
使用 Reroute API 强制重分配分片请求如下1
2
3
4
5
6curl -XPOST 'localhost:9200/_cluster/reroute' -d '
{ "commands" :
[ { "allocate" :
{ "index" : "constant-updates", "shard" : 0, "node": "<NODE_NAME>", "allow_primary": "true" }
}]
}'
副本分片数过多而 ES 节点数不足
此情况又可分为两种:
- (正常)集群启动过程中
- (异常)集群中存在节点宕机
集群启动过程中
在默认情况下,索引会被分配 5 个主分片和各自对应的 1 个副本分片,也就是 5 主加 5 副本。
若搭建的 ES 集群启动开始只有一个节点,此时查看集群的健康状况:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"cluster_name": "elasticsearch",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 5,
"active_shards": 5,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 3,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 50
}
从信息来看:集群 status
值为 yellow
,这代表所有的主分片都正常运行(集群可以正常服务所有请求),但是副本分片没有全部处在正常状态。
实际上,所有 5 个副本分片都是 unassigned
—— 都未被分配到任何节点。
因为在同一个节点上既保存原始数据又保存副本是没有意义的,因此,一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。
一般而言,该情况属于正常情况,基本是在集群刚启动的时候,由于当有新的节点加入后,这些副本分片将被分配,所以不用过于担心,但是也要注意分片的合理分配哦。
补充
当然,若你确实仅需搭建单节点集群进行测试,而又觉得yellow
状态看的不爽,也可以将所有的副本分片设置为零使status
变为green
:1
2
3
4
5
6curl -XPUT 'localhost:9200/_settings' -d '
{
"index" : {
"number_of_replicas" : 0
}
}'
集群中存在节点宕机
假设现在有 3 个 ES 节点,索引设置主分片数量为 10, 副本分片数为 2 。
忽地一下,一个 ES 节点宕机了。。。
在集群上,由于灾备原则(主分片和其对应副本不能同时在一个节点上),现在 ES 无法找到其他节点来存放第三个副本的分片,因此就会有 10 个未分配副本分片。
对于此问题,解决方案有以下两种:
- ① 增加 ES 节点数
- ② 减少副本分片数
1
2
3
4
5
6curl -XPUT 'localhost:9200/_settings' -d '
{
"index" : {
"number_of_replicas" : 2
}
}'
API 故障诊断
集群常见故障诊断手段通常为:通过检查集群的健康状态,是否有节点未加入或者脱离集
群,以及是否有异常状态的分片。可采取以下 API 完成对集群的故障诊断。
6.6.1 Cat APls:
Cat APl(常用)
_cat/indices?health=yellow&v=true
: 查看当前集群中的所有索引_cat/health?v=true
:查看健康状态_cat/nodeattrs
:查看节点属性_cat/nodes?K
:查看集群中的节点_cat/shards
: 查看集群中所有分片的分配情况
Cluster APls
_cluster/ allocation/explain
:可用于诊断分片未分配原因_cluster/health/<target>
:检查集群状态
参考
- ElasticSearch 官网——配置
- ElasticSearch 官网——集群重路由
- ElasticSearch 官网——集群级分片分配
- ElasticSearch 官网——基于磁盘的分片分配
- Stack Overflow——ElasticSearch: Unassigned Shards, how to fix?
文章信息
时间 | 说明 |
---|---|
2020-11-10 | 初版 |
2022-04-04 | 文字纠正 |