草庐IT

深入理解Elasticsearch分片

咦940 2023-12-02 原文

目录

前言

了解分片的基本原理,对Elasticsearch性能调优有帮助。

关系梳理

ES底层使用的是Lucene库,ES的分片(shard )是Lucene的索引,ES的索引是分片的集合,Lucene的索引是由多个段(segment)组成。

段(segment)

Per-segment search,也即按段搜索,是Lucene中的概念。每个段本身就是一个倒排索引,Lucene中的索引除了表示段的集合外,还增加了提交点的概念,一个提交点就是一个列出了所有已知段的文件。

Per-segment search的工作流程如下:

  1. 新的文档首先被写入内存区的索引缓存(buffer)。
  2. 不时,这些buffer被提交。
  3. 新段被打开,它包含的文档可以被检索。
  4. 内存的缓存被清除,等待接收新的文档。

提交

一次完整的提交会将段刷到磁盘,并写入一个包含所有段列表的提交点。ES在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。

不可变性

写入磁盘的倒排索引是不可变的,也即段是不可改变的,所以既不能把文档从旧的段中移除,也不能修改旧的段来更新文档。取而代之的是,每个提交点会包含一个 .del 文件,它记录了段中被删除的文档。

当一个文档被 “删除” 时,它实际上只是在 .del 文件中被标记为删除。一个被标记为删除的文档仍然可以被查询匹配到,但它会在最终结果被返回前从结果集中移除。

文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记为删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前会被移除。

近实时搜索

提交一个新的段到磁盘需要调操作系统的fsync方法,确保段被物理地写入磁盘,即使断电也不会丢失数据。但是fsync是昂贵的,它不能在每个文档被索引时就触发。所以需要一种更轻量级的方式使新的文档可以被搜索。

位于ES和磁盘间的是文件系统缓存。在内存索引缓存中的文档被写入新的段,新的段首先写入文件系统缓存,这代价很低,之后会被同步到磁盘,这代价很大。一旦一个文件被缓存,它也可以被打开和读取,就像其他文件一样。

Refresh

在ES中,refresh是指这样一个过程:将In-memory buffer中的文档写入到文件系统缓存中新的段,新的段被打开(可被搜索)。默认情况下每个分片会每秒自动刷新一次。文档在In-memory buffer中是不能被搜索的,写入到段里面才能被搜索。这就是为什么我们说Elasticsearch是近实时搜索: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。

Flush

在ES中,进行一次提交并删除事务日志的操作叫做flush。一些老资料说ES每30分钟flush一次,或者事务日志过大也会flush。官网最新的说法是ES根据需要自动触发刷新,主要取决于事务日志的大小和权衡执行flush的成本。也可以调用flush API主动flush。

Translog

Translog全称transaction log(事务日志)。事务日志主要是为了防止在两次提交之间的数据丢失。事务日志也被用来提供实时 CRUD ,当你通过文档ID查询、更新、删除一个文档,在从相应的段检索之前, ES会首先检查事务日志最新的改动,这意味着ES总是能够通过文档ID实时地获取到文档的最新版本。

事务日志并不是实时落盘的,而是定期刷到磁盘。所以事务日志其实也是存在丢失的可能性的。那么这里就有一个问题,既然调用fsync的提交是一种昂贵的操作,为了防止数据丢失引入了事务日志,但是事务日志也需要刷到磁盘才能保证数据不丢,那事务日志的意义何在?答案是事务日志的刷盘更轻量级,因为它调用的是fdatasync这个系统函数,而不是fsync。感兴趣的可以了解下fsync和fdatasync的差别。

完整流程

我们将上述知识点串起来得到完整流程。

  1. 当一个文档被索引,它被加入到内存缓存,同时写入事务日志。

  1. 分片每秒都进行refresh。refresh后,内存缓冲区的文档被写入到文件系统缓存;段被打开,使得新的文档可以被搜索;缓存被清除。

  1. 更多的文档加入到缓冲区,写入事务日志,这个过程会持续。

  1. 不时的,比如事务日志很大了,会进行一次全提交。内存缓冲区的所有文档会写入到新的段中;缓冲区被清空;一个提交点写入磁盘;文件系统缓存通过fsync操作flush到磁盘;事务日志被清除。

合并段

通过每秒自动刷新创建新的段,用不了多久段的数量就爆炸了。每个段都会消费文件句柄、内存、CPU资源。更重要的是,每次搜索请求都需要依次检查每个段。段越多,查询越慢。

ES通过后台合并段解决这个问题。小段被合并成大段,再合并成更大的段。合并段时会真正删除被标记为已删除的文档。旧的段不会再复制到更大的新段中。这个过程你不必做什么,当你在索引和搜索时ES会自动处理。这个过程不会中断索引和搜索。

两个提交的段和一个未提交的段合并为了一个更大的段。

这期间发生一系列操作:新的段flush到了硬盘;新的提交点写入新的段,排除旧的段;新的段打开供搜索;旧的段被删除。

合并大的段会消耗很多IO和CPU,如果不合并又会影响到搜索性能。默认情况下,ES会限制合并过程,这样搜索就可以有足够的资源进行。optimize API可以强制合并段。

有关深入理解Elasticsearch分片的更多相关文章

  1. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  2. TimeSformer:抛弃CNN的Transformer视频理解框架 - 2

    Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图

  3. ruby - 易于初学者理解的 Ruby 库 - 2

    关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭3年前。Improvethisquestion我正处于学习Ruby的阶段,我想查看一些小型库的源代码以了解它们是如何构建的。我不知道什么是小型图书馆,但希望SO能推荐一些易于理解的图书馆来学习。因此,如果有人知道一两个非常小的库,这是新手Rubyists学习的好例子,请推荐!我想使用Manveru'sInnatelib,因为它试图保持在2000LOC以下,但我还不熟悉其中经常使用的Ruby速记。也许大约100-5

  4. ruby - 无法理解 `puts{}.class` 和 `puts({}.class)` 之间的区别 - 2

    由于匿名block和散列block看起来大致相同。我正在玩它。我做了一些严肃的观察,如下所示:{}.class#=>Hash好的,这很酷。空block被视为Hash。print{}.class#=>NilClassputs{}.class#=>NilClass为什么上面的代码和NilClass一样,下面的代码又显示了Hash?puts({}.class)#Hash#=>nilprint({}.class)#Hash=>nil谁能帮我理解上面发生了什么?我完全不同意@Lindydancer的观点你如何解释下面几行:print{}.class#NilClassprint[].class#A

  5. ruby - 如何理解 Ruby 中的发送者和接收者? - 2

    我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo

  6. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  7. ruby - Rails Elasticsearch 聚合 - 2

    不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a

  8. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  9. ruby-on-rails - 使用 Rails (Tire) 和 ElasticSearch 进行模糊字符串匹配 - 2

    我有一个Rails应用程序,现在设置了ElasticSearch和Tiregem以在模型上进行搜索,我想知道我应该如何设置我的应用程序以对模型中的某些索引进行模糊字符串匹配。我将我的模型设置为索引标题、描述等内容,但我想对其中一些进行模糊字符串匹配,但我不确定在何处进行此操作。如果您想发表评论,我将在下面包含我的代码!谢谢!在Controller中:defsearch@resource=Resource.search(params[:q],:page=>(params[:page]||1),:per_page=>15,load:true)end在模型中:classResource'Us

  10. ruby - 你如何理解 Ruby 中的这个三元条件? - 2

    我在某些代码中遇到了三元组,但我无法理解条件:str.split(/',\s*'/).mapdo|match|match[0]==?,?match:"somestring"end.join我确实理解我是在某些点上拆分字符串并将总结果转换为数组,然后依次处理数组的每个元素。除此之外,我不知道发生了什么。 最佳答案 一种(稍微)不那么令人困惑的写法是:str.split(/',\s*'/).mapdo|match|ifmatch[0]==?,matchelse"somestring"endend.join我认为多行三元语句很糟糕,尤其是

随机推荐