Elasticsearch-增删改查数据工作原理
集群
集群的基本概念:
- 集群:ES 集群由一个或多个 Elasticsearch 节点组成,每个节点配置相同的 cluster.name 即可加入集群,默认值为 “elasticsearch”。
- 节点:一个 Elasticsearch 服务启动实例就是一个节点(Node)。节点分为主节点(Master),投票节点(Voting),协调节点(Coordinating),候选节点(Master-eligible)和数据节点(Data)。
- 分片:ES 支持 PB 级全文搜索,当索引上的数据量太大的时候,ES 通过水平拆分的方式将一个索引上的数据拆分出来分配到不同的数据块上,拆分出来的数据库块称之为一个分片。
- 副本:副本就是对分片的 Copy,每个主分片都有一个或多个副本分片,当主分片异常时,副本可以提供数据的查询等操作。
如下图可以看出为了达到高可用,Master 节点会避免将主分片和副本分片放在同一个节点上。
路由
1. 写请求首先会被打到协调节点,协调节点根据路由算法决定数据写入的主分片位置,并在主节点上执行写入操作。
路由算法:
shardId = hash(_routing) % num_primary_shards
通过该公式可以保证使用相同routing的文档被分配到同一个shard上。_routing
是一个可变值,默认是文档的 _id
,也可以设置成一个自定义的值,可以用在INDEX, UPDATE,GET, SEARCH, DELETE等各种操作中手动设置。
routing_partition_size
参数
ES还提供了一个 index.routing_partition_size
参数(仅当使用routing参数时可用),用于将routing相同的文档映射到集群分片的一个子集上,这样一方面可以减少查询的分片数,另一方面又可以在一定程度上防止数据倾斜。引入该参数后计算公式如下
shardId = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
2. 主分片执行写入操作,如下图S0主分片写入之后,同步到副本分片
索引写入
主分片写入
当接收到请求时,执行如下步骤:
①判断操作类型:如果是 Bulk Request 会遍历请求中的子操作,根据不同的操作类型跳转到不同的处理逻辑。
②操作转换:将 Update 操作转换为 Index 和 Delete 操作。
③解析文档(Parse Doc):解析文档的各字段。
④更新 Mapping:如果请求中有新增字段,会根据 dynamic mapping 或 dynamic template 生成对应的 mapping,如果 mapping 中有 dynamic mapping 相关设置则按设置处理。
⑤获取 sequence Id 和 Version:从 SequenceNumberService 获取一个 SequenceID 和 Version。SequenceID 用于初始化 LocalCheckPoint,version 是根据当前 versoin+1 用于防止并发写导致数据不一致(乐观锁)。
⑥写入 Lucene:对索引文档 uid 加锁,然后判断 uid 对应的 version v2 和之前 update 转换时的 version v1 是否一致,不一致则返回第二步重新执行。在 version 一致的情况下根据id的情况执行添加或者更新操作。如果同 id 的 doc 已经存在,则调用 updateDocument 接口。
⑦写入 translog:写入 Lucene 的 Segment 后,会以 key value 的形式写 Translog, Key 是 Id,Value 是索引文档的内容。当查询的时候,如果请求的是 GetDocById 则可以直接根据 _id 从 translog 中获取。写入 translog 的操作会在下面的章节中详细讲解。
⑧重构 bulk request:已经多个操作中的 update 操作转换为 index、delete 操作,最终都以 index 或 delete 操作的方式组成 bulk request 请求。
⑨落盘 Translog:默认情况下,translog 要在此处落盘完成,如果对可靠性要求不高,可以设置 translog 异步落盘,同时存在数据有丢失的风险。
⑩发送请求给副本分片:将构造好的 bulk request 发送给各个副本分片,并且等待副本分片返回,然后再响应协调节点。如果某个分片执行失败,主分片会给主节点发请求移除该分片。
⑪等待 replica 响应:当所有的副本分片返回请求时,更新主分片的 LocalCheckPoint。如果设置了index.write.wait_for_active_shards=1,那么写完主节点,直接返回客户端,异步同步到从分片。如果 index.write.wait_for_active_shards=all,那么必须要把所有的副本写入完成才返回客户端。wait_for_active_shards最大值只能是 number_of_replicas +1 ,详情见官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/5.5/docs-index_.html#index-wait-for-active-shards
Elasticsearch 文件合并与刷新
在了解了文件写入流程以后,再来近距离观察一下写入的细节,看看索引是如何通过内存最终写入磁盘的。
如图 2 所示,将每一步写入操作进行拆解如下:
①写入请求会将索引(Index)存放到内存区域,叫做 Index Buffer。这边的内存是ES JVM内存。此时的索引文件暂时是不能被ES搜索到的。
②当达到默认的时间:1 秒钟(参数refresh_interval=1s)或者内存的数据达到一定量(默认值是 JVM 所占内存容量的 10%)时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件系统缓存(FileSystem Cache)上,并将Index Buffer 的数据会被清空。这时虽然新段未被提交到磁盘,但是此时的数据就可以被 ES 搜索到了且不能被修改。
③ES 每次 refresh 都会生成一个 Segment 文件,这样下来 Segment 文件会越来越多。由于每个 Segment 都会占用文件句柄、内存、CPU 资源,假设每次搜索请求都会访问对应 Segment 获取数据,这就意味着 Segment 越多会加大搜索请求的负担,导致请求变慢。为了提高搜索性能 ES 会定期对 Segment 进行合并(Merge)操作,也就是将多个小 Segment 合并成一个 Segment。那么搜索请求就直接访问合并之后的 Segment,从而提高搜索性能。
④上面 3 个步骤都是在内存中完成的,此时数据还没有写到磁盘中。 随着新文档索引不断被写入,当translog日志数据大小超过 512M (由 index.translog.flush_threshold_size 控制)或者时间超过 30 分钟时,会触发一次 Flush。此时 ES 会创建一个 Commit Point 文件,该文件用来标识被 Flush 到磁盘上的 Segment。
Elasticsearch 数据存储可靠性
延续上一节的例子,在原有的基础上加入 Translog 的部分。如图 3 所示,在整个 ES 写入流程中加入 Translog,目的是为了提高 ES 的数据存储可靠性。
索引文档最开始是存放在内存的 Index Buffer 中,当执行了 Refresh 操作会将其保存为 Segment,此时就可以供用户查询了。但是 Segment 在 Flush 之前仍然存在于内存中,如果此时服务器宕机,而 ES 还没有 Flush 操作保存在内存中的 Segment 数据将会丢失。为了提高 ES 的数据存储可靠性,引入了 Translog。在每次用户请求 Index Buffer 进行操作的时候都会写一份操作记录到 Translog 中,Translog 使用特有的机制保存到磁盘中。上一节提到的 Flush 操作,当 Flush 操作将 Segment 进行落盘同时还会将 Translog 的文件进行落盘,之后会将内存中原有的Translog 移除,在内存中会重新创建一个新的 Translog。
translog相关配置:
##translog的刷盘策略durability为request表示同步(默认),async表示异步
index.translog.durability: async
##translog刷盘间隔时间。默认为5s,不可低于100ms
index.translog.sync_interval: 120s
##超过这个大小会导致flush操作,产生新的Lucene分段。默认值为512MB
index.translog.flush_threshold_size: 1024mb
通过这种方式当断电或需要重启时,ES 不仅要根据提交点去加载已经持久化过的段,还需要工具 Translog 里的记录,把未持久化的数据重新持久化到磁盘上,避免了数据丢失的可能。
图中 Translog 存在于内存和磁盘中,分别有两个线将其相连,表示了 Translog 同步的两种方式:
-
在 ES 处理用户请求时追加 Translog,追加的内容就是对ES的请求操作。此时会根据配置同步或者异步的方式将操作记录追加信息保存到磁盘中。
-
另一种 Translog 从内存到磁盘的操作是在 Flush 发生的时候,上节中介绍过,Flush 操作会把 Segment 保存到磁盘同时还会将 Translog 的文件进行落盘。落盘以后存在与内存中的 Translog 就会被移除。
索引检索
在执行文档的CRUD操作时,通过文档ID就能计算出文档存储在哪个分片中,所以只要将客户端请求转发给对应的分片(或其副本)所在的节点进行处理即可。
而执行文档搜索操作时只会提供搜索条件,并不包含文档ID,无法直接知道哪些分片包含搜索结果,需要先搜索所有的分片(或其副本),还要对每个分片上的结果进行汇总以得到最终结果。所以,文档的搜索过程会分为如下两步执行:
-
搜索所有的分片(或其副本),确定哪些文档属于搜索结果;
-
从相关分片上读取文档数据,再汇总组装成最终的结果;
将第一步称为query,第二步称为fetch,整个搜索过程称为query-then-fetch。
以分页查询为例,from + size 分页方式是 ES 最基本的分页方式,类似于关系型数据库中的 limit 方式。from 参数表示:分页起始位置;size 参数表示:每页获取数据条数。例如:
{"query": {"match_all": {}},"from": 10,"size": 20
}
Query阶段
如上图所示,Query 阶段大致分为 3 步:
-
第一步:Client 发送查询请求到 Server 端,Node1 接收到请求然后创建一个大小为 from + size的优先级队列用来存放结果,此时 Node1 被称为 coordinating node(协调节点);
-
第二步:Node1 将请求广播到涉及的 shard (主分片或副本分片,根据随机或轮询算法)上,每个 shard 内部执行搜索请求,然后将执行结果存到自己内部的大小同样为 from+size 的优先级队列里;
-
第三步:每个 shard 将暂存的自身优先级队列里的结果返给 Node1,Node1 拿到所有 shard 返回的结果后,对结果进行一次合并,产生一个全局的优先级队列,存在 Node1 的优先级队列中。(如上图中,Node1 会拿到 (from + size) * 6 条数据,这些数据只包含 doc 的唯一标识_id 和用于排序的_score,然后 Node1 会对这些数据合并排序,选择前 from + size 条数据存到优先级队列);
Fetch阶段
如上图所示,当 Query 阶段结束后立马进入 Fetch 阶段,Fetch 阶段也分为 3 步:
-
第一步:Node1 根据刚才合并后保存在优先级队列中的 from+size 条数据的 id 集合,发送请求到对应的 shard 上查询 doc 数据详情;
-
第二步:各 shard 接收到查询请求后,查询到对应的数据详情并返回为 Node1;(Node1 中的优先级队列中保存了 from + size 条数据的_id,但是在 Fetch 阶段并不需要取回所有数据,只需要取回从 from 到 from + size 之间的 size 条数据详情即可,这 size 条数据可能在同一个 shard 也可能在不同的 shard,因此 Node1 使用 multi-get 来提高性能)
-
第三步:Node1 获取到对应的分页数据后,返回给 Client;
索引修改和删除
索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢?
-
删除操作 :
commit
的时候会生成一个.del
文件,里面将某个doc
标识为deleted
状态,那么搜索的时候根据.del
文件就知道这个 doc 是否被删除了,最终结果被返回前从结果集中移除。 -
更新操作 :就是将原来的
doc
标识为deleted
状态,然后新写入一条数据。
merge
操作时会将多个 segment file
合并成一个,同时将标识为 deleted
的 doc
「物理删除」 ,将新的 segment file
写入磁盘,最后打上 commit point
标识所有新的 segment file
。
相关文章:

Elasticsearch-增删改查数据工作原理
集群 集群的基本概念: 集群:ES 集群由一个或多个 Elasticsearch 节点组成,每个节点配置相同的 cluster.name 即可加入集群,默认值为 “elasticsearch”。节点:一个 Elasticsearch 服务启动实例就是一个节点ÿ…...
IO进、线程——守护进程
守护进程 守护进程的创建过程 1、创建子进程,并退出父进程: 守护进程的创建通常通过fork()系统调用实现。fork()会创建一个新的子进程,该子进程是调用进程(父进程)的副本。父进程会继续执行fork()之后的代码&#x…...

通过v-for生成的input无法连续输入
部分代码:通过v-for循环生成el-form-item,生成多个描述输入框 更改之前的代码(key绑定的是item): <el-form-item class"forminput" v-for"(item,index) in formdata.description" :key"…...
Ventoy 使用教程图文详细版
文章目录 Ventoy 使用教程图文详细版简介安装 Ventoy下载 Ventoy制作基于 Ventoy 的启动U盘使用 Ventoy复制 ISO 文件启动电脑选择 ISO 文件结论Ventoy 使用教程图文详细版 简介 Ventoy 是一款开源的 U盘 启动工具,设计用于简化从 U盘 启动操作系统的过程。其中最主要的特点是…...

脚手架 --- command框架<一>
版本:6.0.0 假设脚手架名称:big-cat-cli 实例化 const commander require(commander) const program new commander.Command()program 基本信息配置 program.name(Object.keys(pkg.bin)[0]) // 赋值name, 显示在useage 前部分.usage(<command>…...
SpringBoot整合Zookeeper
引入Jar包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>s…...
Java和C#选哪个?
选择语言是一个非常重要的决定,因为它可能会对你的职业生涯产生深远的影响。C#和Java都是非常流行的编程语言,它们都有自己的优点和适用场景。 可以从下面几个方面来考虑: 1、就业前景: 就业前景是选择专业时需要考虑的一个非常…...

首批!棱镜七彩通过汽车云-汽车软件研发效能成熟度模型能力评估
2023年7月25-26日,由中国信息通信研究院、中国通信标准化协会联合主办的“2023年可信云大会”隆重召开。会上,在中国信息通信研究院云计算与大数据研究所副所长栗蔚的主持下,中国信通院发布了“2023年上半年可信云评估结果”,并由…...

【Docker】容器的数据卷
目录 一、数据卷的概念与作用 二、数据卷的配置 三、数据卷容器的配置 一、数据卷的概念与作用 在了解什么是数据卷之前我们先来思考以下这些问题: 1.如果我们一个容器在使用后被删除,那么他里面的数据是否也会丢失呢?比如容器内的MySQL的…...

CentOS7安装jenkins
一、安装相关依赖 sudo yum install -y wget sudo yum install -y fontconfig java-11-openjdk二、安装Jenkins 可以查看官网的安装方式 安装官网步骤 先导入jenkins yum 源 sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo…...

Hadoop的伪分布式安装方法
实验环境: 操作系统:Linux (Ubuntu 20.04.5) Hadoop版本:3.3.2 JDK版本:1.8.0_162 hadoop与jdk的安装包可详见博客中: https://blog.csdn.net/weixin_52308622/article/details/131947961?spm1001.2014.3001.550…...

iOS 应用上架的步骤和工具简介
APP开发助手是一款能够辅助iOS APP上架到App Store的工具,它解决了iOS APP上架流程繁琐且耗时的问题,帮助跨平台APP开发者顺利将应用上架到苹果应用商店。最重要的是,即使没有配置Mac苹果机,也可以使用该工具完成一系列操作&#…...

【信号去噪】基于马氏距离和EDF统计(IEE-TSP)的基于小波的多元信号去噪方法研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
智驾SOC shell编程应用实战笔记
文章目录 1. 引言2. 基础2.1 "$"的作用3. 实战笔记3.1 统计某一端口的连接数3.2 获取当前脚本执行的绝对路径3.3 判断某一文件是否存在参考1. 引言 智驾SOC(System on a Chip)是指集成了处理器、存储器、外设和其他功能模块的片上系统,广泛应用于汽车领域中的智能…...

C#实现计算题验证码
开发环境:C#,VS2019,.NET Core 3.1,ASP.NET Core API 1、建立一个验证码控制器 新建两个方法Create和Check,Create用于创建验证码,Check用于验证它是否有效。 声明一个静态类变量存放列表,列…...

【lesson6】Linux下:第一个小程序,进度条代码
文章目录 准备工作sleep问题fflush回车与换行的区别 进度条代码 准备工作 sleep问题 首先我们来看一段代码: 这时候有个 问题这个代码是输出“hello world”还是先sleep三秒? 再来一段代码 这个代码是先sleep三秒还是先输出“hello world”ÿ…...
PostgreSQL实战-pg13主从复制切换测试
PostgreSQL实战-pg13主从复制切换测试 配置PostgreSQL的环境变量 修改/etc/profile文件, vim /etc/profile添加如下内容: # 指定postgres的数据位置 export PGDATA=/var/lib/pg13/data数据联动测试 清空数据表数据 TRUNCATE TABLE tablename;主库清空数据表数据 从库对…...
如何使用OpenCV库进行图像检测
import cv2 # 加载Haar级联分类器 face_cascade cv2.CascadeClassifier(cv2.data.haarcascades haarcascade_frontalface_default.xml) # 读取输入图像 img cv2.imread(input_image.jpg) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 使用Haar级联分类器进行人脸检测 …...

Mybatis中where 1=1 浅析
在一些集成mybatis的工程中经常看到where11 的代码,也有同事问我,这样写有什么用,下面对其进行简单的分析记录一下。 1、场景 看下面这样一段xml中的代码 <select id"queryBook" parameterType"com.platform.entity.Book…...

element中el-input组件限制输入条件(数字、特殊字符)
1、只能输入纯数字 <el-input v-model"aaa" type"text" input"(v)>(aaav.replace(/[^\d]/g,))" /> 2、只能输入纯数字和小数(比如:6.66) <el-input v-model"aaa" type"text&quo…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...