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,不可低于100msindex.translog.sync_interval: 120s
##超过这个大小会导致flush操作,产生新的Lucene分段。默认值为512MBindex.translog.flush_threshold_size: 1024mb

通过这种方式当断电或需要重启时,ES 不仅要根据提交点去加载已经持久化过的段,还需要工具 Translog 里的记录,把未持久化的数据重新持久化到磁盘上,避免了数据丢失的可能。

图中 Translog 存在于内存和磁盘中,分别有两个线将其相连,表示了 Translog 同步的两种方式:

  • 在 ES 处理用户请求时追加 Translog,追加的内容就是对ES的请求操作。此时会根据配置同步或者异步的方式将操作记录追加信息保存到磁盘中。

  • 另一种 Translog 从内存到磁盘的操作是在 Flush 发生的时候,上节中介绍过,Flush 操作会把 Segment 保存到磁盘同时还会将 Translog 的文件进行落盘。落盘以后存在与内存中的 Translog 就会被移除。

索引检索

在执行文档的CRUD操作时,通过文档ID就能计算出文档存储在哪个分片中,所以只要将客户端请求转发给对应的分片(或其副本)所在的节点进行处理即可。

而执行文档搜索操作时只会提供搜索条件,并不包含文档ID,无法直接知道哪些分片包含搜索结果,需要先搜索所有的分片(或其副本),还要对每个分片上的结果进行汇总以得到最终结果。所以,文档的搜索过程会分为如下两步执行:

  1. 搜索所有的分片(或其副本),确定哪些文档属于搜索结果;

  2. 从相关分片上读取文档数据,再汇总组装成最终的结果;

将第一步称为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

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

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

相关文章

安全测试国家标准解读——数据库管理和文件管理

下面的系列文章主要围绕《GB/T 38674—2020 信息安全技术 应用软件安全编程指南》进行讲解,该标准是2020年4月28日,由国家市场监督管理总局、国家标准化管理委员会发布,2020年11月01日开始实施。我们对该标准中一些常见的漏洞进行了梳理&…

【设计模式】代理模式

5.1 代理模式 5.1.1 概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。 Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静…

linux安装nginx遇到的报错

1、Linux如何修改只读文件(以设置自动连网为例) vim /etc/sysconfig/network-scripts/ifcfg-ens33 然后提示 E45:已设定选项“readonly”(请加!强制执行) 如果需要强制修改,可以使用&#xff0…

浏览器协议TCP详解

浏览器协议TCP详解 浏览器进程负责存储、界面、下载等管理。在渲染进程中,运行着熟知的主线程、合成线程、JavaScript 解释器、排版引擎等。 浏览器进程处理用户在地址栏的输入,然后将 URL 发送给网络进程。网络进程发送 URL 请求,在接收到响…

GitLab 删除项目

1.点击头像 2.点击Profile 3.选择要删除的项目点进去 4.settings-general-Advances-expand 5.然后在弹出框中输入你要删除的项目名称即可

RNN架构解析——GRU模型

目录 GRU模型实现优点和缺点 GRU模型 实现 优点和缺点

uniAPP 视频图片预览组件

效果图 思路&#xff1a;处理文件列表&#xff0c;根据文件类型归类 已兼容 H5 ios 设备&#xff0c;测试已通过 浙政钉&#xff0c;微信小程序 视频资源因为&#xff0c;没有预览图&#xff0c;用灰色图层加播放按钮代替 <template><!--视频图片预览组件 -->&l…

Consul的容器服务更新与发现

Consul的容器服务更新与发现 一&#xff1a;Docker consul的容器服务更新与发现&#xff08;1&#xff09;什么是服务注册与发现&#xff08;2&#xff09;什么是consulconsul提供的一些关键特性&#xff1a; 二&#xff1a;consul 部署consul服务器1. 建立 Consul 服务2. 查看…

quartus工具篇——ROM ip核

quartus工具篇——ROM ip核 1、ROM简介 FPGA中的ROM(Read-Only Memory)是一种只读存储器,主要用来存储固化的初始化配置数据。FPGA ROM的特性主要有: 预编程初始化 - ROM在FPGA编程时就已经写入了初始值,这些值在整个工作周期保持不变。初始化配置 - ROM通常用来存储FPGA的初…

【图论】三种中心性 —— 特征向量、katz 和 PageRank

维基百科&#xff1a;在图论和网络分析中&#xff0c;中心性指标为图中相应网络位置的节点分配排名或数值。中心性这一概念最初起源于社交网络分析&#xff0c;因此很多衡量中心性的术语也反映了其社会学背景。 不同中心性指标对 “重要” 的衡量方式不同&#xff0c;因此适用于…

YoLoV7做图像分类/目标检测过程(附代码+详细操作说明)

一、准备数据 图像在my_1imgs中&#xff0c;一个是原图jpg&#xff0c;一个是用labelimg画的标签xml文件。&#xff08;这个画的是一个矩形框&#xff09; 把自己的数据集&#xff08;原图和标签准备好后&#xff09;&#xff0c;这两个文件复制到VOCdevkit中,ImageSets为空。 …

多线程(JavaEE初阶系列5)

目录 前言&#xff1a; 1.什么是定时器 2.标准库中的定时器及使用 3.实现定时器 结束语&#xff1a; 前言&#xff1a; 在上一节中小编给大家介绍了多线程中的两个设计模式&#xff0c;单例模式和阻塞式队列模式&#xff0c;在单例模式中又有两种实现方式一种是懒汉模式&a…

Neo4j图数据基本操作

Neo4j 文章目录 Neo4jCQL结点和关系增删改查匹配语句 根据标签匹配节点根据标签和属性匹配节点删除导入数据目前的问题菜谱解决的问题 命令行窗口 neo4j.bat console 导入rdf格式的文件 :GET /rdf/ping CALL n10s.graphconfig.init(); //初始化 call n10s.rdf.import.fetch(&q…

从Arweave开始:4EVERLAND存储签入挑战开始

嗨&#xff0c;4evers&#xff0c; 今天&#xff0c;我们热烈欢迎您参加 Galxe 上的 4EVERLAND “Arweave 入门”活动。这是一项长期的重头活动&#xff0c;所有参与的用户都有机会获得相应的奖励。 Arweave 是一种革命性的去中心化存储协议&#xff0c;为寻求安全可靠的有价…

ubuntu 开启 ssh 服务 设置root远程登录

设置root用户密码 sudo passwd root安装ssh服务和vim编辑器 sudo apt -y install openssh-server vim开启ssh服务 sudo vim /etc/ssh/ssh_config去掉 配置文件中 Port 22 的注释后保存退出 设置root用户远程登录 sudo vim /etc/ssh/sshd_config将 PermitRootLogin prohibit-pas…

html学习1

1、<!DOCTYPE html>用来告知 Web 浏览器页面使用了哪种 HTML 版本。 2、对于中文网页需要使用 <meta charset"utf-8"> 声明编码&#xff0c;否则会出现乱码。 3、html的结构图&#xff0c;<body> </body>之间的部分可以显示。 4、HTML元素…

[语义分割] DeepLab v2(膨胀卷积、空洞卷积、多尺度信息融合、MSc、ASPP、空洞空间金字塔池化、Step学习率策略、Poly学习率策略)

DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolution, and Fully Connected CRFs 论文地址&#xff1a;DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolution, and Fully Connected CRFs源码地址&…

C# IO 相关功能整合

目录 删除文件和删除文件夹 拷贝文件到另一个目录 保存Json文件和读取Json文件 写入和读取TXT文件 打开一个弹框&#xff0c;选择 文件/文件夹&#xff0c;并获取路径 获取项目的Debug目录路径 获取一个目录下的所有文件集合 获取文件全路径、目录、扩展名、文件名称 …

8款常用系统镜像烧录软件

系统烧录软件是一种用于将操作系统或其他软件程序安装到嵌入式系统、嵌入式设备或存储设备中的工具。它通常用于将预先编译好的二进制文件或源代码烧录到硬件设备的非易失性存储器中&#xff0c;例如闪存芯片、EEPROM、EPROM或其他存储介质。系统烧录软件提供了一个便捷的方式&…

matplotlib

目录 plot bar pie plot plot可以绘制点图和线图 ?plt.plot #使用?查看plot详细信息 x[1,2,3,4,5] y[16,17,18,19,20] plt.plot(x,y) import numpy as np xnp.arange(0,10) yx*x plt.plot(x,y) xnp.arange(5,15,0.1) ynp.sin(x) plt.plot(x,y,ro) #red circle markers p…