ES学习笔记

目录

1.基本概念和原理使用者

1.1 索引结构

1.2 分片

1.3 动态更新索引

1.4 近实时搜索

1.5 段合并

2.集群内部原理

2.1 集群节点角色

1.主节点

2.数据节点

3. 预处理结点 (Ingest node)

4.协调节点(Coordinating node)

5. 部落节点(Tribe node)

3.集群启动流程

3.1选举主节点

3.2 选举集群元信息

3.3 allocation过程

1. 选主分片

2.选副分片

3.4 index recovery

1. 主分片recovery

2.副分片recovery


1.基本概念和原理使用者

es是实时的分布式搜索分析引擎,内部使用Lucene做索引与搜索。

何谓实时? 新增到ES中的数据在1秒后几句能够被检索到,这种哦过年新增数据对搜索的可见性称为“准实时搜索”。分布式意味着可以动态调整集群规模,弹性扩容,而这一切操作起来都非常简便,用户甚至不需要了解集群的原理就可以实现。按官方描述,集群规模支持“上百”个节点,相比HDFs等上千台的集群这个规模是“小了点”,因此我们认为ES适合中等数据量的业务,不适合存储海量数据。

Lucene是Java语言编写的全文搜索框架,用于处理纯文本数据,但是它只是一个库,提供建立索引,执行搜索等接口,但不包含分布式服务,这些正式ES做的,什么是全文,对全部的文本内容进行分析,建立索引,使之可以被搜索,因此称为全文。

基于ES,你可以很容易搭建自己的搜索引擎,用于分析日志,或者配合开源爬虫建立某个垂直领域的搜索引擎。ES易用的产品设计使得它很容易上手。除了搜索,ES还提供了大量的聚合功能,所以它不单是一个搜索引擎,还可以进行数据分析,统计,生成指标数据。而这些功能都快速迭代,目前没两周就会发布新版本。

1.1 索引结构

ES是面向文档的,各种文本结构是以文档的形式存储到ES中,文档可以是一封邮件,一条日志,或者是一个网页的内容。一般使用JSON作为文档的序列化格式,文档可以有很多字段,在创建索引的时候我们需要描述文档中每个字段的数据类型,并且可能需要指定不同的分析器,就像关系型数据库中的CREATE TABLE一样。

在存储结构上,由_index、_type和_id唯一标识一个文档。

_index指向一个或多个物理分片的逻辑命名空间,_type类型用于区分同一个集合中的不同细分,在不同的细分中,数据的整体模式是相同或相似的,不适合完全不同类型的数据。多个_type可以在相同的索引中存在,只要他们的字段不冲突即可(对于整个索引,映射在本质上被扁平化为一个单一的,全局的模式)。_id文档标记由系统自动生成或者使用者提供。

很多初学者喜欢套用DBMS的概念将index_理解成数据库,将_type理解为表,这是一个很牵强的理解,实际上是完全不同的概念,没有什么相似性,不同_type下的字段不能冲突,删除整个_type也不会释放空间,在实际运用中,数据模型不同,有不同_type需求的时候,我们应该建立单独的索引,而不是在一个索引下建立不同的_type。删除过期老化的数据时,最好以索引为单位,而不是_type和_id,正由于_type在实际应用中容易引起概念混淆,以及允许索引存在多_type并且没有什么实际意义,在ES 6.x 版本中,一个索引只语序存在一个_type,未来的7.x版本将完全删除_type的概念。

1.2 分片

在分布式系统中单机无法存储规模巨大的数据,要依靠大规模集群处理和存储这些数,一般通过增加机器数量来提高系统水平扩展能力。因此,需要将数据分成若干大小块分配到各个机器上。然后通过某种路由策略找到某个数块所在的位置。

除了将数据分片以提高水平扩展能力,分布式存储中还会把数据复制成多个副本,放置到不同的机器上,这样一来,可以增加系统可用性,同时数据副本还可以使读操作并发执行,分担集群压力,但是多数副本也带来了一致性的问题,部门副本写成功,部分副本写实效,我们随后讨论。

为了应对并发更新的问题,ES将数副本分为主从两部分,即主分片(primary shard) 和副本分片(replica shard)。主数作为权威数,写过程先写朱分片,成功后再写副分片,恢复阶段以朱分片为主。数据分片和数据副本的关系如下图所示:

分片(shard)是底层的基本读写单元,分片的目的是为了分割巨大索引,让读写可并行操作,由多台机器共同完成,读写请求最终落到某个分片上,分片可以独立执行读写工作。ES利用分片将数据分发到集群内各处。分片是数的容器,文档保存在分片内,不会跨分片存储。分片又被分配到集群内的各个结点中。当集群规模扩大或缩小时,ES会自动再各个结点中迁移分片,使数据任然均匀的分布在集群中。

索引与分片的关系如下图所示:

一个ES索引包含多个分片,一个分片是一个Lucene的索引,它本身就是一个完整的搜索引擎,可以独立执行建立索引和搜索任务。Lucene索引又由很多分段组成,每个分段是一个倒排索引。ES每次refresh都会创建一个新的分段。其中包含若干文档的数据。在每个分段的内部,文档的不同字段被单独创建索引。每个分段的值由若干词组成(Term),Term是原文本内容进过分词器处理和语言处理后的最终结果(例如,去除标点符号和转换为词根)。

索引建立的时候就需要确定好主分片数,在较老的版本中(5.x之前)主分片数量不可以修改,副本分片数量可以随时去修改。5.x-6.x之后,已经支持一定条件的限制下,对某个索引的主分片进行拆分活缩小。但是我们任需要在一开始就尽量规划好主分片的数量;先依据硬件情况定好单个分片的容量,然后依据业务长宁预估数据量和增长量,再除以单个分片的容量。

分片数不够的时候,可以考虑新建索引,搜索一个有着50个分片的索引与搜索50个每个都有一根分片的索引完全等价,或者使用_split API来拆分索引。

在实际应用中,我们不应该向单个索引持续写数据,知道他们的分片巨大无比。巨大的索引会在数据老化后难以删除,以_id为单位的删除文档不会立即释放空间。删除的doc中只在Lucene分段合并时才会真正的从磁盘中删除。即手工触发分段合并,然然会引起较高的I/O压力,并且可能因为分段巨大导致在合并过程中磁盘不足(分段大小大于磁盘可用空间的一半)。因此我们建议周期性的创建新索引,例如每天创建一个,假如有一个索引website,可以将它命名为website_20180319。然后创建一个名为website的索引来关联这些索引。这样对于业务方来说读取时使用的名称不变,当需要删除数据的时候可以直接删除整个索引。

索引的别名就像一个快捷方式或软链接,不同的是它可以指向一个或者多个索引。可以用于实现索引分组,或者索引间无缝切换。

现在我们已经确定好主分片的数量,并且保证单个索引的数据量不会太大,周期性的穿件新索引带来的一个新问题是集群整体数量较多,集群管理的总分片数越多压力就愈大,在每天生成一个索引的场景中,可能某天产生的数据量很小,实际上不需要这么多分片,甚至一个就够,可以使用_shrink API来缩减主分片的数量,降低集群负载。

1.3 动态更新索引

为文档建立索引,使每个字段都可以被搜索,通过关键词检索文档内容,会使用倒排索引的数据结构,倒排索引一旦被写入文件后,就具有不变性,不变性具有很多好处:对文件的访问不需要加锁,读取索引时可以被文件系统缓存等。

那么索引如何更新,让新添加的文档可以被搜索到? 答案是使用更多的索引,新增内容并写到一个新的倒排索引中,查询时,每个倒排索引都可以被轮流查询,查询完再对结果进行合并。

每次内存缓冲的数据被写入文件时,会产生新的Lucene段,每个段都是一个倒排索引。在一个记录元信息的文件中描述当前Lucene索引都包含哪些分段。

由于分段的不变性,更新,删除等操作实际上是将数标记为删除记录到单独的位置,这种方式称为标记删除。因此删除数据不会释放磁盘空间

1.4 近实时搜索

在写操作中一般会先在内存中缓冲一段数据,再将这些数据写入硬盘,每次写入硬盘的这批数据称为一个分段,如同任何写操作一样,一般情况下(direct方式除外),通过操作系统write接口写到磁盘的数据先到达系统缓存(内存),write函数返回成功时,数据未必被刷到磁盘,通过手工调用flush,或者操作系统通过一定策略将系统缓存刷到磁盘。这种策略大幅提升了写入肖略。从write函数返回成功开始,无论数据有没有被刷新到磁盘,该数据已经对读取可见。

ES正是利用这种特性实现了近实时搜索,每秒产生一个新的分段,新段写入文件系统缓存,但稍后再执行flush刷盘操作,写操作很快会执行完,一旦写成功,就可以像其它文件一样被打开和读取了。

由于系统先缓冲一段数据才写,且新段不会立即被刷入磁盘,这两个过程中如果出现某些意外情况(如主机断电),则会存在丢失数据的风险。通用的做法是记录事务日志,每次对ES进行操作时均记录日志文件,当ES启动的时候,重放translog中所有最后一次提交后发生的变更操作,比如HBASE等都有自己的事务日志。

1.5 段合并

在ES中,每秒清空一次写缓冲,将这些数据写入文件,这个过程称为refresh,每次refresh会创建一个新的Lucene段。但是分段的数量太多会带来较大的麻烦,每个段都会消耗文件句柄、内存。每个搜索请求都需要轮流检查每个段,查询完再对结果进行合并:所以段越多,搜索也就越慢。因此需要通过一定的策略将这些较小的段合并为较大的段,常用的方案是选择大小相似的分段进行合并。在合并的过程中,标记为删除的数据不会写入新分段,当合并过程结束,旧的分段数据被删除,标记删除的数据才从磁盘删除。

Hbase,Cassandra等系统都有类似的分段机制,写过程先在内存缓冲一批数据,不时的将这些数据写入文件作为一个分段,分段具有不变性,再通过一些策略合并分段。分段合并过程中,新段产生需要一定的磁盘空间,我们要保证系统有足够的剩余可用空间。Cassandra系统在段合并的过程中的一个问题就是,当持续的向一个表中写入数据,如果段大小没有上线,当巨大的段达到磁盘空间的一半时,剩余空间不足以进行新段的合并过程,如果段文件设置一定的上限不再合并,则对表中部分数据无法真正的物理删除。ES存在同样的问题。

2.集群内部原理

分布式系统的集群方式大致可以分为主从(Master-Slave)模式和无主模式。ES,HDFS,HBASE使用主从模式,Cassandra使用无主模式,主从模式可以简化系统设计,Master作为权威节点,部分操作仅由Master执行,并负责维护集群元信息。缺点是Master节点存在单点故障,需要解决灾备问题,并且集群规模受限于Master节点的管理能力。

因此从集群节点角色的角度花粉,至少存在主节点和数据节点,另外还有协调节点、预处理节点和部落节点,下面分别介绍各种类型节点的职能。

2.1 集群节点角色

1.主节点

主节点负责集群层面的相关操作,管理集群的变更。

通过配置 node.master:true (默认) 使节点具有被选举为Master的资格。主节点是全局唯一的,将从有资格成为Master的结点中进行选举。

主节点也可以作为数据节点,但尽可能做少量的工作,因此生产环境应该尽量分离主节点和数据节点,创建独立主节点的配置:

node.master:true

node.data:false

为了防止数据丢失,每个主节点应该只要有资格成为主节点的数量,默认为1,为避免网络分区时出现多主的情况,配置discovery.zen.minimum_master_nodes原则上最小值应该是(master_eligible_nodes/2)+1

2.数据节点

负责保存数据、执行数据相关的操作:CRUD、搜索,聚合等。数据结点对CPU、内存、I/O要求较高,一般情况下(除一些例外)数据读写流程只和数据节点交互,不会和主节点打交道(异常情况除外)。

可以通过配置node.data:true(默认) 来使一个结点成为数据节点,也可以通过如下配置创建衣蛾数据节点:

node.master: false

node.data: true

node.ingest: false

3. 预处理结点 (Ingest node)

这是从5.0版本开始引入的概念,预处理操作允许在索引文档之前,即写入数据之前,通过事先定义好的一系列processor(处理器)和pipeline(管道),对数据进行某种转换,富华。processors和pipeline拦截bulk和index请求,在应用相关操作后将文档传回给index或bulk API。

默认情况下,在所有的结点上启用ingest,如果想在某个节点上禁用ingest,则可以添加配置node.ingest:false ,也可以通过如下配置创建一个仅用于预处理的结点:

node.master: false

node.data: false

node.ingest:true

4.协调节点(Coordinating node)

客户端请求可以发送到集群的任何节点,每个结点都知道任意文档所处的位置,然后转发这些请求,收集数据并返回给客户端,处理客户端请求的结点称为协调节点。

协调节点将请求转发给保存数据的数据节点。每个数据节点在本地执行请求,并将结果返回协调节点。协调节点手机完数据后,将每个数据节点的结果合并为单个全局结果。对结果手机和排序的过程可能需要很多的CPU和内存资源。(类似于vmselect)

通过下面的配置创建衣蛾仅用于协调的节点:

node.master: false

node.data: false

node.ingest: false

5. 部落节点(Tribe node)

tribes(部落) 功能允许部落节点再多个集群之间充当联合客户端。

在ES 5.0之前还有一个客户端节点(Node Client)的角色,客户端节点有以下属性:

node.master:fasle

node.data: false

它不做主节点,也不做数据节点,仅用于路由请求,本质上是一个智能的负载均衡器(从负载均衡器的定义来说,智能和非智能的区别在于是否知道访问的内容属于哪个节点)从5.0版本开始这个角色被协调节点(Coordinating only node )取代

3.集群启动流程

3.1选举主节点

假设有若干节点正在启动,集群启动的第一件事是从已知的活跃机器中选择一个作为主节点,选主之后的流程由主节点触发。

ES的选主算法是基于Bully算法的改进,主要思路是对节点ID排序,取ID值最大的结点作为Master,每个结点都运行这个流程。选主的目的是确定唯一的主节点,初学者可能以为选举出的主节点持有最新的元数据信息,实际上这个问题是在实现上被分解为两步:先确定唯一的、大家公认的主节点,再想办法把最新的机器元数据复制到选举出的主节点上。

基于节点ID排序的简单选举算法有三个附加约定条件:

(1)参选人数得过半,达到quorum(多数)后就选出了临时的主。为什么是临时的? 每个结点运行排序取最大值的算法,结果不一定相同。例如集群有五台机器,节点ID分别是1、2、3、4、5.当产生网络分区或者节点启动速度差异较大时,节点1看到的节点列表是1、2、3、4 选出4,节点2看到的节点列表是2、3、4、5 选出5 结果就不一致了,由此产下面两条限制。

(2) 得票数得过半。某节点被选择为主节点,必须判断加入它的节点数过半,才确认Master身份,解决第一个问题。

(3) 当探测到节点离开事件时,必须判断当前节点数是否过半,如果达不到quorum,则放弃Master身份,重新假如集群。如果不这么做,设想以下情况:假设5台机器组成的集群产生网络分区,2台一组,3台一组,产生分区前Master位于2台中的一个,此时3台一组的节点会重新并成功选取出Master,产生双主,俗称脑裂。

集群并不知道自己共有多少个节点quorum值从配置中读取,我们需要设置配置项:

discovery.zen.minimum_master_nodes

3.2 选举集群元信息

被选出的Master和集群元信息的新旧程度没有关系。因此它的第一个任务是选举元信息,让各节点把各自存储的元信息发过来,根据版本号确定最新的元信息,然后把这个信息广播下去,这样集群的所有结点都有了最新的元信息。

集群元信息的选举包括两个级别:集群级和索引级。不包含哪个shard属于哪个节点这种信息。这种信息以磁盘存储为准,需要上报。为什么呢,因为读写流程是不经过Master的,Master不知道各shard副本直接的数据差异。HSFS也有类似的机制,block信息依赖于DataNode的上报。

为了集群的一致性,参与选举的元信息数量需要过半,Master发布集群状态成功的规则也是等待发布成功的结点数过半。

在选举过程中,不接受新节点的加入请求。

集群元信息选举完毕后,Master发布首次集群状态,然后开始选举shard级元信息。

3.3 allocation过程

选举shard级元信息,构建内容路由表,是在allocation模块完成的,在初始阶段,所有的shard都处于UNASSIGNED(未分配)状态。ES通过分配过程决定哪个分片位于哪个节点,重构内容路由表。此时,首先要做的事就是分配主分片。

1. 选主分片

现在看某个主分片[website][0]是怎么分配的。所有的分配工作都是Master来做的,此时Master并不知道主分片在哪,它向集群中的所有节点询问:大家把[website][0]分片的元信息发给我,然后Master等待所有的请求返回,正常情况下它就有了这个shard的信息,然后根据某种策略选一个愤怒片作为主分片,是不是效率有点低?这种询问量=shard数x节点数。所以说我们最好控制shard的总规模别太大。

现在有了shard[website][0]的分片的多份信息,具体数量却绝育副本设置了多少。现在考虑把哪个分片作为主分片。在ES5.X版本一下,通过对比shard级元信息的版本号来决定。在多副本的情况下,考虑到如果只有一个shard信息汇报过来,则它一定被选择为主分片,但也许数据不是最新的。版本号比它大的那个shard所在的节点还没启动。在解决这个问题的时候ES5.X开始实施了一种新的策略:给每个shard设置一个UUID,然后在集群级的元信息中记录哪个shard是最新的,因为ES是先写主分片,再由主分片节点转发去写副分片,所以主分片所在的节点肯定是最新的,如果它转发失败了,则要求Master删除那个节点。所以从ES5.X开始,主分片选举的过程是通过集群级元信息中记录的“最新主分片的列表”来确定主分片的:汇报信息中存在,并且这个列表中也存在。

如果集群设置了:

"cluster.routing.allocation.enable":"none"

禁止分配分片,集群仍会强制分配主分片,因此在设置了上述选项的情况下,集群重启后状态为YELLOW,而非RED.

2.选副分片

主分片选举完成后,从上一个过程汇总汇总的shard信息中选择衣蛾副本作为副分片。如果汇总信息中不存在,则分配一个全新副本的操作依赖于延迟配置项:

index.unassigned.node_left.delayed_timeout

我们的线上环境中最大的集群有100+节点,掉节点的情况并不罕见,很多时候不能第一时间处理,这个延迟我么一般设置以天为单位。

最后,allocation过程中允许新启动的节点加入集群。

3.4 index recovery

分片分配成功后进入recovery流程。主分片的recovery不会等待其副分片成功才开始recovery,她们是独立的流程,只是副分片的recoeery需要主分片恢复完毕才开始。

为什么需要recovery? 对于主分片来说,可能有一些数据还没来得及刷盘;对于副分片来说一是没刷盘,而是主分片写完了,副分片还没来得及写,主副分片数据不一致。

1. 主分片recovery

由于每次写都会记录事务日志(translog),事务日志中记录了哪些操作,以及相关的数据。因此将最后一次提交(Lucene的一次提交就是一次fsync刷盘的过程)之后的translog中进行重放,建立Lucene索引,如此完成主分片的recovery

2.副分片recovery

副分片的恢复是比较复杂的,在ES的版本迭代中,副分片恢复策略有不少调整。

副分片需要恢复成与主分片一致,同时,恢复期间允许新的索引操作。在目前的6.0版本中,恢复分成两阶段执行。

  • phase1: 在主分片所在的节点,获取translog保留锁,从获取保留锁开始,会保留translog不受其刷盘清空的影响。然后调用Lucene接口把shard做快照,这是已经刷盘中的分片数据,把这些shard数据复制到副本节点。在phased1完毕前,回向副本节点发送告知对方启动engine,在phase2开始之前, 副本分片就可以正常处理写请求了。
  • phase2: 对translog做快照,这个快照里包含从phase1开始,到执行translog快照期间的新增索引。将这些translog发送到副分片所在节点进行重放。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
elasticsearch 学习笔记包括以下内容: 一、Elasticsearch概述: - Elasticsearch是一种开源的分布式搜索和分析引擎,可以用于快速搜索、分析和存储大量的结构化和非结构化数据。 - Elasticsearch与Solr相比有一些区别,包括用户、开发和贡献者社区的规模和成熟度等方面。 二、Elasticsearch安装: 1. 下载Elasticsearch,可以从官方网站或华为云镜像下载。 2. 安装Elasticsearch。 三、安装head插件: - head插件是一个可视化的管理界面,可以方便地管理和监控Elasticsearch集群。 四、安装Kibana: 1. Kibana是一个开源的数据可视化工具,用于展示和分析Elasticsearch中的数据。 2. 下载Kibana并安装。 3. 启动Kibana并进行访问测试。 4. 可选的汉化操作。 五、ES核心概念理解: - 学习ES的核心概念,包括索引、文档、映射、查询等。 以上是elasticsearch学习笔记的主要内容,希望对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Elasticsearch 学习笔记(上)](https://blog.csdn.net/m0_52691962/article/details/127064350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值