臭宝,满足您的需求,上大招,今天再分享一个我编写且非常好用处理Elasticsearch集群异常状态的脚本

-------------------------------------------------------

作者:尚雷
Oracle、PostgreSQL ACE

如喜欢文章内容,可关注我公众号:

-------------------------------------------------------


 

 

这篇文章给大家描述如果遇到生产Elasticsearch因有unassigned_shard的索引导致集群状态为red,引发应用无法正常写入Elasticsearch,MQ有挤压该如何处理。

集群状态集群状态为何会异常

我们知道Elasticsearch集群健康状态分为三种,分别是:

  • GREEN

  • YELLOW

  • RED

GREEN: 代表集群当前处于健康状态,说明其所有分片及副本都是可用的。此时,Elasticsearch集群的所有主分片和副本分片都已正常分配,集群可以正常对外提供服务。

YELLOW: 该种状态表示主分片可用,但副本分片不可用,该种情况表明Elasticsearch集群中所有主分片都已分配,但至少有一个副本分片未正常分配,该种状态下是不会有数据丢失的,也是可以对外提供搜索的,这种情况也经常会发生,但通常会持续时间比较短,通常会自动恢复,可以这么比喻YELLOW代表集群处于亚健康状态,如果调养好还能恢复正常。

RED: 如果集群状态为RED,表示Elasticsearch已处于不健康状态,集群此时可能难以正常对外提供服务,存在不可用的主分片,虽然查询时可以查询到部分数据,但已经影响到正常的索引读写,此时需要得到及时处理。当Elasticsearch状态为RED,意味部分索引缺失数据,无法获取到全部数据。

如何查询集群状态

可通过如下命令查询当前集群状态。

命令方式

GET /_cluster/health?pretty
-- 若状态为正常,则查询到的信息类似如下:
{
  "cluster_name" : "es-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 10,
  "number_of_data_nodes" : 10,
  "active_primary_shards" : 13814,
  "active_shards" : 15874,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "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" : 100.0
}

当集群状态为RED,可通过命令进一步分析有哪些索引异常,查询的方式有多种,可通过命令或者图形方式进行查询。

命令查询

GET /_cat/indices?v
-- 查询结果类似如下
health status index                                                          uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   xxxx_xxx_r_2024-06-1w                                         Et76c4q0So6h7lB0DoeNmw   1   0     420324           28    221.5mb        221.5mb
green  open   xxxx_app_log_2020-01-31                                         JnhjrFviQSClnRy6HbTKbA   3   0          1            0     37.7kb         3
-- health若为GREEN表示索引分片正常

图片

图形查询通过kibana可通过管理界面进行查询,打开kibana管理界面,依次打开Stack Management-->索引管理,可查看当前各索引分片状态,如下所示,此时展示部分索引分片状态异常,集群状态为RED。

图形方式

通过kibana或其它第三方监控工具,可查看当前Elasticsearch集群状态,如下所示通过kibana查询到的集群状态。

图片

上图表示此时集群处于健康状态,若集群不正常,会提示运行状况为YELLOW或RED。

处理办法如何处理索引异常状态

1为何要处理异常索引

当索引分片异常,导致该索引状态为RED,此时整个Elasticsearch集群状态为RED,难以正常对外提供完整的查询。在我所负责的Elasticsearch生产集群环境中,当集群处于该种状态,MQ无法正常写入ES中这些状态异常的索引,造成大量消息队列挤压,业务人员无法正常查询到业务数据。

2如何处理异常状态索引

初期,当收到Elasticsearch告警提示集群状态异常,信息提示:Cluster status is RED!!!!,通常为了快速处理问题,通常会通过kibana或者命令查询到哪些索引状态异常,然后通过关闭/打开索引快速进行处理。后期,发现这种方式也比较慢,特别是当遇到业务繁忙,kibana打开又比较慢,通常会花较长时间去处理,所以我就通过编写脚本在Elasticsearch服务器上进行处理,初期编写的脚步如下:

#!/bin/bash
ES_HOST="xxx.xxx.xxx.xxx"
ES_PORT="9200"
ES_USER="elastic"
ES_PASS="xxxx"

# 查询所有状态为red的索引
echo "查询所有状态为red的索引..."
RED_INDICES=$(curl -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/_cat/indices?health=red&h=index" | tr '\n' ' ')

if [ -z "$RED_INDICES" ]; then
    echo "没有发现状态为red的索引。"
else
    echo "下列索引状态为red:"
    echo "$RED_INDICES" | tr ' ' '\n'

    # 关闭所有red状态的索引
    for index in $RED_INDICES; do
      echo "正在关闭索引: $index"
      curl -X POST -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/$index/_close" -H "Content-Type: application/json"
    done

    # 等待一段时间后重新打开索引
    echo "等待一段时间后重新打开索引..."
    sleep 30  # 这里的30只是示例,具体时间需要根据实际情况调整

    for index in $RED_INDICES; do
      echo "正在打开索引: $index"
      curl -X POST -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/$index/_open" -H "Content-Type: application/json"
    done

    # 再次检查仍然为red状态的索引
    echo "检查索引状态..."
    sleep 30  # 给ES一些时间来更新状态
    NEW_RED_INDICES=$(curl -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/_cat/indices?health=red&h=index" | tr '\n' ' ')
    if [ -z "$NEW_RED_INDICES" ]; then
        echo "没有索引处于red状态。"
    else
        echo "以下索引仍处于red状态:"
        echo "$NEW_RED_INDICES" | tr ' ' '\n'
    fi
fi

当再次收到Elasticsearch提示索引异常状态告警时,我会登录服务器手工执行该脚本去查询异常索引,然后将其关闭和打开。

但在运维过程后期发现一些问题,特别是当集群节点宕,此时集群各节点索引reblance未平衡结束,此时会有大量索引状态为RED,该状态下执行这个脚本,会导致需要遍历查询大量异常状态索引,然后逐个对其关闭和打开,会非常耗时。

另外也遇到过当出现多个索引状态异常,在关闭/打开这些索引时,由于Kibana的刷新频率,在分页较多的情况下,可能这些异常索引不会在首页展示,会在其它分页中,导致应用无法写入这些关闭的索引。

后期,当我们优化并升级了Elasticsearch的JDK,Elasticsearch出现节点宕的频率已经比较低,而且恢复速度相对提升了很高,为了更好的处理异常索引,我对上述脚本进行了优化,添加了判断条件,当异常索引数量较多,比如大于4个,此时会先不执行该脚本,待异常索引数量少于4个,会对其进行处理,为了降低手工处理时间,我将该脚本添加到crontab定时任务中去执行,每隔两分钟会执行该脚本,通过近期观察,运行效果良好,修改后的脚步如下:

#!/bin/bash
ES_HOST="xxx.xxx.xxx.xxx"
ES_PORT="9200"
ES_USER="elastic"
ES_PASS="xxxx"
LOG_FILE="/home/esuser/scripts/es_indices_check.log"

# 添加日志时间戳
echo "执行时间: $(date)" >> $LOG_FILE

# 查询所有状态为red的索引
echo "查询所有状态为red的索引..." >> $LOG_FILE
RED_INDICES=$(curl -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/_cat/indices?health=red&h=index" | tr '\n' ' ')

if [ -z "$RED_INDICES" ]; then
    echo "没有发现状态为red的索引。" >> $LOG_FILE
else
    # 统计red状态索引的数量
    RED_INDICES_COUNT=$(echo "$RED_INDICES" | wc -w)

    if [ "$RED_INDICES_COUNT" -gt 4 ]; then
        echo "状态为red的索引数量超过4个,请手工处理。" >> $LOG_FILE
        echo "下列索引状态为red:" >> $LOG_FILE
        echo "$RED_INDICES" | tr ' ' '\n' >> $LOG_FILE
    else
        echo "下列索引状态为red:" >> $LOG_FILE
        echo "$RED_INDICES" | tr ' ' '\n' >> $LOG_FILE

        # 关闭所有red状态的索引
        for index in $RED_INDICES; do
          echo "正在关闭索引: $index" >> $LOG_FILE
          curl -X POST -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/$index/_close" -H "Content-Type: application/json"
        done

        # 等待一段时间后重新打开索引
        echo "等待一段时间后重新打开索引..." >> $LOG_FILE
        sleep 30  # 这里的30只是示例,具体时间需要根据实际情况调整

        for index in $RED_INDICES; do
          echo "正在打开索引: $index" >> $LOG_FILE
          curl -X POST -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/$index/_open" -H "Content-Type: application/json"
        done

        # 再次检查仍然为red状态的索引
        echo "检查索引状态..." >> $LOG_FILE
        sleep 30  # 给ES一些时间来更新状态
        NEW_RED_INDICES=$(curl -s -u $ES_USER:$ES_PASS "http://$ES_HOST:$ES_PORT/_cat/indices?health=red&h=index" | tr '\n' ' ')
        if [ -z "$NEW_RED_INDICES" ]; then
            echo "没有索引处于red状态。" >> $LOG_FILE
        else
            echo "以下索引仍处于red状态:" >> $LOG_FILE
            echo "$NEW_RED_INDICES" | tr ' ' '\n' >> $LOG_FILE
        fi
    fi
fi

--- 然后将该脚本放入定时任务中执行
*/2 * * * * /home/esuser/scripts/check_red.sh

执行结果会写入/home/esuser/scripts/es_indices_check.log日志。同时我又编写了另一个脚本,会定期对该日志文件进行清理防止文件过大,清理脚本如下:

#!/bin/bash
LOG_FILE="/home/esuser/scripts/es_indices_check.log"
# 清理日志文件
> $LOG_FILE
echo "日志文件已清理于: $(date)" >> $LOG_FILE

--- 我也将该脚本放入定时任务中执行,如下所示:
0 0 */2 * * /home/esuser/scripts/clean_log.sh

以上是一个处理示例

希望你也能提供更好的处理方法

(如果有更好方法希望告诉我)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尚雷5580

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值