Elasticsearch对复杂分布式机制的透明隐藏特性
Elasticsearch是一套分布式的系统,分布式是为了应对大数据量
隐藏了复杂的分布式机制
分片机制(我们之前很简单的就将一些document插入到es集群中去了,但我们没有关心过数据怎么进行分片的,数据到哪个shard中去)
cluster discovery(集群发现机制,我们之前在做那个集群status从yellow转green的实验里,直接启动了第二个es进程,那个进程作为一个node自动就发现了集群,并且加入了进去,还接受了部分数据,replica shard)
shard负载均衡(举例,假设现在有3个节点,总共有25个shard要分配到3个节点上去,es会自动进行均匀分配,以保持每个节点的均衡的读写负载请求)
shard副本,请求路由,集群扩容,shard重分配
Elasticsearch的垂直扩容与水平扩容
垂直扩容:采购更强大的服务器,成本非常高昂,而且会有瓶颈,假设世界上最强大的服务器容量就是10T,但是当你的总数据量达到5000T的时候,你要采购多少台最强大的服务器
水平扩容:业界经常采用的方案,采购越来越多的普通服务器,性能比较一般,但是很多普通服务器组织在一起,就能构成强大的计算和存储能力
集群健康检查
Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是 集群健康 , 它在 status 字段中展示为 green 、 yellow 或者 red
GET /_cluster/health
创建索引
索引是指向一个或者多个物理分片的逻辑命名空间。
一个分片是一个底层的工作单元,它仅保存了全部数据中的一部分。一个分片是一个 Lucene 的实例,以及它本身就是一个完整的搜索引擎
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
shard&replica机制梳理
- 每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力
- 增减节点时,shard会自动在nodes中负载均衡
- primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard
- replica shard是primary shard的副本,负责容错,以及承担读请求负载
- primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改
- primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard
- primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上
图解:
一台服务器
集群 status 值为 yellow,没有被分配到任何节点的副本数。
集群是正常运行的,但是在硬件故障时有丢失数据的风险,在同一个节点上既保存原始数据又保存副本是没有意义的,因为一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。
两台服务器
集群 status 值为 green。
当第二个节点加入到集群后,3个 副本分片 将会分配到这个节点上。每个主分片对应一个副本分片。 这意味着当集群内任何一个节点出现问题时,我们的数据都完好无损。
集群现在不仅仅是正常运行的,并且还处于始终可用的状态。
三台服务器
Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点,现在每个节点上都拥有2个分片,而不是之前的3个。 这表示每个节点的硬件资源(CPU, RAM, I/O)将被更少的分片所共享,每个分片的性能将会得到提升。
修改副本个数
PUT /blogs/_settings
{
"number_of_replicas" : 2
}
主分片的数目在索引创建时就已经确定了下来。但是,读操作——搜索和返回数据——可以同时被主分片 或 副本分片所处理,所以当你拥有越多的副本分片时,也将拥有越高的吞吐量。
当然,如果只是在相同节点数目的集群上增加更多的副本分片并不能提高性能,因为每个分片从节点上获得的资源会变少。 你需要增加更多的硬件资源来提升吞吐量。
按照上面的节点配置,我们可以在失去2个节点的情况下不丢失任何数据。
Rebalance(再平衡),当集群中节点数量发生变化时,将会触发es集群的rebalance,即重新分配shard。Rebalance的原则就是尽量使shard在节点中分布均匀,达到负载均衡的目的。
容错机制
假如,我们现在关闭第一个节点
关闭的节点是一个主节点。而集群必须拥有一个主节点来保证正常工作,所以发生的第一件事情就是选举一个新的主节点: Node 2 。
在我们关闭 Node 1 的同时也失去了主分片 1 和 2,如果此时来检查集群的状况,我们看到的状态将会为 red :不是所有主分片都在正常工作。
但是在其它节点上存在着这两个主分片的完整副本, 所以新的主节点立即将这些分片在 Node 2 和 Node 3 上对应的副本分片提升为主分片, 此时集群的状态将会为 yellow 。 这个提升主分片的过程是瞬间发生的,如同按下一个开关一般。
为什么集群状态是 yellow 而不是 green 呢? 虽然我们拥有所有的三个主分片,但是同时设置了每个主分片需要对应2份副本分片,而此时只存在一份副本分片。 所以集群不能为 green 的状态。
如果我们同样关闭了 Node 2 ,集群依然可以保持在不丢任何数据的情况下运行,因为 Node 3 为每一个分片都保留着一份副本。
我们重新启动 Node 1 ,集群可以将缺失的副本分片再次进行分配,那么集群的状态也将回到green。
Master选举
选举时间点
- 集群启动初始化
- 集群的Master崩溃的时候
- 任何一个节点发现当前集群中的Master节点没有得到n/2 + 1节点认可的时候,触发选举
集群节点角色
- 主节点(Master node)
主要职责是负责集群层面的相关操作,管理集群变更,如创建或删除索引,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点。
主节点也可以作为数据节点,但稳定的主节点对集群的健康是非常重要的,默认情况下任何一个集群中的节点都有可能被选为主节点,索引数据和搜索查询等操作会占用大量的cpu,内存,io资源,为了确保一个集群的稳定,分离主节点和数据节点是一个比较好的选择。
通过配置node.master:true(默认)使节点具有被选举为Master的资格。主节点使全局唯一的,将从有资格成为Master的节点中选举。
为了防止数据丢失,每个主节点应该知道有资格陈伟主节点的数量,默认为1,为了避免网络分区出现多主的情况,配置discovery.zen.minimun_master_nodes原则上最小值应该为:(master_eligible_nodes/2)+1
node.master:true
node.data:false
- 数据节点(Data node) 数据节点主要是存储索引数据的节点,执行数据相关操作:CRUD、搜索,聚合操作等。数据节点对cpu,内存,I/O要求较高, 在优化的时候需要监控数据节点的状态,当资源不够的时候,需要在集群中添加新的节点。
node.master:false
node.data:true
- 协调节点(Coordinating node)
客户端请求可以发送到集群的任何节点,每个节点都知道任意文档所处的位置,然后转发这些请求,收集数据并返回给客户端,处理客户端请求的节点称为协调节点。
协调节点将请求转发给保存数据的数据节点。每个数据节点在本地执行请求,并将结果返回给协调节点。协调节点收集完数据合,将每个数据节点的结果合并为单个全局结果。对结果收集和排序的过程可能需要很多CPU和内存资源。
node.master:false
node.data:false
node.ingest:false
- 投票节点(voting node) 通过设置配置中的node.voting_only=true,(仅投票节点,即使配置了node.master = true,也不会参选, 但是仍然可以作为数据节点)。
- Master-eligible node (候选节点) 当node.master为true时,其表示这个node是一个master的候选节点,可以参与选举,在ES的文档中常被称作master-eligible node,类似于MasterCandidate。ES正常运行时只能有一个master(即leader),多于1个时会发生脑裂。
- Ingest node(预处理节点)
- Machine learning node (机器学习节点)
选举流程
即当一个节点发现包括自己在内的多数派的master-eligible节点认为集群没有master时,就可以发起master选举。
7.X之前的选主流程
源码流程
-
- 筛选activeMasters列表 master就是从activeMasters列表或者masterCandidates列表选举出来,所以选举之前es首先需要得到这两个列表。Elasticsearch节点成员首先向集群中的所有成员发送Ping请求,elasticsearch默认等待discovery.zen.ping_timeout时间,然后elasticsearch针对获取的全部response进行过滤,筛选出其中activeMasters列表,activeMaster列表是其它节点认为的当前集群的Master节点
List<DiscoveryNode> activeMasters = new ArrayList<>();
for (ZenPing.PingResponse pingResponse : pingResponses) {
//不允许将自己放在activeMasters列表中
if (pingResponse.master() != null && !localNode.equals(pingResponse.master())) {
activeMasters.add(pingResponse.master());
}
}
-
- 筛选masterCandidates列表 masterCandidates列表是当前集群有资格成为Master的节点,如果我们在elasticsearch.yml中配置了如下参数,那么这个节点就没有资格成为Master节点,也就不会被筛选进入masterCandidates列表
# 配置某个节点没有成为master资格
node.master:false
List<ElectMasterService.MasterCandidate> masterCandidates = new ArrayList<>();
for (ZenPing.PingResponse pingResponse : pingResponses) {
if (pingResponse.node().isMasterNode()) {
masterCandidates.add(new ElectMasterService.MasterCandidate(pingResponse.node(), pingResponse.getClusterStateVersion()));
}
}
-
- 从activeMasters列表选举Master节点
如果activeMasters 为空,不存在活着的master节点。如果activeMasters列表不为空,elasticsearch会优先从activeMasters列表中选举,选举的算法是Bully算法。
在activeMasters列表优先级比较的时候,如果节点有成为master的资格,那么优先级比较高,如果activeMaster列表有多个节点具有master资格,那么选择id最小的节点
- 从activeMasters列表选举Master节点
如果activeMasters 为空,不存在活着的master节点。如果activeMasters列表不为空,elasticsearch会优先从activeMasters列表中选举,选举的算法是Bully算法。
private static int compareNodes(DiscoveryNode o1, DiscoveryNode o2) {
if (o1.isMasterNode() && !o2.isMasterNode()) {
return -1;
}
if (!o1.isMasterNode() && o2.isMasterNode()) {
return 1;
}
return o1.getId().compareTo(o2.getId());
}
-
- 从masterCandidates列表选举Master节点 如果activeMaster列表为空,那么会在masterCandidates中选举,首先会判断masterCandidates列表成员数目是否达到了最小数目discovery.zen.minimum_master_nodes。如果达到的情况下比较优先级,优先级比较的时候首先比较节点拥有的集群状态版本编号,然后再比较id,这一流程的目的是让拥有最新集群状态的节点成为master
public static int compare(MasterCandidate c1, MasterCandidate c2) {
int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
if (ret == 0) {
ret = compareNodes(c1.getNode(), c2.getNode());
}
return ret;
}
-
- 本地节点是master
选举之后,会选举出一个准master节点, 准master节点会等待其它节点的投票,如果有discovery.zen.minimum_master_nodes-1个节点投票认为当前节点是master,那么选举就成功,准master会等待discovery.zen.master_election.wait_for_joins_timeout时间,如果超时,那么就失败
本地节点是Master的时候,Master节点会开启错误检测(NodeFaultDetection机制),它节点会定期扫描集群所有的成员,将失活的成员移除集群,同时将最新的集群状态发布到集群中,集群成员收到最新的集群状态后会进行相应的调整,比如重新选择主分片,进行数据复制等操作
- 本地节点是master
选举之后,会选举出一个准master节点, 准master节点会等待其它节点的投票,如果有discovery.zen.minimum_master_nodes-1个节点投票认为当前节点是master,那么选举就成功,准master会等待discovery.zen.master_election.wait_for_joins_timeout时间,如果超时,那么就失败
-
- 本地节点不是master 当前节点判定在集群当前状态下如果自己不可能是master节点,首先会禁止其他节点加入自己,然后投票选举出准Master节点。同时监听master发布的集群状态(MasterFaultDetection机制),如果集群状态显示的master节点和当前节点认为的master节点不是同一个节点,那么当前节点就重新发起选举。
消息类型
1)选举消息 (Election Message: Sent to announce election.)
2)应答消息(Answer (Alive) Message: Responds to the Election message.)
3)选举成功消息 (Coordinator (Victory) Message: Sent by winner of the election to announce victory.)
当一个进程P接收到主节点失效信息,进程P将做以下事情:
1)如果进程P有最大的进程ID,那么它则会向其他节点广播Coordinator (Victory) Message。否则进程P向进程号比它大的进程发送Election Message
2)如果进程P发送Election Message后,没有接收到应答,它就会向其他节点广播Coordinator (Victory) Message,并成为master。
3)如果进程P接收到比它进程号更高的进程的Answer (Alive) Message信息,那么它这次的选举就失败了,等待接收其他节点的Coordinator (Victory) Message。
4)如果进程P接收到比它进程号低的进程的Election message,那么它会向该节点返回一个Answer (Alive) Message,并启动选举进程,并向比它更高的进程发送Election Message。
5)如果进程P接收到Coordinator (Victory) Message,那么它就会把发送这条消息的节点看作为master 进程。
zhuanlan.zhihu.com/p/110015509
Bully算法缺陷
Master假死
Master节点承担的职责负载过重的情况下,可能无法即时对组内成员作出响应,这种便是假死。
如果master节点假死,又选举出了新的master,那就是脑裂问题。
脑裂问题
脑裂问题指的是一个集群中出现了两个及以上的Master节点。
集群因为网络原因分成了两个部分,一个部分称为partition1包含P3,P5,P6节点,另一部分称为partition2包含P2,P1,P4节点,这两个partition因为网络原因比如路由器短时故障造成不能相互通信的问题。
discovery.zen.minimum_master_nodes = (n / 2)+ 1
脑裂问题是所有集群选举算法都要面对的一个问题,Elasticsearch集群机制采用了最小参与节点的方案解决的。假设elasticsearch集群中有资格投票的实例个数是n,节点想要成为master必须要得到n/2 +1票数(在本示例中是4)。上图中的分区一P6和分区二中的P4,任何一个master节点所在的分区集群的候选节点数目都小于4,更不可能得到4个选票,所以整个Elasticsearch集群处于瘫痪状态
Elasticsearch 7.x master选举 Raft算法
raft是一个共识算法(consensus algorithm),所谓共识,就是多个节点对某个事情达成一致的看法,即使是在部分节点故障、网络延时、网络分割的情况下。
- leader election
raft协议中,一个节点任一时刻处于以下三个状态之一:
leader
follower
candidate
正常情况下,集群中只有一个 Leader,其他节点全是 Follower 。Follower 都是被动接收请求,从不发送主动任何请求。Candidate 是从 Follower 到 Leader的中间状态。
- term
从上面可以看出,哪个节点做leader是大家投票选举出来的,每个leader工作一段时间,然后选出新的leader继续负责。这根民主社会的选举很像,每一届新的履职期称之为一届任期,在raft协议中,也是这样的,对应的术语叫term。
term(任期)以选举(election)开始,然后就是一段或长或短的稳定工作期(normal Operation)。从上图可以看到,任期是递增的,这就充当了逻辑时钟的作用。另外,term 3展示了一种情况,就是说没有选举出leader就结束了,然后会发起新的选举
- 选举过程
如果follower在election timeout内没有收到来自leader的心跳,(也许此时还没有选出leader,大家都在等;也许leader挂了;也许只是leader与该follower之间网络故障),则会主动发起选举。步骤如下:
-- 1.增加节点本地的 current term ,切换到candidate状态
-- 2.投自己一票
-- 3.并行给其他节点发送 RequestVote RPCs
-- 4.等待其他节点的回复
在这个过程中,根据来自其他节点的消息,可能出现三种结果:
-- 1.收到majority的投票(含自己的一票),则赢得选举,成为leader
-- 2.被告知别人已当选,那么自行切换到follower
-- 3.一段时间内没有收到majority投票,则保持candidate状态,重新发出选举
第一种情况,赢得了选举之后,新的leader会立刻给所有节点发消息,广而告之,避免其余节点触发新的选举。先回到投票者的视角,投票者如何决定是否给一个选举请求投票呢,有以下约束:
-- 1.在任一任期内,单个节点最多只能投一票
-- 2.候选人知道的信息不能比自己的少(这一部分,后面介绍log replication和safety的时候会详细介绍)
-- 3.first-come-first-served 先来先得
第二种情况,比如有三个节点A B C。A B同时发起选举,而A的选举消息先到达C,C给A投了一票,当B的消息到达C时,已经不能满足上面提到的第一个约束,即C不会给B投票,而A和B显然都不会给对方投票。A胜出之后,会给B,C发心跳消息,节点B发现节点A的term不低于自己的term,知道有已经有Leader了,于是转换成follower。
第三种情况,没有任何节点获得majority投票,比如下图这种情况:
总共有四个节点,Node C、Node D同时成为了candidate,进入了term 4,但Node A投了NodeD一票,NodeB投了Node C一票,这就出现了平票 split vote的情况。这个时候大家都在等啊等,直到超时后重新发起选举。如果出现平票的情况,那么就延长了系统不可用的时间(没有leader是不能处理客户端写请求的),因此raft引入了randomized election timeouts来尽量避免平票情况。同时,leader-based 共识算法中,节点的数目都是奇数个,尽量保证majority的出现。
log replication : 在raft中,leader将客户端请求(command)封装到一个个log entry,将这些log entries复制(replicate)到所有follower节点,然后大家按相同顺序应用(apply)log entry中的command,则状态肯定是一致的。
raft算法为了保证高可用,并不是强一致性,而是最终一致性,leader会不断尝试给follower发log entries,直到所有节点的log entries都相同。
safety : raft保证被复制到大多数节点的日志不会被回滚,那么就是safety属性。而raft最终会让所有节点状态一致,这属于liveness属性。
- 脑裂问题
Raft 针对这种情况的处理方式是老的 Leader 集群虽然剩下三个节点,但是 Leader 对数据的处理过程还是在按原来 5 个节点进行处理,所以老的 Leader 接收到的数据,在向其他 4 个节点复制数据,由于无法获取超过 N/2 个 Follower 节点的复制完毕数据响应(因为无法连接到 B 机房中的 2个节点),所以 client 在向老 Leader 发送的数据请求均无法成功写入,而 client 向B机房新 Leader 发送的数据,因为是新成立的集群,所以可以成功写入数据,在A、B两个机房恢复网络通讯后,A 机房中的所有节点包括老 Leader 再以 Follower 角色接入这个集群,并同步新 Leader 中的数据,完成数据一致性处理。
动画演示
ElasticSearch完整目录
1. Elasticsearch是什么
2.Elasticsearch基础使用
3.Elasticsearch Mapping
4.Elasticsearch 集群原理
5.Elasticsearch Scripts和读写原理
6.Elasticsearch 分词器
7.Elasticsearch TF-IDF算法及高级查询
8.Elasticsearch 地理位置及搜索
9.Elasticsearch ELK