ElasticSearch集群灾难:别放弃,也许能再抢救一下 | 京东云技术团队

news2024/10/2 10:29:41

1 前言

Elasticsearch作为一个分布式搜索引擎,自身是高可用的;但也架不住一些特殊情况的发生,如:

  • 集群超过半数的master节点丢失,ES的节点无法形成一个集群,进而导致集群不可用;

  • 索引shard的文件损坏,分片无法被正常恢复,进而导致索引无法正常提供服务

  • 本地盘节点,多数据节点故障,旧节点无法再次加入集群,数据丢失

针对上述的情况,今天来聊一聊相关的解决方案。

2 基础知识

2.1 集群经典架构

在聊解决方案之前,首先来看一看ES集群层面的基本知识,es的集群组成通常如图1-1所示es集群角色.png

图 1-1 es常用集群架构

如图1-1所示,为生产环境es集群的经典架构,主要由专有主节点、专有协调节点和数据节点组成:

  • 专有主节点(Master-eligible node): 具有master角色的节点,这使其有资格被选为主节点,只存储集群元信息包含cluster、index、shard级别的元数据;该种角色节点被选举为master之后,将作为整个ES集群的大脑,负责维护集群层面的元信息,创建删除索引等工作。该种节点的个数必须为奇数,通常我们固定为3个,如果该类节点丢失半数,es集群将无法维持es节点形成一个集群。

  • 专有协调节点(网关节点): 该种节点不具有任何角色,仅仅用来处理es请求;比如(1)将写请求的数据归类转发到数据所属的节点(2)查询请求的二次聚合计算。通常我们也会给该类节点保留ingest角色,ingest的主要作用是对数据进行预处理;比如:字段重命名、给数据文档打上指纹和清洗数据等功能主要通过pipeline能力进行处理

  • 数据节点(Data node): 存储数据和集群元信息,执行与数据相关的操作,如CRUD、搜索和聚合。在数据节点上打上不同的属性,可以使其成为hot、warm、cold数据节点,在es7.9版本之后配置略有不同,但是原理基本不变。

如果没有显示设置节点角色,es的每个节点都会含有以上三种角色。除此之后还有Remote-eligible node、ml-node和Transform nodes等角色需要显示的配置,节点才会有该角色。

2.2 集群元信息

集群完全启动主要包含选举主节点、元信息、主分片、数据恢复等重要阶段;如图2-1所示[1]。

5211704611687_.pic.jpg

图 2-1 es集群启动流程

主节点选举的过程,不是本文的重点,而是集群元信息的选举。被选举出的master和集群元信息新旧程度没有关系;master节点被选举出来之后,它所要完成的第一个任务,即是选举集群元信息。

(1)Master选举成功之后,判断其持有的集群状态中是否存在STATE_NOT_RECOVERED_BLOCK,如果不存在,则说明元数据已
经恢复,跳过gateway恢复过程,否则等待。org.elasticsearch.gateway.GatewayService#clusterChanged

//跳过元数据恢复
if (state.blocks().hasGlobalBlock(STATE_NOT_RECOVERED_BLOCK) == false) {
            // already recovered
            return;
 }
 //此处省略部分代码。
 //进入gateway恢复过程   
performStateRecovery(enforceRecoverAfterTime, reason); 

(2)Master从各个节点主动获取元数据信息。org.elasticsearch.gateway.Gateway#performStateRecovery

# 获取元信息核心代码
 final String[] nodesIds = clusterService.state().nodes().getMasterNodes().keys().toArray(String.class);
        logger.trace("performing state recovery from {}", Arrays.toString(nodesIds));
        final TransportNodesListGatewayMetaState.NodesGatewayMetaState nodesState = listGatewayMetaState.list(nodesIds, null).actionGet();

(3)从获取的元数据信息中选择版本号最大的作为最新元数据;元信息包括集群级、索引级。

## org.elasticsearch.gateway.Gateway#performStateRecovery

    public void performStateRecovery(final GatewayStateRecoveredListener listener) throws GatewayException {
# 省略若干行代码

## 进入allocation阶段;
## final Gateway.GatewayStateRecoveredListener recoveryListener = new GatewayRecoveryListener();
## listener为 GatewayStateRecoveredListener   
 listener.onSuccess(builder.build());    
}

(4)两者确定之后,调用allocation模块的reroute,对未分配 的分片执行分配,主分片分配过程中会异步获取各个shard级别元数据。

#主要实现方法为如下方法   
#org.elasticsearch.gateway.GatewayService.GatewayRecoveryListener#onSuccess
## 主要工作是构建集群状态(ClusterState),其中的内容路由表 依赖allocation模块协助完成,调用 allocationService.reroute 进 入下一阶段:异步执行分片层元数据的恢复,以及分片分配。updateTask线程结束.
   

ES中存储的数据:(1)state元数据信息;(2)index Lucene生成的索引文件;(3)translog事务日志。
元数据信息

  1. nodes/0/_state/*.st,集群层面元信息MetaData(clusterUUID 、 settings 、templates等);

  2. nodes/0/indices/{index_uuid}/_state/*.st,索引层面元信息IndexMetaData( numberOfShards 、mappings等);

  3. nodes/0/indices/{index_uuid}/0/_state/*.st,分片层面元信息ShardStateMetaData(version 、indexUUID、primary等)。

上述信息被持久化到磁盘:持久化的state不包括某个分片存在于哪个节点这种内容路由信息,集群完全重启时,依靠gateway的recovery过程重建RoutingTable和RoutingNode。当读取某个文档时, 根据路由算法确定目的分片后,再从RoutingTable中查找分片位于哪个节点,然后将请求转发到目的节点[1]。

⚠️ 注意:在es7.0.0之后es的元信息存储方式发生变化;
es7.0.0之后元信息存储改使用lucene的方式存储,见pr50928 Move metadata storage to Lucene)

7.10.2 专有主节点,集群元数据

./
|-- _state
|   |-- _39h.cfe
|   |-- _39h.cfs
|   |-- _39h.si
|   |-- node-0.st
|   |-- segments_50d
|   `-- write.lock
`-- node.lock

6.8.13 专有主节点,集群元数据

./
|-- _state
|   |-- global-230.st
|   `-- node-2.st
|-- indices
|   |-- -hiy4JnoRfqUJHTJoNUt4Q
|   |   `-- _state
|   |       `-- state-4.st
|   `-- ylJKVlqISGOi8EkpxHE_2A
|       `-- _state
|           `-- state-6.st
`-- node.lock

3 灾难场景与处理方法

3.1 master节点丢失

⚠️ 注意本文所述的master节点个数,假设前提均为3个

场景1 master节点丢失过半

master节点是控制整个集群;当该种节点角色丢失过半,由于集群中投票节点永远不可能达到quorum无法选主,将无法维持es节点形成一个集群;虽然集群无法形成一个集群,但所仍幸master-eligible节点存活,我们可以使用如下手段进行处理。

es7.0.0版本之前

1 修改剩余节点的elasticsearch.yaml配置如下,修改quorum的个数,然后启动剩余的节点,形成一个新的集群;

discovery.zen.minimum_master_nodes: 1
discovery.zen.ping.unicast.hosts:
- masters-0

2 重建补充之前丢失的master-eligible节点,加入集群之后.
3 将集群配置修改为旧的配置,再逐一重启下集群中的节点,先从master-eligible开始.

es7.0.0(包含)版本之后.

在es7.0.0版本之后,由于es修改集群的启动配置,新增配置discovery.seed_hosts和cluster.initial_master_nodes;es集群第一次启动时称为bootstrap,该过程将配置文件中的cluster.initial_master_node作为初始的投票节点Voting configurations,投票节点具有选举master和commit cluster state的权利,超过半数以上同意即投票成功。如果在集群健康的场景下,我们需要下线超过半数的master-eligible;则必须首先使用投票配置排除API从投票配置中排除受影响的节点。

POST _cluster/voting_config_exclusions?node_names={node_names}
POST _cluster/voting_config_exclusions?node_ids={node_ids}
DELETE _cluster/voting_config_exclusions

但是如果丢失的master节点超过半数,则可以使用新的集群处理工具elasticsearch-node unsafe-bootstrappr37696和elasticsearch-node detach-clusterpr37979

面对丢失半数master-eligible,es7.0.0(包含)版本之后的处理步骤如下:
1 使用bin/elasticsearch-node unsafe-bootstrap命令让唯一主节点以不安全的方式改写投票节点,就像重新进行bootstrap一样,自己使用持久化的cluster state形成一个新集群
2 其他数据节点无法加入新集群因为UUID不同(es使用UUID作为节点和集群的唯一表示,每个节点都会持久化当前集群的UUID),使用bin/elasticsearch-node detach-cluster命令让节点离开之前的集群
3 启动数据节点和新的master-eligible节点(如下补充两个新的master-eligible),他会加入新集群中

cluster.initial_master_nodes:
- {master-0}
- {new-master-1}
- {new-master-2}
discovery.seed_hosts:
- {master-ip-0}
- {new-master-ip-1}
- {new-master-ip-2}

场景2 master节点全部丢失

es7.0.0版本之前

1 关闭 security 功能(如果开启了, 最好先关闭security插件功能):
1.1 因为新启动的master节点, 没有数据节点(如果只配置了一个master的角色), security插件的初始化无法完成, 各类接口不好调用
1.2 如果给新启动的master节点, 配置了master and data角色, 则security插件会初始化成功. 会插入index, 但是这个index会和原来的data节点上保存的冲突. 不知道怎么解.
elastic官方xpack-security;关闭鉴权:xpack.security.enabled:false
2 启动足够的新master-eligible节点形成一个新集群.

discovery.zen.minimum_master_nodes: 2
discovery.zen.ping.unicast.hosts:
- {new-masters-1}
- {new-masters-2}
- {new-masters-3}

3 修改数据节点的为新master的地址,并且删除掉节点上的_state(因为新集群的cluster UUID不一致),同上
4 启动数据节点,数据被恢复加入到集群

es7.0.0(包含)版本之后

已经没有cluster state了,唯一的希望是数据节点上的index数据;恢复方式借助elasticsearch-node工具

1 关闭security功能(如果开启了, 最好先关闭security插件功能),原因同上
2 启动足够的新master-eligible节点形成一个新集群

cluster.initial_master_nodes:
- {new-master-0}
- {new-master-1}
- {new-master-2}
discovery.seed_hosts:
- {new-master-ip-0}
- {new-master-ip-1}
- {new-master-ip-2}

3bin/elasticsearch-node detach-cluster命令让数据节点离开之前的集群

./bin/elasticsearch-node detach-cluster
------------------------------------------------------------------------

    WARNING: Elasticsearch MUST be stopped before running this tool.

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

You should only run this tool if you have permanently lost all of the
master-eligible nodes in this cluster and you cannot restore the cluster
from a snapshot, or you have already unsafely bootstrapped a new cluster
by running `elasticsearch-node unsafe-bootstrap` on a master-eligible
node that belonged to the same cluster as this node. This tool can cause
arbitrary data loss and its use should be your last resort.

Do you want to proceed?

Confirm [y/N] y
Node was successfully detached from the cluster

4查询dangling索引,GET /_dangling, 改api 引入es7.9版本于pr58176
5 启动数据节点并使用Import dangling indexAPI将index数据import到cluster state中(官方推荐,es7.9版本之后). 或者 配置gateway.auto_import_dangling_indices: true引入于es7.6版本pr49174(es7.6.0-7.9.0可用该配置,在7.6版本之前不需要配置默认加载dangling索引)并启动数据节点

POST /_dangling/{index-uuid}?accept_data_loss=true

6 导入完成之后,索引recovery之后即可进行读写

注意

Q1: 为什么7.6.0之后需要配置,才能处理悬空索引(dangling index)才能让数据加入新集群,7.6.0之后没有悬空索引吗?
A1: 其实也是有的,只不过在es2版本将配置移除(对应pr10016),默认自动加载dangling index(es2.0-es7.6); 具体实现于org.elasticsearch.gateway.DanglingIndicesState#processDanglingIndiceses7.6再次引入dangling配置,es7.9引入dangling index rest api

Q2: 什么是 dangling 索引?
A2: 当一个节点加入集群时,如果发现存储在其本地数据目录中的任何分片(shard)不存在于集群中,将认为这些分片属于“悬空”索引。悬空索引产生的场景(1)在 Elasticsearch 节点离线时删除了多个cluster.indices.tombstones.size索引,节点再次加入集群集群 (2)master节点丢失,数据节点重新加入新的集群等

3.2 数据节点故障

数据节点灾难故障之后,无法恢复加入集群;可将数据物理复制到新的节点,然后按照master节点丢失的方式,将数据节点加入集群即可。

3.3 分片不能够自动分配

查看索引分片为什么无法分配,POST _cluster/allocation/explain

3.3.1 分片正常

如果分片数据正常,那么我们可以尝试重试分配分片任务;POST _cluster/reroute?retry_failed

获取索引的shard在那些节点上,使用_shard_stores api

GET indexName1/_shard_stores

使用cluster reroute重新分配

# 尝试分配副本 
POST /_cluster/reroute
{
  "commands": [
    {
      "allocate_replica": {
        "index": "{indexName1}",
        "shard": {shardId},
        "node": "{nodes-9}"
      }
    }
  ]
}

如果是主分片无法分配,可以尝试如下命令进行分配

POST /_cluster/reroute
{
  "commands": [
    {
      "allocate_stale_primary": {
        "index": "{indexName1}",
        "shard": {shardId},
        "node": {nodes-9},
        "accept_data_loss": true
      }
    }
  ]
}

如果主分片确实是无法分配,只能选择丢失该分片的数据,分配一个空的主分片

POST /_cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "{indexName1}",
        "shard": {shardId},
        "node": "{nodes-9}",
        "accept_data_loss": true
      }
    }
  ]
}

es5.0版本之前参考; https://www.elastic.co/guide/en/elasticsearch/reference/2.4/cluster-reroute.html

3.3.2 分片数据损坏

shard corrupted

错误参考Corrupted elastic index

shard-tooles6.5版本引入,该操作需要stop节点
elasticsearch-shard 工具es6.5版本引入pr33848
elasticsearch-shard remove-corrupted-data 的 es7.0.0引入pr32281

bin/elasticsearch-shard remove-corrupted-data --index {indexName} --shard-id {shardId}
## 示列:修复索引twitter的0号分片
bin/elasticsearch-shard remove-corrupted-data --index twitter --shard-id 0

## 如果--index和--shard-id换成索引分片目录参数--dir,则直接修复data和translog
bin/elasticsearch-shard remove-corrupted-data --dir /var/lib/elasticsearchdata/nodes/0/indices/P45vf_YQRhqjfwLMUvSqDw/0

修复完成之后,启动节点,如果分片不能够自动分配,使用reroute命令进行shard分片

POST /_cluster/reroute{
  "commands":[
    {
      "allocate_stale_primary":{
        "index":"index42",
        "shard":0,
        "node":"node-1",
        "accept_data_loss":false
      }
    }
  ]}

5版本之前可以通过索引级别配置,进行修复
index.shard.check_on_startup: fix ,该配置在es6.5版本移除pr32279

translog 损坏

修复translog操作,需要stop节点。

修复工具 elasticsearch-translog es5.0.0 引入pr19342
elasticsearch-shard remove-corrupted-data translog的 es7.4.1开始引入,pr47866elasticsearch-shard 可以直接清除translog,也可以像上文中指定–dir那样进行修复translog

bin/elasticsearch-shard remove-corrupted-data --index  --shard-id   --truncate-clean-translog
## 示列:修复索引twitter的0号分片
bin/elasticsearch-shard remove-corrupted-data --index twitter --shard-id 0 --truncate-clean-translog

清除完成之后使用cluster reroute 进行恢复

5版本之前可以通过索引级别配置,进行修复
index.shard.check_on_startup: fix ,该配置在es6.5版本移除pr32279

segments_N文件丢失

该种场景的文件损坏是最难修复的;官方还未提供工具,我们正在自己调研中

4 参考

[1]elasticsearch集群启动流程
[2]https://www.elastic.co/guide/en/elasticsearch/reference/7.9/dangling-indices-list.html
[3]https://www.elastic.co/guide/en/elasticsearch/reference/7.10/node-tool.html

作者:京东科技 杨松柏

来源:京东云开发者社区 转载请注明来源

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1402318.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蔚来卖一辆车亏20万,去年前三季度巨亏153亿

作为曾经的造车新势力“老大哥”蔚来,一边发布全新旗舰车型ET9预售价80万引争议,一边交付量在新势力垫底;更加“雪上加霜”的是,业绩亏损继续扩大。 「不二研究」据蔚来汽车三季报发现:今年三季度,蔚来净亏…

PyTorch深度学习实战(31)——生成对抗网络(Generative Adversarial Network, GAN)

PyTorch深度学习实战(31)——生成对抗网络 0. 前言1. GAN2. GAN 模型分析3. 利用 GAN 模型生成手写数字小结系列链接 0. 前言 生成对抗网络 (Generative Adversarial Networks, GAN) 是一种由两个相互竞争的神经网络组成的深度学习模型,它由…

基于taro搭建小程序多项目框架,记重点了!!!

前言 为什么需要这样一个框架,以及这个框架带来的好处是什么? 从字面意思上理解:该框架可以用来同时管理多个小程序,并且可以抽离公用组件或业务逻辑供各个小程序使用。当你工作中面临这种同时维护多个小程序的业务场景时&#…

react umi/max 页签(react-activation)

思路:通过react-activation实现页面缓存,通过umi-plugin-keep-alive将react-activation注入umi框架,封装页签组件最后通过路由的wrappers属性引入页面。 浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能&#xf…

日常常见应用组件升级记录

一、前言 因近期安全扫描,发现java后端应用涉及多个引用组件版本过低,涉及潜在漏洞利用风险,特记录相关处理升级处理过程,以备后续确认; 二、升级处理过程 2.1、Java类应用内置Spring Boot版本升级 Spring Boot是一…

【数据结构与算法】之字符串系列-20240121

这里写目录标题 一、344. 反转字符串二、125. 验证回文串三、205. 同构字符串四、242. 有效的字母异位词五、290. 单词规律 一、344. 反转字符串 简单 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额…

java SSM政府采购管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM政府采购管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的源代 码和数据库,系统主要采…

【UE5】第一次尝试项目转插件(Plugin)的时候,无法编译

VS显示100条左右的错误,UE热编译也不能通过。原因可能是[名字.Build.cs]文件的错误,缺少一些内容,比如说如果要写UserWidget类,那么就要在 ]名字.Build.cs] 中加入如下内容: public class beibaoxitong : ModuleRules …

UML序列图入门

使用工具:processOn可免费建9个文件 UML:Unified Modeling Language 统一建模语言 ProcessOn - 我的文件 一、介绍 序列图是基于对象而非基于类; 从上到下:展示了处理过程中,每个对象的生命周期; 从左到…

从白子画到东方青苍,你选择谁来守护你的修仙之旅?

从白子画到东方青苍,你选择谁来守护你的修仙之旅? 在繁花似锦的修仙世界中,每一位追梦者都渴望有那么一位守护者,与你共患难,共成长。热血与浪漫交织的《花千骨》与《苍兰诀》,给我们带来了两位风华绝代的守护者:白子…

ST-GCN 人体姿态估计模型 代码实战

构建一个ST-GCN(Spatio-Temporal Graph Convolutional Network)模型需要结合图卷积网络(GCN)的思想,以处理时空数据。以下是一个简单的例子,演示如何使用PyTorch构建ST-GCN模型: import torch …

偷偷浏览小网站时,原来有这么多人已经知道

最近看到一篇挺有意思文章,偷偷浏览小网站时,都有谁会知道你看了啥。思量之下,从更广泛的技术角度看,仍有大量补充的空间,于是就有了这样一篇文章。本文的目的在于增强大家的网络安全意识,非必要不要浏览不…

护眼灯品牌哪个好?护眼灯最好的品牌排行

很多家长在帮助孩子选购台灯时可能会遇到一些困扰,而市面上存在许多质量不合格的台灯。曾经有央视节目曝光了许多LED台灯存在严重不合格的情况。尽管目前对于台灯执行强制性产品认证,并不定期进行抽样检查,但仍然存在一些未强制认证的产品在市…

EF Core实操,数据库生成实体,迁移

EF Core实操,数据库生成实体,迁移 大家好,我是行不更名,坐不改姓的宋晓刚,下面将带领大家进入C#编程EF Core数据库基础入门知识,如何连接数据库,如何编写代码,跟上我的步伐进入EF Core数据库下的世界。 家人们,如果有什么不懂,可以留言,或者加我联系方式,一起进入…

python系列-顺序/条件/循环语句

🌈个人主页: 会编程的果子君 ​💫个人格言:“成为自己未来的主人~” 目录 顺序语句 条件语句 什么是条件语句 语法格式 缩进和代码块 空语句pass 循环语句 while循环 for循环 continue break 顺序语句 默认情况下,Python的代码执行…

Elasticsearch+Kibana 学习记录

文章目录 安装Elasticsearch 安装Kibana 安装 Rest风格API操作索引基本概念示例创建索引查看索引删除索引映射配置(不配置好像也行、智能判断)新增数据随机生成ID自定义ID 修改数据删除数据 查询基本查询查询所有(match_all)匹配查…

为什么 HTTPS 协议能保障数据传输的安全性?

HTTP 协议 在谈论 HTTPS 协议之前,先来回顾一下 HTTP 协议的概念。 HTTP 协议介绍 HTTP 协议是一种基于文本的传输协议,它位于 OSI 网络模型中的应用层。 HTTP 协议是通过客户端和服务器的请求应答来进行通讯,目前协议由之前的 RFC 2616 拆…

C++ | 五、哈希表 Hash Table(数组、集合、映射)、迭代器

哈希表基础 哈希表是一类数据结构(哈希表包含数组、集合和映射,和前两篇文章叙述的字符串、链表平级)哈希表概念:类似于Python里的字典类型,哈希表把关键码key值通过哈希函数来和哈希表上的索引对应起来,之…

BGP AS-Path 选路试验

一、拓朴图: 实验要求:R5 通过改变对端传入的 AS-Path 路由策略,使原来较长的 AS-Path 成为最优 二、步骤: 1、配置IP 2、R1、R2、R3 配置 IGP 3、R1、R2、R3 配置 BGP,将 R1 创建的 Loop 100.1.1.1 的环回口在 IBGP …

uni-app小程序:文件下载打开文件方法苹果安卓都适用

api: const filetype e.substr(e.lastIndexOf(.)1)//获取文件地址的类型 console.log(文档,filetype) uni.downloadFile({url: e,//e是图片地址success(res) {console.log(res)if (res.statusCode 200) {console.log(下载成功,);var filePath encodeURI(res.tempFilePath);…