ES节点故障的容错方案

news2024/11/13 22:06:03

ES节点故障的容错方案

  • 1. es启动加载逻辑
    • 1.1 segment和translg组成和分析
    • 1.2 es节点启动流程
    • 1.3 es集群的初始化和启动过程
  • 2. master高可用
    • 2.1 选主逻辑
      • 2.1.1 过滤选主的节点列表
      • 2.1.2 Bully算法
      • 2.1.2 类Raft协议
      • 2.1.3 元数据合并
    • 2.2 HA切换
  • 3. 分片高可用
    • 3.1 集群分片汇报
    • 3.2 选举主分片
    • 3.4 主分片恢复
    • 3.4 副分片恢复
    • 3.2 分片恢复的一致性
    • 3.2 HA切换逻辑
    • 3.3 如果写入过程中,分片副本节点宕机,会如何处理?
  • 4. 疑问和思考
    • 4.1 如果一个es宕机,运行在es上的shard数据丢失,是否会自动做均衡?
  • 5. 参考文档

本文主要探讨es集群的高可用容错方案和容错能力的探讨。在出现单机故障时相关的容错方案。

更多关于分布式系统的架构思考请参考文档关于常见分布式组件高可用设计原理的理解和思考


1. es启动加载逻辑

1.1 segment和translg组成和分析

可以参考文章ES高可用架构涉及常用功能整理,本文不再赘述。

1.2 es节点启动流程

在这里插入图片描述
更多细节可以参考玩转Elasticsearch源码-一图看懂ES启动流程

1.3 es集群的初始化和启动过程

es集群的启动大致流程如下
在这里插入图片描述
这里的集群启动过程指集群完全重启时的启动过程,期间要经历选举主节点、主分片、数据恢复等重要阶段,理解其中原理和细节,对于解决或避免集群维护过程中可能遇到的脑裂、无主、恢复慢、丢数据等问题有重要作用。

2. master高可用

2.1 选主逻辑

es的master选主逻辑根据版本不同,有不同的调整

  • 7.0版本之前,使用Bully算法
  • 7.0版本以后,使用类Raft协议,基于Raft协议做了调整

2.1.1 过滤选主的节点列表

选举的第一步,就是需要过滤出选参选的活跃master节点列表,并判断活跃的master列表是否满足选举条件。

  1. 通过参数discovery.zen.ping.unicast.hosts 获取初始的master列表,之后需要做2个事情
  • 通过ping机制,获取列表中活跃的master列表
  • 由于人工静态配置的列表可能不全,因此需要跟活跃的初始列表通信,获取集群中能够成为master的所有节点
  1. 判断过滤出来的活跃master列表数量是否满足discovery.zen.minimum_master_nodes要求,如果不满足,说明集群中参选的数量不足,有可能会有脑裂的风险,不能进一步选举。否则无法满足quorum机制

注: 在7.0后版本中,废除了discovery.zen.minimum_master_nodes参数,而是通过类raft算法自行计算

2.1.2 Bully算法

Bully算法的基本原理就是,根据节点的ID大小来判定谁是leader

Bully算法在选举的时候会发送三种消息类型

  • 选举消息 (Election Message: Sent to announce election.)
  • 应答消息(Answer (Alive) Message: Responds to the Election message.)
  • 选举成功消息 (Coordinator (Victory) Message: Sent by winner of the election to announce victory.)

这三种消息类型组成了Bully的基础消息类型,这也是Bully算法选举必须要了解的东西。

分步解释

  • 节点1向节点,节点3发送选举,并且带上自己的序号1
  • 节点2,3接收到消息之后,进行序号比较,发觉自己的序号更大,向节点1返回应答消息Answer (Alive) Message,告知节点1被踢出选主序列(大概是这个意思)
  • 节点2向节点3发送选举请求,节点3找不到更高序号的节点发送选举请求了节点3向节点2返回应答消息,节点3收不到其他节点的应答消息了
  • 节点3被认为是leader,向其他节点发送Coordinator Message,选举成功的请求,将自己是master节点广播到节点1,节点2

从如上算法的介绍中,可以得知,

  • bully算法有点是简单,能够选出leader很容易。
  • bully算法有很多缺陷,最大的问题还是master假死后不能重新触发选主和难以规避脑裂问题

因此es给bully算增加了限制,以规避bully算法的原生问题。

  • 设置最少得节点参选数量discovery.zen.minimum_master_nodes
  • 至少满足(n+1)/2选票,才能成为leader

这也是为什么在7.0版本,选举算法切换为raft的重要原因。

2.1.2 类Raft协议

raft协议经常接触,可以参考 ETCD高可用架构涉及常用功能整理,不在介绍。

相比于Raft算法,Es的选主算法有如下不同

  • 初始为 Candidate状态
  • 允许多次投票,也就是每个有投票资格的节点可以投多票
  • 候选人可以有投票的机会
  • 可能会产生多个主节点,举例来说,如果node1,node2,node3进行选主

如果node1当选leader,但是node2发来了投票要求,那么node1无条件退出leader状态,node2选为主节点,但是node3也发来了投票要求,那么node2退出leader状态,node3当选主节点。

说明白了,就是保证最后当选的leader为主leader

2.1.3 元数据合并

无论是bully算法还是类raft协议,并不考虑当前节点的数据是否最新,而是在完成选举出leader后进行数据合并中完成数据的一致性问题。

原因是客户端在es的副本写入数据过程中,并不会通知master节点,因此master节点并不知道哪个节点的元数据最新,而是通过后续node节点的数据汇报进行完善,在这一点上跟hdfs的nn类似。

这跟etcd、zk有本质区别,因为etcd、zk的leader节点也是数据节点,所有的数据写入是从leader完成,follower进行同步,因此能够感知谁的数据最新。而es的master节点和node节点是拆分的,因此无法实现这一点,因此只能是类raft协议。

因此在完成leader选举后,需要进行元数据合并

  • 其他的master角色节点(没有选举成为master)发送自身的元数据给master
  • node节点上报自身元数据给master
  • master完成元数据合并后,广播到其他的节点经合并

2.2 HA切换

当探测到节点离开事件时,必须判断当前节点数是否过半。如果达不到半数以上,则放弃Master身份,重新加入集群。如果不这么做,则设想以下情况:假设5台机器组成的集群产生网络分区,2台一组,3台一组,产生分区前,Master位于2台中的一个,此时3台一组的节点会重新并成功选取Master,产生双主,俗称脑裂。(节点失效检测)

在这里插入图片描述

节点失效检测会监控节点是否离线,然后处理其中的异常。失效检测是选主流程之后不可或缺的步骤,不执行失效检测可能会产生脑裂(双主或多主)。

3. 分片高可用

3.1 集群分片汇报

完成master选主后,需要重建集群的shard路由表,该工作全部都是master完成

  • 最开始时,Master不知道主分片在哪,它向集群的所有其他节点询问,让其他节点把[website][0]分片的元信息发过来。
  • Master 收到所有返回后,它就有了这个 shard 的信息,然后根据某种策略选一个分片作为主分片。

是不是效率有些低?这种询问量=shard 数×节点数。所以说我们最好控制shard的总规模别太大。

3.2 选举主分片

构建完所有的分片信息,现在考虑把哪个分片作为主分片。

  • ES 5.x以下的版本,通过对比shard级元信息的版本号来决定。

但是有问题: 在多副本的情况下,考虑到如果只有一个 shard 信息汇报上来,则它一定会被选为主分片,但也许数据不是最新的,版本号比它大的那个shard所在节点还没启动。因此可能会数据丢失。

在解决这个问题的时候,ES 5.x开始实施一种新的策略:给每个 shard 都设置一个 UUID,然后在元信息中记录哪个shard是最新的(ES是先写主分片,再由主分片节点转发请求去写副分片,所以主分片所在节点肯定是最新的,如果它转发失败了,则要求Master删除那个节点,所以可以识别哪个分片最新)

如果集群设置了:禁止分配分片,集群仍会强制分配主分片。

"cluster.routing.allocation.enable": "none"

因此,在设置了上述选项的情况下,集群重启后的状态为Yellow,而非Red。

3.4 主分片恢复

由于每次写操作都会记录事务日志(translog),事务日志中记录了哪种操作,以及相关的数据。因此将最后一次提交(一次提交就是一次 fsync 刷盘的过程)之后的 translog中进行重放,建立索引,如此完成主分片的recovery。

3.4 副分片恢复

副分片的恢复是比较复杂的,在ES的版本迭代中,副分片恢复策略有过不少调整。副分片需要恢复成与主分片一致,同时,恢复期间允许新的索引操作。在目前的6.0版本中,恢复分成两阶段执行:

  • 阶段1
  1. 在主分片所在节点,获取translog保留锁,从获取保留锁开始,会保留translog不受其刷盘清空的影响
  2. 调用接口把shard做快照,这是已经刷磁盘中的分片数据,把这些shard数据复制到副本节点。
  3. 在阶段1完毕前,会向副分片节点发送告知对方启动engine,在阶段2开始之前,副分片就可以正常处理写请求了。

针对当前的分片数据做checkpoint,并送给副分片恢复,耗时长,但是并不影响新的数据写入(写的数据写入到新的translog中,并且在快照期间不会translog不会被清理)

  • 阶段2
  1. translog做快照,这个快照里包含从阶段1开始,到执行translog快照期间的新增索引
  2. 将这些translog发送到副分片所在节点进行重放。

涉及的数据量少,所以耗时短。

由于需要支持恢复期间的新增写操作(让ES的可用性更强),这两个阶段中需要重点关注以下几个问题:

es的分片恢复根据版本不同,有不同的调整

  • 6.0版本之前,副本分片数据全部来自主分片,需要从主分片同步
  • 6.0版本以后,副本分片数据先从本地的translog加载,在从主分片同步,环节主分片压力,是一个分片恢复的提升。

3.2 分片恢复的一致性

恢复时,因为主副分片恢复时间不一致,主分片先进行Recovery,然后副分片才能基于主分片进行Recovery,所以主分片可以工作之后,副分片可能还在恢复中,此时主分片会向副分片发送写请求,因此恢复reply与主分片可能会同时(或者不按发生顺序)对同一个doc进行操作。ES中通过doc的版本号解决这个问题,当收到一个版本号低于doc当前版本号的操作时,会放弃本次操作。对于特定的doc,只有最新一次操作生效。

3.2 HA切换逻辑

当主分片不可用时,es就会重新进行选举,把最新的副本分片提高到主分片的地位,由master进行检测和分片选主,并在分片完成选主后,触发分片的数据恢复逻辑。

3.3 如果写入过程中,分片副本节点宕机,会如何处理?

如果正在写入过程时,副本分片宕机或者出现异常,master会从shard分片中剔除该分片,继续执行写入。

  • 如果分片副本标记写入成功的节点数量,满足要求(具体等待多少副本取决于wait_for_active_shards的配置值),本次写入即可标记成功,并返回给客户端
  • 如果分片副本标记写入成功的节点数量,不满足要求(具体等待多少副本取决于wait_for_active_shards的配置值),本次写入即可标记失败,并返回给客户端,客户端来决定是否重试。

4. 疑问和思考

4.1 如果一个es宕机,运行在es上的shard数据丢失,是否会自动做均衡?

取决于是否配置自动分配参数cluster.routing.allocation.enable,默认是all,表示能够自动触发分配。

  • all:表示能够自动分配分片,如果节点宕机,节点上的涉及的分片副本会自动迁移到其他的节点上,从而满足副本要求(配置了节点标签,不满足分配条件的除外)
  • none: 不触发自动分配,通过在节点主动维护时使用。在进行节点维护时,如果希望临时关闭自动分配,可以使用如下方式
curl -XPUT http://127.0.0.1:9200/_cluster/settings -d '{
  "transient" : {
    "cluster.routing.allocation.enable" : "none"
  }
}'

是否配置主动触发分配,有利有弊,主要原因是自动分配不能识别难以识别业务高峰期,会占用磁盘io和网络带宽。并且如果只是短时间维护节点,触发分配后,机器维护完成,又要重新触发恢复分配,恢复时间较长,因此根据实际情况调整。

个人建议

  • 如果能够清楚的知道节点维护的时间和周期(比如1-2h),可以临时关闭自动分配(恢复时间快)
  • 如果不可预估节点维护的时间或者维护周期过长,不建议关闭自动分配(数据的安全重要度高)

5. 参考文档

  • ElasticSearch——详细看看ES集群的启动流程
  • ElasticSearch-新老选主算法对比

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

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

相关文章

前端常用代码整理(不断更新中)— js,jquery篇

1.随机函数代码 function getRandom(min, max) {return Math.floor(Math.random() * (max - min 1)) min}2.倒计时代码 let now new Date()// 2. 得到指定时间的时间戳let last new Date(这里写想要达到的时间)// 3. (计算剩余的毫秒数) / 1000 剩余…

ChinaXiv:中科院科技论文预发布平台

文章目录 Main彩蛋 Main 主页:https://chinaxiv.org/home.htm 彩蛋

11.0 Zookeeper watcher 事件机制原理剖析

zookeeper 的 watcher 机制,可以分为四个过程: 客户端注册 watcher。服务端处理 watcher。服务端触发 watcher 事件。客户端回调 watcher。 其中客户端注册 watcher 有三种方式,调用客户端 API 可以分别通过 getData、exists、getChildren …

vue3 使用defineAsyncComponent 动态加载组件

问题场景 在项目中使用静态加载组件基本能覆盖80%的场景了,如下图 但是我们在需要 循环生成一些的component 的时候或者在 开发ssr服务端渲染的页面 就会遇到有些组件以静态方式导入就会报错,导致进程失败,那么这时候就需要用到动态组件。那…

智能运维适合哪些行业?智能运维需要哪些设备?

构建一个智能运维系统所必须的设备和工具包括: 硬件设备: 服务器:用于部署智能运维平台和存储数据。 网络设备:包括路由器、交换机等,用于连接各种设备和系统。 存储设备:如硬盘、SSD等&am…

时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 时序预测 | Matlab实现基于LSTM长短期记忆神经网络的电力负荷预测模型 LSTM(长短期记忆)是一种递归神经网络(RNN)的变体,它在序列数据建模方面表现出色。电力负荷预测是一项重要的任务,可以利用LSTM神经网络…

Adb显示第3方应用的包名原理

Android早期版本实现原理请看 Android源码分析-pm命令的实现,列出包名pm list package,列出系统库pm list libraries_pm list packages-CSDN博客 Android12 对adb shell pm 实现原理做了重构:改成了template模式PackageManagerShellCommand …

如何在 Java 中通过 Map.Entry 访问 Map 的元素

我们使用 Map.Entry 来遍历 ConcurrentHashMap 的代码片段如下&#xff1a; for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("Key: " entry.getKey() ", Value: " entry.getValue()); } 在 Map.java 中&…

Java20:新特性

一&#xff1a;Lambda表达式&#xff1a; 1. Lambda表达式使用前后对比&#xff1a; 举类一&#xff1a; Testpublic void test(){ Runnable r1 new Runnable() {Overridepublic void run() {System.out.println("我爱北京天安门&#xff01;");} };r1.run();Syst…

华为机考入门python3--(11)牛客11-数字颠倒

分类&#xff1a;字符串 知识点&#xff1a; int转字符串 str int(num) 对字符串进行逆序 my_str str[::-1] 题目来自【牛客】 def reverse_integer(n): # 将整数转换为字符串 str_n str(n) # 使用[::-1]来反转字符串 reversed_str str_n[::-1] return reversed…

FINN: 使用神经网络对网络流进行指纹识别

文章信息 论文题目&#xff1a;FINN: Fingerprinting Network Flows using Neural Networks 期刊&#xff08;会议&#xff09;&#xff1a;Annual Computer Security Applications Conference 时间&#xff1a;2021 级别&#xff1a;CCF B 文章链接&#xff1a;https://dl.ac…

BioTech - 小分子药物设计与优化 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135998902 小分子药物设计与优化&#xff0c;是利用计算机辅助技术&#xff0c;根据特定的生物学靶点&#xff0c;发现和改进具有治疗作用的小分子…

Codeforces Round 920 (Div. 3)(A~F)

文章目录 ABCDEF A 按题意模拟即可 #include <bits/stdc.h> #define int long long #define rep(i,a,b) for(int i (a); i < (b); i) #define fep(i,a,b) for(int i (a); i > (b); --i) #define pii pair<int, int> #define pll pair<long long, long…

JavaEE作业-实验二

目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 实现两个整数求和的WEB程序 2 实验要求 ①采用SpringMVC框架实现 ②数据传送到WEB界面采用JSON方式 3 思路 ①创建一个SpringMVC项目&#xff0c;配置好相关的依赖和配置文件。 ②创建一个Con…

Win32 SDK Gui编程系列之--ListView自绘OwnerDraw

ListView自绘OwnerDraw 1.ListView自绘OwnerDraw 正在试错是否使用了列表视图,尽量制作出智能的表格编辑器。本页显示了业主抽签的表格数据(二维数组数据)的显示方法。 显示画面和整个程序如下所示。使用ListView_GetSubItemRect宏的话,就不需要getRect函数了。 当nCol的…

thinkphp获取用户最新的阅读记录,按书籍id去重,返回最新的阅读记录

通过uid查询data_user_zhangjie的记录 去重shuji_id 获取createtime最新的一条数据 //获取用户章节记录public function getUserZhangjieList(){$uid = input(uid);if(empty

Maven构建OSGI+HttpServer应用

Maven构建OSGIHttpServer应用 官网&#xff08;https://eclipse.dev/equinox/server/http_in_equinox.php&#xff09;介绍有两种方式&#xff1a; 一种是基于”org.eclipse.equinox.http”包的轻量级实现&#xff0c;另一种是基于”org.eclipse.equinox.http.jetty”包&#…

jvm体系结构

一、Jvm 的介绍 1、JVM体系结构 2、JVM运行时数据区 3、JVM内存模型 JVM运行时内存 共享内存区 线程内存区 3.1、共享内存区 共享内存区 持久带(方法区 其他) 堆(Old Space Young Space(den S0 S1)) 持久代&#xff1a; JVM用持久带&#xff08;Permanent Space&…

MySQL数据库语句总结

一. 数据定义语言 DDL 数据定义语言&#xff0c;用来定义数据库对象的&#xff08;比如&#xff1a;数据库、表、字段等&#xff09; 1. 数据库操作 &#xff08;1&#xff09;查询所有的数据库 —— show databases; &#xff08;2&#xff09;创建数据库 —— create dat…

【数据结构】二叉树的顺序结构及实现(堆)

1.二叉树的顺序结构 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储&#xff0c;需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两…