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. golang flag简单用法

    package main import ( "flag" "strings" "os" "fmt" ) var ARGS ...

  2. 【webdriver自动化】使用unittest实现自动登录163邮箱然后新建一个联系人

    #练习:登录163邮箱然后新建一个联系人 import unittest import time from selenium import webdriver from selenium.webdri ...

  3. elk的安装部署

    Elk日志安装文档 需要用到有三个软件包 和redis 分布式部署:已上图就是分布式部署的架构图 Logstash :    是部署在前台的应用上,收集数据的 和部署在redis和elasticsea ...

  4. advanced ip scanner —— 局域网下 ip 及设备的扫描

    advanced ip scanner 下载地址:Advanced IP Scanner - Download Free Network Scanner. 用于扫描当前局域网下全部设备及其 ip,构建 ...

  5. CodeMirror tab转空格

    解决CodeMirror编辑器Tab转空格问题 editor.setOption("extraKeys", { Tab: newTab }); function newTab(cm ...

  6. ZOJ - 4089 :Little Sub and Isomorphism Sequences (同构 set)

    Little Sub has a sequence . Now he has a problem for you. Two sequences of length and of length are ...

  7. SVN :Unable to connect to a repository at URL

     编程之路刚刚开始,错误难免,希望大家能够指出. 单位换地方了,SVN的服务器和本机不在一个网段,原先的SVN文件夹进行“SVN Update”的时候报错了,如下: 网上一查,原来是DNS域名解析错误 ...

  8. C结构体变量2种运算(比如链表的结点)(区别与java)

    a结构体变量,只能做两种运算, 整体引用(赋值,参数传递) 或访问成员(点运算—地址方式简化,地址方式)(见最后的图片) case万: 结论:java里面的class Node : Node p; p ...

  9. HttpClient-传入url得到json字符串( PostMethod method = new PostMethod(url)是个好方法)

    import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import ...

  10. OpenGL编程-第一个程序-画出一个正方形

    账号是:qq876.......   pwd:bky.13....................... 程序如下 #include <GL/glut.h> // #pragma comm ...