zookeeper集群

配置多个实例共同构成一个集群对外提供服务以达到水平扩展的目的,每个服务器上的数据是相同的,每一个服务器均可以对外提供读和写的服务,这点和redis是相同的,即对客户端来讲每个服务器都是平等的。

这篇主要分析leader的选择机制,zookeeper提供了三种方式:

LeaderElection

AuthFastLeaderElection

FastLeaderElection

默认的算法是FastLeaderElection,所以这篇主要分析它的选举机制。

选择机制中的概念

服务器ID

比如有三台服务器,编号分别是1,2,3。

编号越大在选择算法中的权重越大。

数据ID

服务器中存放的最大数据ID.

值越大说明数据越新,在选举算法中数据越新权重越大。

逻辑时钟

或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。

选举状态

LOOKING,竞选状态。

FOLLOWING,随从状态,同步leader状态,参与投票。

OBSERVING,观察状态,同步leader状态,不参与投票。

LEADING,领导者状态。

选举消息内容

在投票完成后,需要将投票信息发送给集群中的所有服务器,它包含如下内容。

服务器ID

数据ID

逻辑时钟

选举状态

选举流程图

因为每个服务器都是独立的,在启动时均从初始状态开始参与选举,下面是简易流程图。

选举状态图

描述Leader选择过程中的状态变化,这是假设全部实例中均没有数据,假设服务器启动顺序分别为:A,B,C。

源码分析

QuorumPeer

主要看这个类,只有LOOKING状态才会去执行选举算法。每个服务器在启动时都会选择自己做为领导,然后将投票信息发送出去,循环一直到选举出领导为止。

publicvoidrun() {

//.......

try{

while(running) {

switch(getPeerState()) {

caseLOOKING:

if(Boolean.getBoolean("readonlymode.enabled")) {

//...

try{

//投票给自己...

setCurrentVote(makeLEStrategy().lookForLeader());

}catch(Exception e) {

//...

}finally{

//...

}

}else{

try{

//...

setCurrentVote(makeLEStrategy().lookForLeader());

}catch(Exception e) {

//...

}

}

break;

caseOBSERVING:

//...

break;

caseFOLLOWING:

//...

break;

caseLEADING:

//...

break;

}

}

}finally{

//...

}

}

FastLeaderElection

它是zookeeper默认提供的选举算法,核心方法如下:具体的可以与本文上面的流程图对照。

publicVote lookForLeader()throwsInterruptedException {

//...

try{

HashMaprecvset =newHashMap();

HashMapoutofelection =newHashMap();

intnotTimeout = finalizeWait;

synchronized(this){

//给自己投票

logicalclock.incrementAndGet();

updateProposal(getInitId(), getInitLastLoggedZxid(), getPeerEpoch());

}

//将投票信息发送给集群中的每个服务器

sendNotifications();

//循环,如果是竞选状态一直到选举出结果

while((self.getPeerState() == ServerState.LOOKING) &&

(!stop)){

Notification n = recvqueue.poll(notTimeout,

TimeUnit.MILLISECONDS);

//没有收到投票信息

if(n ==null){

if(manager.haveDelivered()){

sendNotifications();

}else{

manager.connectAll();

}

//...

}

//收到投票信息

elseif(self.getCurrentAndNextConfigVoters().contains(n.sid)) {

switch(n.state) {

caseLOOKING:

// 判断投票是否过时,如果过时就清除之前已经接收到的信息

if(n.electionEpoch > logicalclock.get()) {

logicalclock.set(n.electionEpoch);

recvset.clear();

//更新投票信息

if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,

getInitId(), getInitLastLoggedZxid(), getPeerEpoch())) {

updateProposal(n.leader, n.zxid, n.peerEpoch);

}else{

updateProposal(getInitId(),

getInitLastLoggedZxid(),

getPeerEpoch());

}

//发送投票信息

sendNotifications();

}elseif(n.electionEpoch

//忽略

break;

}elseif(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,

proposedLeader, proposedZxid, proposedEpoch)) {

//更新投票信息

updateProposal(n.leader, n.zxid, n.peerEpoch);

sendNotifications();

}

recvset.put(n.sid,newVote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));

//判断是否投票结束

if(termPredicate(recvset,

newVote(proposedLeader, proposedZxid,

logicalclock.get(), proposedEpoch))) {

// Verify if there is any change in the proposed leader

while((n = recvqueue.poll(finalizeWait,

TimeUnit.MILLISECONDS)) !=null){

if(totalOrderPredicate(n.leader, n.zxid, n.peerEpoch,

proposedLeader, proposedZxid, proposedEpoch)){

recvqueue.put(n);

break;

}

}

if(n ==null) {

self.setPeerState((proposedLeader == self.getId()) ?

ServerState.LEADING: learningState());

Vote endVote =newVote(proposedLeader,

proposedZxid, proposedEpoch);

leaveInstance(endVote);

returnendVote;

}

}

break;

caseOBSERVING:

//忽略

break;

caseFOLLOWING:

caseLEADING:

//如果是同一轮投票

if(n.electionEpoch == logicalclock.get()){

recvset.put(n.sid,newVote(n.leader, n.zxid, n.electionEpoch, n.peerEpoch));

//判断是否投票结束

if(termPredicate(recvset,newVote(n.leader,

n.zxid, n.electionEpoch, n.peerEpoch, n.state))

&& checkLeader(outofelection, n.leader, n.electionEpoch)) {

self.setPeerState((n.leader == self.getId()) ?

ServerState.LEADING: learningState());

Vote endVote =newVote(n.leader, n.zxid, n.peerEpoch);

leaveInstance(endVote);

returnendVote;

}

}

//记录投票已经完成

outofelection.put(n.sid,newVote(n.leader,

IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state));

if(termPredicate(outofelection,newVote(n.leader,

IGNOREVALUE, IGNOREVALUE, n.peerEpoch, n.state))

&& checkLeader(outofelection, n.leader, IGNOREVALUE)) {

synchronized(this){

logicalclock.set(n.electionEpoch);

self.setPeerState((n.leader == self.getId()) ?

ServerState.LEADING: learningState());

}

Vote endVote =newVote(n.leader, n.zxid, n.peerEpoch);

leaveInstance(endVote);

returnendVote;

}

break;

default:

//忽略

break;

}

}else{

LOG.warn("Ignoring notification from non-cluster member " + n.sid);

}

}

returnnull;

}finally{

//...

}

}

判断是否已经胜出

默认是采用投票数大于半数则胜出的逻辑。

选举流程简述

目前有5台服务器,每台服务器均没有数据,它们的编号分别是1,2,3,4,5,按编号依次启动,它们的选择举过程如下:

服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking。

服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。

服务器3启动,给自己投票,同时与之前启动的服务器1,2交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1,2成为小弟。

服务器4启动,给自己投票,同时与之前启动的服务器1,2,3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服务器4只能成为小弟。

服务器5启动,后面的逻辑同服务器4成为小弟。

zookeeper选举状态介绍 摘自https://cloud.tencent.com/developer/news/303891的更多相关文章

  1. 有状态(Stateful)应用的容器化 - 云+社区 - 腾讯云 https://cloud.tencent.com/developer/article/1020178

    有状态(Stateful)应用的容器化 - 云+社区 - 腾讯云 https://cloud.tencent.com/developer/article/1020178

  2. 我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=i5j7gwrxj9x5

    我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=i5j7gwrxj9x5

  3. 我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3cp8ng15g94wc

    我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3cp8ng15g94wc

  4. flask 框架 转载:https://cloud.tencent.com/developer/article/1465949

    1.cookie.py """ - 解释: 用来保持服务器和浏览器交互的状态的, 由服务器设置,存储在浏览器 - 作用: 用来做广告推送 - cookie的设置和获取 - ...

  5. flask 框架 转载:https://cloud.tencent.com/developer/article/1465968

    特点总结: 类名称---->数据库表名 类属性---->数据库字段 类的对象----->数据库表中的一行一行数据 3.ORM操作注意(理解) 1/因为SQLALChemy去app身上 ...

  6. 【转】Zookeeper学习---zookeeper 选举机制介绍

    [原文]https://www.toutiao.com/i6593162565872779784/ zookeeper集群 配置多个实例共同构成一个集群对外提供服务以达到水平扩展的目的,每个服务器上的 ...

  7. go-micro介绍 摘自https://www.cnblogs.com/s0-0s/p/6874800.html

    Micro 架构与设计 翻译自 Micro architecture & design patterns for microservices 注: 原文作者即 Micro 框架的开发者. 过去 ...

  8. 【分布式】Zookeeper的Leader选举-选举过程介绍(经典的Paxos算法解析)

    一.前言 前面学习了Zookeeper服务端的相关细节,其中对于集群启动而言,很重要的一部分就是Leader选举,接着就开始深入学习Leader选举. 二.Leader选举 2.1 Leader选举概 ...

  9. zookeeper 选举机制 和 eruake

    zookeeper简介: 在分布式环境中,多个服务之间协调一致.有提供分布式锁.服务配置.实现分布式领域CAP(consistency一致性,Availiablity高可用,patition tolr ...

随机推荐

  1. python socket 编程之三:长连接、短连接以及心跳(转药师Aric的文章)

    长连接:开启一个socket连接,收发完数据后,不立刻关闭连接,可以多次收发数据包. 短连接:开启一个socket连接,收发完数据后,立刻关闭连接. 心跳:长连接在没有数据通信时,定时发送数据包(心跳 ...

  2. Spring面向切面编程

    在使用面向切面编程时,我们可以在一个地方定义通用的共鞥,但是可以通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类.横切关注点可以被模块化为特殊的类,这些类被称为切面.这样的优点是 ...

  3. Enhancement in SAP abap.

    Recently I have been taught through how to do enhancement for those standard programs. Th reason for ...

  4. IDEA激活

    https://blog.csdn.net/qq_34273222/article/details/78810799 目测这个服务器可用:http://idea.iteblog.com/key.php

  5. [转载]PT建站源码(PT服务器原程序)汇总(20100815更新)

    Tbsource官方网站(已失效):http://www.tbsource.com/下载地址:http://www.ipv6bbs.com/thread-5152-1-1.html使用站点:CCFbi ...

  6. DG搭建方式区分

    DG搭建三种方式: 一.异机恢复,restore database,recover database 二. duplicate target database for standby from act ...

  7. DQN-深度Q网络

    深度Q网络是用深度学习来解决强化中Q学习的问题,可以先了解一下Q学习的过程是一个怎样的过程,实际上就是不断的试错,从试错的经验之中寻找最优解 关于Q学习,我看到一个非常好的例子,另外知乎上面也有相关的 ...

  8. 优先队列(挑程)poj 2431

    每次写poj的题都很崩溃,貌似从来没有一次一发就ac的,每次都有特别多的细节需要考虑.还有就是自己写的太粗糙了,应该把每种情况都想到的,总是急着交,然后刷一页wa. 优先队列直接用stl就可以,简单实 ...

  9. Python 模块管理1

    Python 模块管理   导入新的模块 创建一个 calculate.py 文件 print('ok') def add(x,y): return x + y def sub(x,y): retur ...

  10. 【HDOJ4109】【拓扑OR差分约束求关键路径】

    http://acm.hdu.edu.cn/showproblem.php?pid=4109 Instrction Arrangement Time Limit: 2000/1000 MS (Java ...