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. JAVA将异常的堆栈信息转成String

    有时候我们需要将系统出现异常的堆栈信息显示到异常页面的一个隐藏的DIV内,这样查看源时就可以快速的定位到异常信息.这个时候就要将异常信息转成String. /* * 将异常的堆栈信息转成String ...

  2. 【Python】爬虫-2

    8. urllib2.urlopen可以接受一个Request对象或者url,(在接受Request对象时候,并以此可以来设置一个URL的headers),urllib.urlopen只接收一个url ...

  3. Makefile内置变量,递归式变量,直接展开式变量,条件赋值,追加赋值

    将shell命令的输出赋值给变量: VALUE = $(shell   命令) Makefile中给变量赋值: =     是递归展开式变量 value1 = 5 value2 = $(value1) ...

  4. PHP设计模式之观察者模式(转)

    开篇还是从名字说起,“观察者模式”的观察者三个字信息量很大.玩过很多网络游戏的童鞋们应该知道,即便是斗地主,除了玩家,还有一个角色叫“观察者".在我们今天他谈论的模式设计中,观察者也是如此. ...

  5. selenium 定位无标签的元素

    转载需注明出处. 如: ::before 伪元素xpath css_selector. id. class_name各种定位失效,可以选择用, .get_attribute('innerHTML')方 ...

  6. each的break

    $.each var arr = [1, 2, 'test', 3, 4, 5, 6] // break $.each(arr, function(index, value) { if (value ...

  7. qt 内置图标使用

    QToolButton *button = new QToolButton(this); button->resize(100,30); button->setToolButtonStyl ...

  8. java list 的遍历

    import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.I ...

  9. java-权限修饰符的区别

    说明:所谓访问权限,是指对象是否可以通过“.”运算符操作自己的变量或通过“.”运算符使用类中的方法. 1.Java中的四种访问修饰符:public.protected.default(无修饰符,默认) ...

  10. RESTful规范(一)

    一.学习restframework之前准备 1.json格式若想展示中文,需要ensure_ascii=False import json dic={'name':'你好'} print(json.d ...