1. 首页 > 快讯

Elasticsearch写入原理,一看便知!-51CTO.COM

[[429936]]

图片来自趵突网

【51CTO.com原稿】Elasticsearch也以分布式存储和分布式搜索而闻名,那么数据是如何写入Elasticsearch来提供高质量的搜索服务的呢?

本文介绍了Elasticsearch索引文件写入流程,介绍了Elasticsearch集群架构的特点,索引文件如何通过路由写入到ES,写入的文件如何组合刷新以供用户搜索,Elasticsearch如何保证写入数据存储的可靠性。

我从以下三个方面来分享:

Elasticsearch集群与路由Elasticsearch文件合并与刷新Elasticsearch数据存储可靠性

Elasticsearch 集群与路由

在介绍如何将数据写入ES(以下使用ES,统称为Elasticsearch)之前,需要了解ES的集群架构,也就是说,了解数据如何存储在集群节点的ES中。

这里需要介绍几个关键词来帮助大家理解ES中的一些基本概念:

Node:用于运行的ES实例以进程的形式存在,节点运行在物理服务器上。索引文件(Index):是需要写入ES节点的数据,其数据模型信息Mapping(数据结构)和数据文件(数据内容)。索引文件可以分布在一个节点上,也可以分布在多个不同的节点上。 Shard:用于存储索引文件或部分索引文件信息。如果索引包含大量文档,而单个节点所在的物理服务器硬件能力有限,那么存储索引文件的容量就会受到限制。这种“大”的索引文件无法存储在一个节点中,因此ES提供了一种分片机制,允许一个索引文件存储在不同节点上的不同分片中。

索引文件可以按照一定的维度分为多个部分。每个部分都是一个分片,分片由节点管理。

一个节点(Node)将管理多个分片。分片可以属于同一个索引,也可以属于不同的索引。为了可靠性和可用性,相同索引的分片会尽可能分布在不同的节点(Node)上。

分片类型:分片是承载索引(数据)的基本单位。它可以分为两种类型:主分片和副本分片。

主分片将尽可能均匀地分布在不同的节点上。副本分片,顾名思义,是主分片的副本,用于提供数据的冗余副本。

一般来说,副本分片和主分片不会出现在同一个节点上。原因是当单个节点发生故障时,只会影响该节点上的分片,而其他节点上的分片仍然可以正常工作。

需要注意的是,只有主分片可以处理索引写入请求,副本分片仅用于存储数据。

Replica:同一个分片(Shard)的备份数据。一个分片可能有0 个或多个副本。这些副本中的数据保证强一致或最终一致。

前面介绍了ES的基本概念后,我们对ES的数据存储有了一个大概的了解。索引会按照规则进行分片,分片分为主分片和副本分片。

主分片用于处理索引写入请求,副本分片用于存储索引数据。分片将在节点上运行,节点将在物理服务器上运行。

由于ES的分布式数据存储模型,索引数据会存储在不同的节点和分片上。因此写入索引时需要遵循一定的规则,这就是接下来要介绍的路由规则。

ES的路由规则是在多分片索引写入数据时,通过路由来决定写入哪个分片。这个判定过程是通过下面的公式来实现的:

shard=hash(routing)%number_of_primary_shardsrouting 是一个变量值。默认是文档的_id,也可以设置为自定义值。

Routing通过hash函数生成一个数字,然后用这个数字除以number_of_primary_shards(主分片的数量)得到余数。

0 和number_of_primary_shards 之间的余数是正在查找的文档所在分片的位置。

这就解释了为什么主分片的数量在索引创建时就确定了,并且永远不会改变:因为如果数量改变,之前所有的路由值都将失效,文档将不再被找到。

索引中的每个文档都属于一个单独的主分片,因此主分片的数量决定了索引可以存储多少数据(实际数量取决于数据、硬件和应用场景)。

下面通过一个例子来帮助您理解上面的路由公式。 ES集群中的每个节点通过路由知道集群中文档的存储位置,因此每个节点都有能力处理读写请求。

这种节点称为协调节点。协调节点会根据路由公式计算出需要写入哪个分片,然后将请求转发到该分片的主分片节点。需要注意的是,虽然协调节点根据路由规则将写请求转发到主分片。

如图1所示,有三个节点:ES1、2、3。每个节点包含多个分片,其中S0、1、2、3为主分片,其他以“R”开头的为副本分片。

图1:ES写入数据的路由流程

这里的路由规则是shard=hash(routing) % 4=0,其中4是主分片的数量。假设结果为“0”,即数据写入S0主分片。

路由流程大致如下:

客户端向ES1节点(协调节点)发送写请求,通过路由计算公式得到的值为0,则当前数据应该写入主分片S0。 ES1节点将请求转发到S0主分片所在的节点ES3。 ES3接受请求并将其写入磁盘。将数据并发复制到两个副本分片R0,通过乐观并发控制数据冲突。一旦所有副本分片报告成功,节点ES3 将向协调节点报告成功,协调节点将向客户端报告成功。上述写入过程涉及到协调节点、主分片和副本分片的数据写入。这里我们就进一步分析一下这三个块的写法。

协调(coordinating)节点

ES中接收并转发请求的节点称为协调节点。 ES中的所有节点都可以接受并转发该请求。

当节点收到写入或更新请求时,它将执行以下操作:

ingest pipeline:是一个请求预处理管道,会按照规则对请求进行预处理。

它将检查请求是否与摄取管道的模式匹配。如果匹配,就会执行管道中的逻辑。它通常会对文档进行各种预处理,例如格式调整、添加字段等。

自动创建索引:判断索引是否存在。如果启用自动创建,则会自动创建。否则会报错。

设置 routing:获取请求URL或映射中的_routing。如果没有,请使用_id。如果不指定_id,ES会自动生成一个全局唯一的ID。 _routing 字段用于确定文档被分配到索引中的哪个分片。

构建 BulkShardRequest:创建多操作请求。假设Bulk Request包含多个(Index/Update/Delete)请求,并且这些请求需要在不同的分片上执行。

这一步需要根据分片区分请求,将同一个分片上的请求聚合在一起构建BulkShardRequest。

将请求发送给 primary shard:如果用户请求是写操作,则该请求会被路由到主分片所在节点,并等待主分片写入结果的返回信息。

主分片

主分片请求的入口点是PrimaryOperationTransportHandler的MessageReceived。

收到请求后,执行以下步骤:

判断操作类型:如果是Bulk Request,会遍历请求中的子操作,根据不同的操作类型跳转到不同的处理逻辑。

操作转换:将更新操作转换为索引和删除操作。

解析文档(Parse Doc):解析文档的各个字段。

更新 Mapping:如果请求中有新字段,将根据动态映射或动态模板生成相应的映射。如果映射中有动态映射相关设置,则按照设置进行处理。

获取 sequence Id 和 Version:从SequenceNumberService 获取SequenceID 和版本。

SequenceID用于初始化LocalCheckPoint,version以当前版本为基础+1,防止并发写入导致数据不一致。

写入 Lucene:锁定索引文档uid,然后判断该uid对应的版本v2与上次更新转换时的版本v1是否一致。如果不一致,则返回第二步,重新执行。

如果版本一致,则根据id进行添加或更新操作。如果同id的doc已经存在,则调用updateDocument接口。

写入 translog:写入Lucene Segment后,Translog会以key value的形式写入。 Key 是Id,Value 是索引文档的内容。

查询时,如果请求是GetDocById,则可以根据_id直接从translog中获取。写入translog的操作将在后续章节详细讲解。

重构 bulk request:多个操作中的更新操作已转换为索引和删除操作,最终以索引或删除操作的形式组成批量请求请求。

落盘 Translog:默认情况下,translog 将在此处下载到磁盘。如果可靠性要求不高,可以设置translog异步下载,但存在数据丢失的风险。

发送请求给副本分片:将构造好的批量请求发送到各个副本分片,等待副本分片返回后再响应协调节点。如果某个分片执行失败,主分片会向主节点发送删除该分片的请求。

等待 replica 响应:当所有副本分片返回请求时更新主分片的LocalCheckPoint。

副本分片

副本分片请求的入口点是ReplicaOperationTransportHandler 中的messageReceived。总体流程与初次分片类似。相同的步骤在此不再描述。

列出来供大家参考:

判断操作类型:写请求已转换为对主分片的增删操作,只需根据操作类型执行即可。 Parse Doc:相同主分片。更新映射:同主分片。获取sequenceId和Version:使用从主分片发送的内容。写入Lucene:共同主分片。写入Translog:相同的主分片。删除translog:相同主分片。

Elasticsearch 文件合并与刷新

前面介绍了ES索引的写入流程。当索引保存到ES集群时,会通过路由规则找到对应的分片写入数据。主分片收到数据后,也会同步到副本分片。完成整个写作。

了解了文件写入流程后,我们再仔细看看写入细节,看看索引最终是如何通过内存写入磁盘的。

如图2所示,这里列出了索引写入的步骤,写入操作分别在内存和磁盘中完成。

图2:ES写入流程

如图2所示,写入操作的每一步拆解如下:

写请求会将索引(Index)存储到一个称为Index Buffer的内存区域中。此时的索引文件暂时无法被ES搜索到。

默认情况下,ES每秒执行一次Refresh操作,将Index Buffer中的索引写入Filesystem,Filesystem也是一块内存区域。

将Index Buffer中的索引转换为Segment,此时的数据就可以被ES搜索到了。

这也是ES的近实时搜索。当索引保存到Index Buffer中后,只有刷新到Segment中才能被搜索到。

需要说明的是,Refresh的触发有两种条件,其中之一就是根据时间频率触发。默认是每1秒触发一次刷新,可以通过index.refresh_interval来设置。

这就是为什么人们称Elasticsearch 为近实时搜索。

另一种触发方式是当Index Buffer满时触发Refresh。 Index Buffer的默认大小是JVM占用内存容量的10%。

Refresh后,Index Buffer中的数据会被写入到Segment中,此时Index Buffer中的数据会被清除。

ES每次刷新都会生成一个Segment文件,所以Segment文件会越来越多。

由于每个Segment都会占用文件句柄、内存、CPU资源,因此假设每个搜索请求都会访问对应的Segment来获取数据。这意味着更多的Segment会增加搜索请求的负担,导致请求变得更慢。

为了提高搜索性能,ES会定期对Segment进行合并操作,即将多个小Segment合并为一个Segment。然后搜索请求直接访问合并后的Segment,从而提高搜索性能。

以上三步都是在内存中完成的,数据还没有写入磁盘。随着段的增长,内存空间有限,因此需要将数据写入磁盘。

因此,合并完成后,新的Segment文件会被Flush写入磁盘。此时ES会创建一个Commit Point文件,用于标识刷新到磁盘的Segment。

由于Segment是从内存提交到磁盘的,所以需要这个Commit Point文件来记录。它记录了Segment的目的地。合并前的旧Segment和小Segment将从其中移除。

为此,Commit Point 将创建一个.del 文件来存储删除的Segment 信息。

需要注意的是,Flush的目的是为了持久化。毕竟,Segment 存储在内存中,并且必须始终保存到磁盘上。

执行Flush时,会依次执行以下操作:

索引缓冲区被清除并记录。 Commit PointFilesystem Buffer中的Segment通过fsync刷新到磁盘。 translog被删除(translog后面会详细介绍)。 Flush触发的条件是每30分钟或者translog达到一定大小(由index.translog.flush_threshold_size控制)。默认512mb),也就是说满足上述条件时ES才会触发Flush。

Elasticsearch 数据存储可靠性

前面讲解了ES的文件合并和刷新,分四步详细介绍了索引写入过程。

索引文档最初存储在内存中的索引缓冲区中。当执行Refresh操作时,它会被保存为一个Segment,然后用户可以查询。

但是Flush之前Segment仍然存在于内存中。如果此时服务器崩溃,ES还没有进行Flush操作,那么内存中存储的Segment数据就会丢失。

为了提高ES数据存储的可靠性,引入了Translog。用户每次请求Index Buffer进行操作时,都会向Translog写入一条操作记录。 Translog 使用独特的机制将其保存到磁盘。

默认情况下,ES会为每个请求同步Translog到磁盘,即为请求配置index.translog.durability。

不过这样会影响ES的性能,所以对于一些可以容忍数据丢失的场景可以设置异步磁盘磁盘操作。

Index.translog.durability可以配置为async,以提高写入Translog的性能,即会将translog异步写入磁盘。写入磁盘的频率是通过index.translog.sync_interval 控制的。

另外,随着Translog中的请求数量不断扩大,需要将其整体保存到磁盘,就像段合并文件一样。

这也是上一节提到的Flush操作。当Flush操作刷新Segment的时候,也会刷新Translog。

每次Flush后,由于Translog已经被flush,所以原来的Translog会被移除,并在内存中重新创建一个新的Translog。

由于Translog是追加写入,所以性能相对优越。当机器宕机时,启动ES服务时会读取Translog信息,回放中间操作命令来恢复数据。

继续上一节的示例,将Translog 部分添加到原始部分。如图3所示,在整个ES写入流程中加入Translog,是为了提高ES数据存储的可靠性。

图3:Translog 简介

图中,Translog存在于内存和磁盘中,有两条线分别连接它们,表示Translog同步的两种方式:

Translog是ES处理用户请求时附加的,附加的内容是对ES的请求操作。此时,操作记录的附加信息会根据配置以同步或异步的方式保存到磁盘中。另一种从内存到磁盘的Translog操作是发生Flush时。正如上一节中介绍的,Flush 操作会将Segment 保存到磁盘,并将Translog 文件删除到磁盘。下载磁盘后,内存中存在的Translog将被删除。

总结

综上所述,本文重点介绍ES的编写过程。首先介绍了ES的基本定义,然后从写请求开始介绍ES集群和路由实现。

ES根据路由将写请求通过协调节点发送到主分片,然后主分片将数据同步到副本分片。

然后介绍了协调节点、主分片和副本分片的写操作。从宏观上了解了ES的写入过程后,我们再从微观上描述索引文档如何通过内存写入磁盘的过程。

索引文档写入Index Buffer后,会通过Refresh操作保存到Filesystem的内存缓冲区中。此时,写入的索引文档将被转换为Segment,可供用户搜索。

同时,随着Segments数量的增加,ES提供了合并机制,将多个小Segment合并成大Segment,从而提高搜索效率。

为了提供ES数据存储的可靠性,使用Translog机制追加ES请求命令,使用Flush机制将内存中的Segment和Translog刷新到磁盘。

作者:崔浩

简介: 十六年开发和架构经验。曾在惠普武汉交付中心担任技术专家、需求分析师、项目经理,后在一家创业公司担任技术/产品经理。善于学习,乐于分享。目前专注于技术架构和研发管理。

编辑:陶家龙

征稿:如果您有兴趣提交文章或寻求报道,请联系editor@51cto.com

【51CTO原创稿件,合作网站转载请注明原作者及出处:51CTO.com】

OK,关于Elasticsearch写入原理,一看便知!-51CTO.COM和的内容到此结束了,希望对大家有所帮助。

用户评论

容纳我ii

终于找到一篇解释 Elasticsearch 写入原理的文章了,之前总是卡在这块

    有5位网友表示赞同!

顶个蘑菇闯天下i

elasticsearsh 大家都在用,我自己也偶尔会操作,但其实不太了解其背后的运作机制,看这篇文章应该能有所收获

    有9位网友表示赞同!

哽咽

"一看便知" 这个标题有点自信啊,哈哈!感觉文章风格轻松幽默

    有20位网友表示赞同!

墨染年华

我一直对搜索引擎的底层原理感兴趣,这个 Elasticsearch 的写逻辑挺重要的吧?

    有6位网友表示赞同!

淡抹烟熏妆丶

如果能用通俗易懂的方式解释写入原理,那这份文章真的太棒了!

    有6位网友表示赞同!

陌離

看简介说很详细,感觉可以参考一下做个笔记,下次遇到相关问题方便查询

    有20位网友表示赞同!

初阳

我最近在学习Elasticsearch,这篇文章刚好对我有帮助

    有16位网友表示赞同!

無極卍盜

51CTO写的文章一直质量都比较高,这个 Elasticsearch 写入原理的文章应该也能值得一看

    有6位网友表示赞同!

拽年很骚

刚开始的时候用 Elasticsearch 的时候总觉得有些莫名其妙,希望通过这篇文章能理清思路

    有7位网友表示赞同!

巷口酒肆

学习新技术有时候会遇到瓶颈,希望这篇关于 Elasticsearsh 写入原理的文章能破开我的思考盲点

    有20位网友表示赞同!

水波映月

对于开发人员来说理解 Elasticsearch 的写入机制非常重要!

    有20位网友表示赞同!

孤者何惧

以前从未关注搜索引擎的细节,这次有机会从文章学习一些基础知识

    有15位网友表示赞同!

╯念抹浅笑

看标题感觉内容应该比较浅显易懂,适合小白入门学习

    有10位网友表示赞同!

尘埃落定

希望文章能详细解释不同类型数据在 Elasticsearch 中的写入流程

    有8位网友表示赞同!

优雅的叶子

如果能结合案例讲解,更能够加深理解,期待作者能做更深入的分析

    有11位网友表示赞同!

空巷

Elasticsearch 的应用场景还挺广泛的,了解它的写入机制更能帮助我选择合适的数据存储方案

    有9位网友表示赞同!

各自安好ぃ

对于想要学习 Elasticsearch 相关技术的同学来说,这篇文章绝对是一个很好的入门教程

    有12位网友表示赞同!

暖栀

相信通过阅读这篇文章,我能对 Elasticsearch 就有一个更加清晰的认识

    有13位网友表示赞同!

无所谓

希望作者能分享更多关于 Elasticsearch 的实用技巧和经验

    有11位网友表示赞同!

情字何解ヘ

期待看到更多有关 Elasticsearch 的文章,深入探讨其高级特性和应用方法!

    有6位网友表示赞同!

本文采摘于网络,不代表本站立场,转载联系作者并注明出处:https://www.iotsj.com//kuaixun/7891.html

联系我们

在线咨询:点击这里给我发消息

微信号:666666