elasticsearch集群健康状态解析与高频异常场景分析

2024-04-12 10:02:51 浏览数 (1)

一.elasticsearch集群的三种健康状态

  1. Green(绿色):表示集群处于良好状态。所有的主分片和副本分片都正常分配在集群中的节点上,并且集群的功能正常运行。
  2. Yellow(黄色):表示集群处于部分可用状态。所有的主分片都正常分配在集群中的节点上,但是部分副本分片可能由于某种原因未能分配或者未能正常运行。
  3. Red(红色):表示集群处于不可用状态。至少一个主分片未能分配在集群中的节点上,导致相关索引不可用。

elasticsearch集群的健康状态是通过监控和评估集群中的主分片和副本分片的分配情况来确定的。通过查看健康状态能够直观的获取出集群当前的运行状态,分片状态等信息。

二.如何快速获取集群健康状态

1.通过_cluster API进行获取

代码语言:javascript复制
GET /_cluster/health/<target>

当集群负载较高时,通过API请求elasticsearch集群健康状态时可能会出现超时而无法获取到集群健康状态。我们则可以在该API中指定超时参数来延长请求的时间。以便获取到集群健康状态。

该API目前支持以下参数:

level:我们可以指定获取健康状态的级别,可以是cluster,indices,shards;提供了完整的粒度健康状态级别。默认值为cluster。

local:值为true/flase。默认值为false。当指定为true时,表示仅从本地节点获取检索信息。默认值为false时,表示从主节点获取返回信息。

master_timeout:请求连接至主节点的超时时间,默认值为30s,如果出现超时则返回请求失败的超时信息。

timeout:请求等待响应的超时时间。默认值为30s,如果超出超时时间范围则返回请求失败的超时时间。

wait_for_active_shards:指定要等待多少活动分片,等待集群中所有分片都处于activity状态或不等待的数字,默认值为0.

wait_for_status:可以用来指定等待集群的状态,参数值有:green,yellow,red。

当我们使用默认API执行后,会得到以下返回信息:

返回体解读:

代码语言:json复制
{
  "cluster_name" : "testcluster",#集群名称
  "status" : "yellow",#集群健康状态
  "timed_out" : false,#是否超时
  "number_of_nodes" : 1,#集群节点数
  "number_of_data_nodes" : 1,#集群数据节点数
  "active_primary_shards" : 1,#活跃主分片数
  "active_shards" : 1,#活跃分片数
  "relocating_shards" : 0,#正在搬迁分片数
  "initializing_shards" : 0,#正在初始化分片数
  "unassigned_shards" : 1,#无法分配的分片的数量
  "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.0#活跃分片数占总分片数的百分比
}

2.通过_cat API 进行获取

代码语言:javascript复制
GET /_cat/health

执行该API后可以获取到以下返回信息:

代码语言:javascript复制
epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1475871424 16:17:04  elasticsearch green           1         1      1   1    0    0        0             0                  -                100.0%

该API也能够达到相同效果。只是支持的请求参数相较于_cluster更少一些。

三.集群健康状态异常问题高频场景分析

场景1:集群分片数达到上限,导致新建索引的分片无法被分配引起集群健康状态变化。

异常日志多为以下内容:

代码语言:javascript复制
[indices:admin/create]]; nested: IllegalArgumentException[Validation Failed: 1: this action would add [2] total shards, but this cluster currently has [4000]/[4000] maximum shards open;];

原因:在elasticsearch集群中,对于每一个节点上能容纳的分片总数都有约束。当节点上的分片总数达到上限后,就会提示新建索引的分片无法被分配到节点上。分片上限策略主要是为了防止分片被过度分配。因为每一个索引分片都会消耗集群的CPU与内存资源。

大多数分片都会包含多个segement。而elasticsearch会将segment元数据保存在JVM堆内存中。伴随着分片数的增长,存储于JVM堆内存中的segment元数据也会逐渐增长,进一步加剧JVM堆内存的消耗。此时则需要通过对索引进行merge,将分片中的小segment合并为大segement,以此来提高对数据的搜索能力并降低JVM堆内存的消耗。

解决办法:

代码语言:javascript复制
PUT _cluster/settings
{
    "persistent":{
        "cluster":{
            "max_shards_per_node":10000 #根据实际需要进行调整即可
        }
    },
    "transient":{
        "cluster":{
            "max_shards_per_node":10000
        }
    }
}

建议:1GB堆内存支持20-30个分片比较合理;

场景2:分片损坏导致集群健康状态异常

异常日志多为以下内容:

代码语言:javascript复制
index/shard/recovery/prepare_translog] Caused by: org.elasticsearch.index.translog.TranslogCorruptedException: expected shard UUID [57 55 4d 6b 4c 4e 77 53 51 49 2d 31 6a 6a 75 5f 74 70 75 70 35 67] but got: [54 35 69 49 6d 43 70 63 53 61 75 62 4f 65 65 30 6e 6b 6b 57 6c 51] this translog file belongs to a different translog. path:/data1/containers/xxxxxx/es/data/nodes/0/indices/IB9qEdKERzyvWbepTwj4mA/1/translog/translog-1001.tlog

原因:

  • 由于短暂的机器故障或文件系统异常造成分片损坏,无法被分配至节点上。
  • 由于物理文件系统损坏或其他不可抗力原因,造成translog文件异常,进而导致分片损坏。

当分片异常时,其相应的主分片也会异常。此时则会影响到集群索引的读写业务。

解决办法:

  • 重新尝试分片分配
代码语言:javascript复制
#通过调用_close,_open API 强制对分片进行分配。
POST /twitter/_close?pretty
POST /twitter/_open?pretty
  • 丢弃分片
代码语言:javascript复制
#丢弃分片动作为分片恢复手段中的下下策。不到万不得已不建议使用。一旦使用就代表着舍弃该分片上的数据。
#使用之前需要慎重评估相关影响。
POST /_cluster/reroute?pretty
{
    "commands" : [
        {
          "allocate_empty_primary" : {
              "index" : "{索引名称}", 
              "shard" : "{分片ID}",
              "node" : "{节点名称}",
              "accept_data_loss": true
          }
        }
    ]
}

场景3:分片分配超出最大重试次数,导致分片没有被分配至节点上,引起集群健康状态变化

异常日志多为以下内容:

代码语言:javascript复制
shard has exceeded the maximum number of retries [5]

原因:大部分时候都是由于节点压力短时间内过大,出现过短暂的离线,导致分片分配超出了最大重试次数。

解决办法:这种情况下,我们在集群负载降低后手动触发分片分配任务即可。

代码语言:javascript复制
POST /_cluster/reroute?retry_failed=true

retry_failed(可选,布尔值)如果为true,则重试由于后续分配失败过多而阻塞的分片的分配。

场景4:由于节点频繁离线导致集群健康状态变化

异常日志多为以下内容:

代码语言:javascript复制
node-left[{bbs-tagdata-es-prd-050201-cvm}{ImUkdwUSRougiS8jdGlh3A}{IuYyXPRWQIa5HqqQz0m5Vw}{10.46.50.201}{10.46.50.201:9300}{ilr}{ml.machine_memory=33565073408, ml.max_open_jobs=20, xpack.installed=true, transform.node=false} reason: disconnected], term: 40, version: 9596, delta: removed {{bbs-tagdata-es-prd-050201-cvm}{ImUkdwUSRougiS8jdGlh3A}{IuYyXPRWQIa5HqqQz0m5Vw}{10.46.50.201}{10.46.50.201:9300}{ilr}{ml.machine_memory=33565073408, ml.max_open_jobs=20, xpack.installed=true, transform.node=false}}

原因:通过日志分析,我们可以发现日志中有频繁的left/join信息。代表这当前节点频繁的在脱离后加入集群。每一次left/join都会引起分片的初始化与恢复。导致集群长时间处于分片恢复状态,造成集群健康状态异常。如果是冷热集群可能还会涉及分片搬迁任务。

例如:

  • 由于索引分片规划不合理导致在对索引进行大量读写请求时压力主要聚集于部分节点。造成节点压力过大,发生elasticsearch服务重启,引起节点离线。一般发生重启,我们可以在日志中发现"restart"等关键字.
  • 节点上分片过多。超出节点负载能力。数据节点与主节点通信超时,导致该数据节点被主节点临时踢出集群,引起集群健康状态变化。
  • 物理机发生重启,导致短时间内集群健康状态异常。
  • 节点压力过大,集群出现熔断,导致节点频繁离线。引起集群健康状态变化。

解决办法:

代码语言:javascript复制
PUT _cluster/settings 
{
  "persistent" : {
  "discovery.find_peers_interval": "30s"
  },
  "transient" : {
  "discovery.find_peers_interval": "30s"
  }
}

在7.10.x以后得elasticsearch版本中,可以通过调整节点发现的时长来一定程度上规避由于超时引起的节点被踢出集群的情况。从稳定性上来分析,合理的规划索引,充分利用集群的资源才能够从根本上解决该问题。

分析思路:

① CPU使用过高,load持续打满情况

需要结合机架监控,集群监控,分析集群当前业务的实际情况与与集群状态,索引分片配置等。可以使用GET _tasksAPI来确认一下集群当前主要的任务。进而明确导致CPU使用率过高的原因。然后引导用户进行节点规格升级等操作。

② JVM堆内存使用率过高情况

Case1:检查集群分片数,对应集群规格,判断一下当前集群是否能够承载现有分片。如果无法承载,需要引导用户进行分片删除降低负载与数据节点规格升级。

Case2:结合集群日志与机架监控,确认集群熔断的具体原因。如果是读写引起的熔断。可以先尝试开启部分堆外内存空间,看看是否可以缓解,内存压力。结合实际情况暂停短时间的业务访问,让集群恢复。根据集群实际状况,来排查是否需要升配与扩容。

场景5:磁盘文件系统只读,导致分片无法分配,引起集群健康状态变化

异常日志多为以下内容:

代码语言:javascript复制
tmp: Read-only file system

原因:集群长时间大量写入的情况下会小概率发生Linux文件系统只读的情况。

解决办法:需要在CVM实例上使用fsck命令检查并修复文件系统,解除只读状态。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞