Elasticsearch 主副分片切换过程中对业务写入有影响吗

🍊🍉🍋 先说下结论,只要集群中的工作节点过半,有候选的master节点,挂掉的节点中不同时包含索引的主分片和副分片,那么ES是可以做到让业务无感知的进行主副分片切换的。

蓝胖子会先讲解下ES集群写入文档的原理,并对异常情况进行分析,最后来模拟集群写入过程中节点宕机的情况来对这个问题展开讨论。

主副分片的写入流程

之前我在Elasticsearch 如何保证写入过程中不丢失数据的 有提到ES 通过translog 保证了segment在写入完成后即使会在内存停留一段时间也不会因为宕机而丢失数据。但是没有提到ES在写入时,副本和主节点之间的关系,现在把这部分补充完整。

如下图所示,有3个es节点,es03是整个集群的master节点,同时也承担数据节点的角色,es01,es02都是数据节点,同时也可以成为master节点候选者。

image.png

es client客户端发送插入文档的请求,默认是随机选取集群中的一个节点进行发送,假设请求发送给了es02,由于插入和修改操作只能由主分片进行,此时主分片又是es03节点,所以es02这个时候就充当了协调节点的角色,对客户端的请求进行了转发,转发给了es03

正常情况下es03 会在主分片对数据进行写入,写入成功后,再将插入请求转发到副本节点进行复制,等待副本节点回应后(无论成功还是失败都会回应)会将此次写入数据的结果返回给协调节点es03,es03再将结果返回给客户端。

分片写入过程中的异常处理流程

上面是一个正常的流程,现在来看一下一个异常的情况,如下图所示,在协调节点es02转发请求给es03时,es03 在处理分片写入过程中宕机了,这个时候,客户端的此次写入会失败掉吗?

image.png

es03 节点上的是主分片,这里有必要对es03节点宕机的时机进行分析,

1,es03节点在主分片写入前宕机。

2,es03 节点在主分片写入成功后,还没来得及向副分片写入数据就宕机。

3,es03节点在副分片也写入成功后,就宕机。

以上是主分片的3种宕机的情况。

接着,回到写入流程上,es03节点宕机了,es02的http 转发请求将会失败,此时es02节点在收到失败后,将会进行重试,并且由于此时是主分片,且是master节点宕机,所以,es02节点会等待整个集群重新选出主分片和主节点后,再会进行重试

📢📢📢需要注意的是,如果es03节点宕机的时机是主分片写入前,或者是还没来得及向副分片进行复制就宕机,那么重试不会有任何问题,新的主分片将会拥有写入失败的数据。如下图所示,

image.png

如果es03节点在宕机前已经完成了副分片的复制,es01节点已经拥有了这条插入的数据,那么协调节点es02的重试会导致多插入一条数据吗?

其实是不会的,在Es节点内部,每个文档都会有一个_idversion_id 标记唯一一个文档,version 用于版本更新,ES的更新是基于乐观锁机制,并发更新时有可能返回致版本错误,需要业务方进行重试,更新成功后文档的version字段会进行加1。

在协调节点转发插入请求前,便会生成_idversion 字段,所以如果es03节点已经将插入的数据复制到了副分片,那么es02节点在进行重试发请求时,请求到达es01节点,会在文档中发现相同的_idversion的文档,则会认为数据已经插入了,忽略掉这次重试的插入请求。ES集群会正常的进行插入数据,后续客户端的插入请求都将被转发到es01节点的主分片进行插入。客户端除了直接请求es03节点,不会察觉到es03节点挂了。

上面是在文档写入过程中节点宕机的情况,除以以外,如果es03节点如果没有在处理请求就宕机了,那么集群会重新选主节点和主分片,如果选举过程还没结束,此时客户端就发送来插入请求,那么会等待选举结束后,es02才会继续转发请求到新主分片节点。

所以,你可以看到,Es节点可以通过重试和等待主分片选举实现让业务无感知的进行主副分片的切换。

压测集群模拟节点宕机

下面我用docker compose 启动一个3节点集群,然后对集群进行并发插入,接着模拟节点 宕机,主动kill掉一个节点,来看看最后插入的数据是否和并发插入数据是吻合的,并且插入过程没有报错。

启动一个es集群,

version: '2.2'  
services:  
  es01:  
    image: docker.elastic.co/elasticsearch/elasticsearch:7.14.2  
    container_name: es01  
    environment:  
      - node.name=es01  
      - cluster.name=es-docker-cluster  
      - discovery.seed_hosts=es02,es03  
      - cluster.initial_master_nodes=es01,es02,es03  
      - bootstrap.memory_lock=true  
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  
    ulimits:  
      memlock:  
        soft: -1  
        hard: -1  
    ports:  
      - 9200:9200  
  es02:  
    image: docker.elastic.co/elasticsearch/elasticsearch:7.14.2  
    container_name: es02  
    environment:  
      - node.name=es02  
      - cluster.name=es-docker-cluster  
      - discovery.seed_hosts=es01,es03  
      - cluster.initial_master_nodes=es01,es02,es03  
      - bootstrap.memory_lock=true  
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  
    ulimits:  
      memlock:  
        soft: -1  
        hard: -1  
  
    ports:  
      - 9201:9200  
  es03:  
    image: docker.elastic.co/elasticsearch/elasticsearch:7.14.2  
    container_name: es03  
    environment:  
      - node.name=es03  
      - cluster.name=es-docker-cluster  
      - discovery.seed_hosts=es01,es02  
      - cluster.initial_master_nodes=es01,es02,es03  
      - bootstrap.memory_lock=true  
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"  
    ulimits:  
      memlock:  
        soft: -1  
        hard: -1  
    ports:  
      - 9202:9200

启动之后,创建了一个名字叫做cd的索引,

PUT /cd
{
  "mappings": {
    "properties": {
      "info":{
        "type": "text"
      },
      "age":{
      "type":"integer"
    },
      "email":{
        "type": "keyword",
        "index": false
      },
      "name":{
        "type": "object",
        "properties": {
          "firstName": {
            "type": "keyword"
          },
          "lastName": {
            "type": "keyword"
          }
        }
      }
    }
  }  
}

通过kibana进行查看,目前的主节点es03

Pasted image 20240315181819.png

接着,我用golang写了一个程序总共发出10万的插入请求,100并发进行发出,代码如下,

package main  
  
import (  
    "fmt"  
    "github.com/google/uuid"   
     "io/ioutil"    
     "net/http"   
      "strings"   
       "sync")  
  
func main() {  
    wg := sync.WaitGroup{}  
    for i := 1; i <= 100000; i++ {  
       if i%100 == 0 {  
          wg.Wait()  
       }  
       wg.Add(1)  
       go func() {  
          defer wg.Done()  
          insert()  
       }()  
    }  
    wg.Wait()  
}  
  
func insert() {  
    url := "http://localhost:9201/cd/_doc"  
    method := "POST"  
  
    id := uuid.New().String()  
    payload := strings.NewReader(`{  
  "info":"` + id + `",  
  "email":"12345@136.com",  "name":{    "firstName":"张",  
    "lastName":"四"  
  },  "age":18}`)  
  
    client := &http.Client{}  
    req, err := http.NewRequest(method, url, payload)  
  
    if err != nil {  
       fmt.Println(err)  
       return  
    }  
    req.Header.Add("Content-Type", "application/json")  
  
    res, err := client.Do(req)  
    if err != nil {  
       fmt.Println(err, "错误了", id)  
       return  
    }  
    defer res.Body.Close()  
  
    body, err := ioutil.ReadAll(res.Body)  
    if err != nil {  
       fmt.Println(err)  
       return  
    }  
    if res.StatusCode != 201 {  
       fmt.Println(string(body), res.StatusCode, id)  
    }  
}

程序启动后,就开始并发的往集群中进行插入,此时我手动进入es03容器内部,然后kill掉了es进程。接着,此时索引的主副分片发生了变化,如下图所示,索引的主分片变到了节点es01上,而集群的master节点变成了es02。

Pasted image 20240315182242.png

整个程序此时还在进行,并未有任何报错。

此时我又手动重启了挂掉的es03,让其自动进行恢复recovery ,节点状态变化如下,可以看到es03已经变成副分片了。

Pasted image 20240315182838.png

最后,等待并发程序结束后,我向集群中对插入的数据行数进行查询,的确是10万条数据,说明数据没有发生丢失,并且,整个过程,客户端也没有报错。

Pasted image 20240315183036.png

足以说明,ES的主副分片的确对业务是无感知的了。的确是妙啊。对比起mysql的可靠性优先的主备切换方式,数据库会有小段的时间不可写,重试机制由ES帮我们做了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ARM_基础之RAS

Reliability, Availability, and Serviceability (RAS), for A-profile architecture 源自 https://developer.arm.com/documentation/102105/latest/ 1 Introduction to RAS 1.1 Faults,Errors,and failures 三个概念的区分&#xff1a; • A failure is the event of devia…

外包干了3天,技术明显进步。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入南京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

16、技巧之九: 修改参数,如何让表格翻页滚动到底部?【Selenium+Python3网页自动化总结】

1、问题提出 在网页配置参数时&#xff0c;输入参数名称搜索&#xff0c;搜出来的同名参数结果有多个&#xff0c;分布在一个表格的不同行&#xff0c;表格是动态加载的&#xff0c;需要滚动鼠标才能把所出参数找出来。用selenium怎么实现这种参数修改&#xff1f; 2、网页元素…

JVM学习-JVM的自动优化

目录 1.语法糖 1.1默认构造器 1.2自动拆装箱 1.3泛型集合取值 1.4可变参数实现 1.5 foreach循环 1.6 switch配合String使用 1.7 switch配合枚举使用​编辑 1.8 try-with-resources 1.9方法重写的桥接方法 2.运行时优化 2.1分层优化以及逃逸分析 2.2方法内联 2.3字段优化 JVM会…

产品推荐 - 基于FPGA XC7K325T+DSP TMS320C6678的双目交汇视觉图像处理平台

一、产品概述 TES601是一款基于FPGA与DSP协同处理架构的双目交汇视觉图像处理系统平台&#xff0c;该平台采用1片TI的KeyStone系列多核浮点/定点DSP TMS320C6678作为核心处理单元&#xff0c;来完成视觉图像处理算法&#xff0c;采用1片Xilinx的Kintex-7系列FPGA XC7K325T作为视…

​​SQLiteC/C++接口详细介绍之sqlite3类(十)

返回目录&#xff1a;SQLite—免费开源数据库系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍之sqlite3类&#xff08;九&#xff09; 下一篇&#xff1a;​​SQLiteC/C接口详细介绍之sqlite3类&#xff08;十一&#xff09; 30.sqlite3_enable_load_extension&#x…

三、NLP中的句子关系判断

句子关系判断是指判断句子是否相似&#xff0c;是否包含&#xff0c;是否是问答关系等&#xff0c;常应用在文本去重、检索&#xff08;用户输入和文档的相关性&#xff09;、推荐&#xff08;和用户喜好文章是否相似&#xff09;等场景中。 3.0、文本相似度计算 3.0.0 传统机…

更改el-tabs默认样式,实现tab标签居中显示,标签对应内容使用另一个div显示

首先看效果图 如图所示&#xff0c;标签在浏览器窗口居中&#xff0c;但是下面的内容依然是默认从左到右&#xff0c;不会受到tab样式的影响 <template><div><div style"display: flex; justify-content: center; align-items: center;"><el-…

JVM学习-JVM简介以及其内部结构

目录 1.什么是JVM 2.JVM、JRE、JDK、JavaSE、JavaEE之间的联系 3.JVM的内部结构 4.各部分的作用 4.1 类加载器 4.2 方法区 4.3 堆 ​编辑 4.4 虚拟机栈 4.5 程序计数器 4.6 本地方法栈 4.7 解释器和JIT即时编译器 4.9 GC垃圾回收 5.拓展 5.1一些可能会遇到的问…

Mysql 死锁案例4-delete 相邻记录导致死锁

死锁复现 CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,d int(11) DEFAULT NULL,PRIMARY KEY (id),KEY c (c) ) ENGINEInnoDB DEFAULT CHARSETutf8;/*Data for the table t */insert into t(id,c,d) values (0,0,0),(5,5,5),(10,10,10),(15,15,15) 事务1事…

C语言初学12:强制类型转换

一、强制数据类型转换举例 1.1 double赋值给int #include<stdio.h> int main() {double sum 18, count 5;int mean;mean sum / count;printf("Value of mean : %d\n", mean);} 执行结果&#xff1a; double赋值给int&#xff0c;小数部分会删除&#xff…

dp入门:从暴力dfs 到 dp

本篇为小金鱼大佬视频的学习笔记&#xff0c;原视频链接&#xff1a;https://www.bilibili.com/video/BV1r84y1379W?vd_source726e10ea5b787a300ceada715f64b4bf 基础概念 暴力dfs很多时候仅能过部分测试点&#xff0c;要想将其优化&#xff0c;一般以 dfs -> 记忆化搜索 …

汽车IVI中控开发入门及进阶(十三):语音识别

前言: IVI中控上的语音识别,在目前市场上也是非常显眼的一个创新,大幅改变了传统IVI的操作习惯。 语音识别Speech recognition,也称为自动语音识别(ASR)、计算机语音识别或语音到文本,是一种使程序能够将人类语音处理成书面格式的能力。 语音识别Speech recognition是计…

1.6w字数据库基础知识超详细解析~‍(进阶/复习版)

文章目录 前言一、数据库的操作1.登入数据库2.创建数据库3.显示当前数据库4.使用数据库5.删除数据库 二、常用数据类型三、数据库的约束1约束类型2NULL约束3UNIQUE:唯一约束4DEFAULT&#xff1a;默认值约束5 PRIMARY KEY&#xff1a;主键约束6 FOREIGN KEY&#xff1a;外键约束…

Calendar类 --java学习笔记

Calendar 代表的是系统此刻时间对应的日历通过它可以单独获取、修改时间中的年、月、日、时、分、秒等 常见方法&#xff1a; 创建Calendar对象&#xff1a; 用Calendar.getInStance&#xff08;&#xff09;方法&#xff0c;返回一个此时此刻的日历&#xff08;Calendar&am…

关于IP地址证书的申请

对于直接通过IP地址访问的服务器&#xff0c;为其配置SSL证书同样至关重要。以下是一份详尽的指南&#xff0c;教你如何为你的IP地址申请SSL证书。 IP地址证书目前有DV验证和OV验证两种主流的验证方式&#xff0c;DV验证只需验证IP的所有权&#xff0c;OV的在此基础上&#xff…

换根dp,LeetCode310. 最小高度树

一、题目 1、题目描述 树是一个无向图&#xff0c;其中任何两个顶点只通过一条路径连接。 换句话说&#xff0c;一个任何没有简单环路的连通图都是一棵树。 给你一棵包含 n 个节点的树&#xff0c;标记为 0 到 n - 1 。给定数字 n 和一个有 n - 1 条无向边的 edges 列表&#…

自媒体人的超级宝典

这个10块钱的小报童还有谁没买&#xff1f; 你可别等到它涨到19.9的时候来问我有没有优惠 昨天正式发售就已经2300人了&#xff0c;之前可是几个小时就涨了400多人&#xff0c;照这个速度下去&#xff0c;明天就要涨价了。 说实话&#xff0c;我看了里面的内容&#xff0c;觉…

Linux网络编程: 以太网帧Frame/ARP/RARP详解

一、TCP/IP五层模型 物理层&#xff08;Physical Layer&#xff09;&#xff1a;物理层是最底层&#xff0c;负责传输比特流&#xff08;bitstream&#xff09;以及物理介质的传输方式。它定义了如何在物理媒介上传输原始的比特流&#xff0c;例如通过电缆、光纤或无线传输等。…

SAP Activate项目管理方法论路线图

SAP Activate 是 SAP 推出的一种基于敏捷方法论的灵活、快速且引导式的实施方法论&#xff0c;专为加速SAP S/4HANA和其他SAP解决方案的部署而设计。这个方法论结合了最佳实践、引导配置和方法论本身的强大能力&#xff0c;以确保项目的快速实施和成功部署。SAP Activate的核心…