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. Fizz Buzz 问题

    要求: 给你一个整数n. 从 1 到 n 按照下面的规则打印每个数: 如果这个数被3整除,打印fizz. 如果这个数被5整除,打印buzz. 如果这个数能同时被3和5整除,打印fizz buzz. 示 ...

  2. [error]OpenCV Error: Assertion failed (ssize.width > 0 && ssize.height > 0) in resize, file modules/imgproc/src/resize.cpp, line 3289

    error OpenCV Error: Assertion failed (ssize.width > && ssize.height > ) terminate call ...

  3. 20155208实验三 敏捷开发与XP实践

    20155208实验三 敏捷开发与XP实践 一.实验内容 (1)在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Code菜单,找出一项让自己感觉最 ...

  4. 20155208徐子涵 2016-2017-2 《Java程序设计》第4周学习总结

    20155208徐子涵 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 第六章 继承与多态 继承 继承作为面向对象的第二大特征,基本上就是避免多个类间重复定义 ...

  5. js 自定义滚动条

    http://visugar.com/2017/08/18/20170818CustomScroll/    chrome浏览器 https://www.cnblogs.com/yclblog/p/6 ...

  6. HDU 6015 Skip the Class 优先队列 map的使用

    Skip the Class Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Tota ...

  7. SkyWalking+SkyApm-dotnet分布式链路追踪系统

    SkyWalking+SkyApm-dotnet分布式链路追踪系统 对于普通系统或者服务来说,一般通过打日志来进行埋点,然后再通过elk或splunk进行定位及分析问题,更有甚者直接远程服务器,直接操 ...

  8. 2017.7.11 linux 挂载

    挂载:Liunx采用树形的文件管理系统,也就是在Linux系统中,可以说已经没有分区的概念了.分区在Linux和其他设备一样都只是一个文件.要使用一个分区必须把它加载到文件系统中.这可能难于理解,继续 ...

  9. 06 Listener,Filter,BeanUtils

    Listener 监听器,监听某一个事件的发生. 状态的改变. 内部机制其实就是接口回调. 接口回调  需求:A在执行循环,当循环到5的时候, 通知B.事先先把一个对象传递给 A , 当A 执行到5的 ...

  10. PS学习之小猪佩奇身上纹,掌声送给社会人

    首先准备素材 用ps首先打开素材一 首先对图片去色 快捷键:shift+Ctrl+u 调整色阶 设置高斯模糊: 另存为psd格式,命名为叠加的对象 再次打开素材一,把佩奇拖入到图层里,并调整大小,旋转 ...