es核心原理

(一)节点类型:

1)master节点

整个集群只会有一个master节点,它将负责管理集群范围内的所有变更,例如增加、删除索引;或者增加、删除节点等。而master节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个master节点的情况下,即使流量的增加它也不会成为瓶颈。

master节点需要从众多候选master节点中选择一个。

node.master: true

node.data: false

master节点的作用:

1 负责集群节点上下线,shard分片的重新分配。

2 创建、删除索引。

3 负责接收集群状态(cluster state)的变化,并推送给所有节点。集群节点都各有一份完整的cluster state,只是master node负责维护。

4 利用自身空闲资源,协调创建索引请求或者查询请求,将请求分发到相关node服务器。

2)数据节点

1 负责存储数据,提供建立索引和搜索索引的服务。

2 data节点消耗内存和磁盘IO的性能比较大。

node.master: false

node.data: true

3)协调节点

不会被选作主节点,也不会存储任何索引数据。主要用于查询负载均衡。将查询请求分发给多个node服务器,并对结果进行汇总处理。

协调节点的作用:

第一:诸如搜索请求或批量索引请求之类的请求可能涉及保存在不同数据节点上的数据。 例如,搜索请求在两个阶段中执行(query 和fetch),这两个阶段由接收客户端请求的节点 - 协调节点协调。

第二:在请求阶段,协调节点将请求转发到保存数据的数据节点。 每个数据节点在本地执行请求并将其结果返回给协调节点。 在收集fetch阶段,协调节点将每个数据节点的结果汇集为单个全局结果集。

第三:每个节点都隐式地是一个协调节点。 这意味着将所有三个node.master,node.data设置为false的节点作为仅用作协调节点,无法禁用该节点。 结果,这样的节点需要具有足够的内存和CPU以便处理收集阶段。协调节点最好不要分离,跟数据节点在一起就行.

node.master: false

node.data: false

 

(二)Cluster State

1)什么是CLUSTER STATE

Cluster State是指集群中的各种状态和元数据(meta data)信息。其中,索引(Index)的mappings、settings配置、持久化状态等信息,以及集群的一些配置信息都属于元数据(meta data)。

元数据非常重要,标识了集群中节点状态、索引的配置与状态信息等;假如记录某个index的元数据丢失,那么集群就认为这个index不再存在。ES集群中的每个节点都会保存一份这样的元数据信息,这样在增删索引、节点场景下能够极大方便集群选主流程、集群的管理操作。

2) CLUSTER STATE的更新流程

ClusterState相关特性如下:

1. ClusterState是不可变对象,每次状态变更都会产生新的ClusterState,版本号随之更新

2. 在ES中, 集群状态由Master节点维护,并且只能由Master节点更新集群状态

3. Master节点一次处理一批集群状态更新,计算所需的更改并将更新后的新版集群状态发布到集群中的所有其他节点.

 

Cluster State的更新流程,实现了原子性和一致性,确保Cluster State能够反映集群中最新且真实的状态,为Master选举流程、错误检测、

集群扩缩容提供了高度的一致性保障。下面来详细分析:

1. 原子性保证:master节点进程内的不同线程更改ClusterState时,每次需提交一个Task给MasterService,

MasterService中只使用一个线程来串行处理这些Task,每次处理时把当前的ClusterState作为Task中execute函数的参数,

即保证了所有的Task都是在currentClusterState的基础上进行更改,然后不同的Task是串行执行的。

2. 一致性保证:

一致性 是为了解决这样一个问题,我们知道,新的集群状态一旦在某个节点上commit,那么这个节点就会执行相应的操作,比如删除某个Shard等,这样的操作是不可回退的。

而假如此时Master节点挂掉了,新产生的Master一定要在新的集群配置信息上进行更改,不能出现回退,否则就会出现集群配置数据回退了但是操作无法回退的情况;

ES使用两阶段提交方式(Add twophased commit to Cluster State publishing)实现一致性 。

所谓的两阶段提交,是把Master节点发布ClusterState分成两步,第一步是向所有节点推送最新的ClusterState,当有超过半数的master节点返回ack请求时,再发送commit请求,

要求节点commit接收到的新版ClusterState。如果没有超过半数的节点返回ack,则认为本次发布失败,同时退出master状态,执行rejoin重新加入集群。

image.png

每次发布大致流程如上图所示:

1. 首先由Master节点向集群中的所有节点广播新版本的集群状态;

2. 其他节点接收到新版集群状态后,均向Master节点发送ack确认请求,但此时并不立即应用新接收

的集群状态。

3. 一旦Master节点收到足够多的候选Master节点的确认请求,就认为新版集群状态已提交

(committed),继而广播commit请求,指示其他节点应用现在已提交的集群状态。

4. 每个节点接收到commit请求后,会把新版ClusterState发给该节点上相关的各个模块,各个模块根

据新版ClusterState判断是否要做什么操作,如创建Shard等;应用新版集群状态后,再将第二个

ack确认请求发送回Master节点。

5. 在Master节点开始处理并发布下一版本集群状态更新前,它一直处于等待状态,直到到达超时时间

或它收到集群中每个节点已应用新版集群状态的确认请求。其中,新版集群状态完全发布到所有节

点的超时时间,由 cluster.publish.timeout 这一配置设置,默认为从发布开始算起的30s。如

果在提交新版集群状态之前已达到该超时时间,则集群状态更改失败,并且Master节点认为退出

Master状态,并重新加入集群,开始尝试选举新的Master节点。如果新版集群状态在到达

cluster.publish.timeout 指定的超时时间前已提交,则Master节点认为更改已成功。

6. 如果没有收到某些节点确认已应用当前新版集群状态的请求,则这些节点被认为滞后节点,因为它

们的集群状态已落后于Master节点的最新状态。Master节点等待滞后节点再追赶

cluster.follower_lag.timeout 设定的时间,默认为90s。如果节点在该时间段内仍未成功应用

集群状态更新,则认为该节点已失败并将之从集群中删除。

 

(三)集群选举

1)选举的时机

master选举当然是由master-eligible节点发起,当一个master-eligible节点发现满足以下条件时发起选

举:

1. 该master-eligible节点的当前状态不是master。并且该master-eligible节点通过ZenDiscovery模

块的ping操作询问其已知的集群其他节点,没有任何节点连接到master。

2. 包括本节点在内,当前已有超过 minimum_master_nodes 个节点没有连接到master。

总结一句话,即当一个节点发现包括自己在内的多数派的master-eligible节点认为集群没有master时,

就可以发起master选举。

2)选举的过程

先根据节点的clusterStateVersion比较,clusterStateVersion越大,优先级越高。clusterStateVersion

相同时,进入compareNodes,其内部按照节点的Id比较(Id为节点第一次启动时随机生成)。

1. 当clusterStateVersion越大,优先级越高。这是为了保证新Master拥有最新的clusterState(即集群的meta),避免已经commit的meta变更丢失。因为Master当选后,就会以这个版本的

clusterState为基础进行更新。(一个例外是集群全部重启,所有节点都没有meta,需要先选出一个master,然后master再通过持久化的数据进行meta恢复,再进行meta同步)。

2. 当clusterStateVersion相同时,节点的Id越小,优先级越高。即总是倾向于选择Id小的Node,这个Id是节点第一次启动时生成的一个随机字符串。之所以这么设计,应该是为了让选举结果尽可能

稳定,不要出现都想当master而选不出来的情况。

 

(四)脑裂问题

1. 什么是脑裂现象

由于部分节点网络断开,集群分成两部分,且这两部分都有master选举权。就成形成一个与原集群一样名字的集群,这种情况称为集群脑裂(split-brain)现象。这个问题非常危险,因为两个新形成的集群会同时索引和修改集群的数据。

解决方案:

# 决定选举一个master最少需要多少master候选节点。默认是1。

# 这个参数必须大于等于为集群中master候选节点的quorum数量,也就是大多数。

# quorum算法:master候选节点数量 / 2 + 1

# 例如一个有3个节点的集群,minimum_master_nodes 应该被设置成 3/2 + 1 = 2(向下取整)

discovery.zen.minimum_master_nodes:2

# 等待ping响应的超时时间,默认值是3秒。如果网络缓慢或拥塞,会造成集群重新选举,建议略微调大这个值。

# 这个参数不仅仅适应更高的网络延迟,也适用于在一个由于超负荷而响应缓慢的节点的情况。

discovery.zen.ping.timeout:10s

# 当集群中没有活动的Master节点后,该设置指定了哪些操作(read、write)需要被拒绝(即阻塞执行)。有两个设置值:all和write,默认为wirte。

discovery.zen.no_master_block : write

 

(五)ES数据存储

1、存储流程

为了将数据添加到Elasticsearch,我们需要索引(index)——一个存储关联数据的地方。实际上,索引只是一个用来指向一个或多个分片(shards)的“逻辑命名空间(logical namespace)”.一个分片(shard)是一个最小级别“工作单元(worker unit)”,它只是保存了索引中所有数据的一部分。

当一个写请求发送到 es 后,es 将数据写入 memory buffer 中,并添加事务日志( translog )。如果每次一条数据写入内存后立即写到硬盘文件上,由于写入的数据肯定是离散的,因此写入硬盘的操作也就是随机写入了。硬盘随机写入的效率相当低,会严重降低es的性能。

因此 es 在设计时在 memory buffer 和硬盘间加入了 Linux 的页面高速缓存(File system cache)来提高es的写效率。当写请求发送到es后,es将数据暂时写入memory buffer中,此时写入的数据还不能被查询到。默认设置下,es每1秒钟将memory buffer中的数据refresh到Linux的File system cache ,并清空 memory buffer ,此时写入的数据就可以被查询到了。

但 File system cache 依然是内存数据,一旦断电,则 File system cache 中的数据全部丢失。默认设置下,es每30分钟调用fsync将 File system cache 中的数据 flush 到硬盘。因此需要通过translog来保证即使因为断电 File system cache 数据丢失,es 重启后也能通过日志回放找回丢失的数据。

translog 默认设置下,每一个 index 、 delete 、 update 或 bulk 请求都会直接 fsync 写入硬盘。为了保证 translog 不丢失数据,在每一次请求之后执行fsync确实会带来一些性能问题。对于一些允许丢失几秒钟数据的场景下,可以通过设置 index.translog.durability 和index.translog.sync_interval 参数让translog 每隔一段时间才调用 fsync 将事务日志数据写入硬盘。

image.png

1 不直接将每个document数据落盘,而是缓存到memory buffer中,有一秒的时间积累;

2 每隔一秒将内存的数据先刷新到操作系统的文件系统缓存,此时是已经保存到lucence的segment中了的,这些数据是可以用来查询的。

3 因为基本上每秒都会产生一个新的lucence segment文件,文件产生很快,一直去落到磁盘效率也很低,因此就每30分钟刷新一次。为了保证数据的不丢失,用translog记录这段时间的操作以便数据恢复

4文件系统缓存的segment 落到磁盘后,时间久了,磁盘上的segment文件会非常多,es会有专门的后台线程进行合并,针对于已经删除的,合并的时候就不要这些数据了。

 

(六)增删改原理

1)增加文档

增加文档就是在新的索引段中增加一个文档,并且新的文档的增加会产生新的索引段。

2)删除文档

由于段是不可修改的删除文档,所以删除文档只需要在被删除的文档上打上一个删除标记,等合并索引段的时候将这个文档删除。

3)修改文档

修改文档也是在旧的文档上打上删除标记,然后增加一个新的文档。等合并索引段的时候将这个文档删除。

 

posted @ 2023-04-13 16:26  小兵要进步  阅读(287)  评论(0编辑  收藏  举报