zookeeper之master选举代码实现

news2024/11/15 17:31:20

master选举的基本概念

(1)假设有一个系统A,它向外提供了一个服务,叫做服务B。并且这个服务需要24小时持续不断的向外提供。也就是提供服务的机器不能够有单点故障。于是我们考虑使用集群。
(2)我们采用的是master-slave的方式。集群中有一台主机,多台备机。由主机向外提供服务,备机负责监听主机的状态。一旦出现了宕机,备机必须要很迅速的接管主机。继续向外服务。在这个过程中,由备机选出主机的过程就是master选举。

master选举的基本流程

(1)下图中左边代表的是zk集群,右边的三个立方体代表的是三台工作服务器。
(2)这三台机器在启动过程中会去zk的servers节点下创建三个临时节点。并且把自己的临时信息写入到临时节点中。这个过程我们 叫做服务注册。系统中的其它服务可以通过servers节点下的子节点列表来了解当前系统哪些服务器可用。这个过程叫做服务发现。
(4)紧接着这三台服务器就尝试去创建master节点,谁可以创建master节点,谁就是master.假设2号服务器可以创建master,那么2号服务器就称为master。其它的俩台服务器就是slave。所有的工作服务器都必须关注master节点的删除事件。
(5)一个临时节点在创建了会话失效以后,会自动的被删除掉。而创建这次会话的服务器宕机会直接导致会话失效。换句话说,我们可以监听master节点的删除来判断。
(6)master服务器是否宕机。一旦master服务器宕机,那么必须开始新一轮的选举。


master选举代码实现流程图

集群中每个工作服务器启动时的执行流程:

(1)每一台工作服务器都要关注master节点的删除工作。

(2)如果监测到master节点被删除了,那么每台工作服务器都尝试竞争成为master节点。

(3)如果某一工作服务器创建了master节点并且写入了自己的信息,那么表明此工作服务器已经成为了master节点。


如果存在网络抖动:


(1)在网络发生抖动的时候,可能会发生master 服务器会话的中断。那么这样的话,就会再进行master的选举,选举的结果有俩个,一个是原来的master服务器作为master。
(2)另外的一种情况是不是原来的master服务器作为master.但是如果选举了另外的服务器作为master,那么就会引起资源的迁移,会有消耗。所以,为了避免这种情况的发生,需要使原来的master服务器称为master的概率增大。最近一次的master服务器判断是否是自己。增强master。

master选举代码实现

(1)workServer:就是工作服务器

package com.jike.mastersel;
 
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkException;
import org.I0Itec.zkclient.exception.ZkInterruptedException;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.apache.zookeeper.CreateMode;

/**工作服务器**/
 
public class WorkServer {
 
  private volatile boolean running = false;
 
  private ZkClient zkClient;
 
  private static final String MASTER_PATH = "/master";
 
  private IZkDataListener dataListener;
 
  private RunningData serverData;
 
  private RunningData masterData;
  
  private ScheduledExecutorService delayExector = Executors.newScheduledThreadPool(1);
  private int delayTime = 5;
 
  public WorkServer(RunningData rd) {
     this.serverData = rd;
     this.dataListener = new IZkDataListener() {
 
       public void handleDataDeleted(String dataPath) throws Exception {
          // TODO Auto-generated method stub
          
          //takeMaster();
          
         if (masterData!=null && masterData.getName().equals(serverData.getName())){
            takeMaster();
            
          }else{
             delayExector.schedule(new Runnable(){
               public void run(){
                 takeMaster();
               }
            }, delayTime, TimeUnit.SECONDS);
            
          }
          
          
       }
 
       public void handleDataChange(String dataPath, Object data)
            throws Exception {
          // TODO Auto-generated method stub
 
       }
     };
  }
 
  public ZkClient getZkClient() {
     return zkClient;
  }
 
  public void setZkClient(ZkClient zkClient) {
     this.zkClient = zkClient;
  }
 
  public void start() throws Exception {
     if (running) {
       throw new Exception("server has startup...");
     }
     running = true;
     zkClient.subscribeDataChanges(MASTER_PATH, dataListener);
     takeMaster();
 
  }
 
  public void stop() throws Exception {
     if (!running) {
       throw new Exception("server has stoped");
     }
     running = false;
     
     delayExector.shutdown();
 
     zkClient.unsubscribeDataChanges(MASTER_PATH, dataListener);
 
     releaseMaster();
 
  }
 
  private void takeMaster() {
     if (!running)
       return;
 
     try {
       zkClient.create(MASTER_PATH, serverData, CreateMode.EPHEMERAL);
       masterData = serverData;
       System.out.println(serverData.getName()+" is master");
       delayExector.schedule(new Runnable() {       
          public void run() {
            // TODO Auto-generated method stub
            if (checkMaster()){
               releaseMaster();
            }
          }
       }, 5, TimeUnit.SECONDS);
       
     } catch (ZkNodeExistsException e) {
       RunningData runningData = zkClient.readData(MASTER_PATH, true);
       if (runningData == null) {
          takeMaster();
       } else {
          masterData = runningData;
       }
     } catch (Exception e) {
       // ignore;
     }
 
  }
 
  private void releaseMaster() {
     if (checkMaster()) {
       zkClient.delete(MASTER_PATH);
 
     }
 
  }
 
  private boolean checkMaster() {
     try {
       RunningData eventData = zkClient.readData(MASTER_PATH);
       masterData = eventData;
       if (masterData.getName().equals(serverData.getName())) {
          return true;
       }
       return false;
     } catch (ZkNoNodeException e) {
       return false;
     } catch (ZkInterruptedException e) {
       return checkMaster();
     } catch (ZkException e) {
       return false;
     }
  }
 
}


(2)RunningData:描述workServer的信息

package com.jike.mastersel;
 
import java.io.Serializable;


/**描述workServer的信息**/
 
public class RunningData implements Serializable {
 
  /**
   * 
   */
  private static final long serialVersionUID = 4260577459043203630L;
  
  
  
  private Long cid;
  private String name;
  public Long getCid() {
     return cid;
  }
  public void setCid(Long cid) {
     this.cid = cid;
  }
  public String getName() {
     return name;
  }
  public void setName(String name) {
     this.name = name;
  }
 
}


(3)leaderSelectorZkClinet:作为启动和停止WorkServer的调度器

package com.jike.mastersel;
 
 
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
 
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


/**作为启动和停止WorkServer的调度器**/ 
public class LeaderSelectorZkClient
{
  //启动的服务个数
    private static final int        CLIENT_QTY = 10;
    //zookeeper服务器的地址
    private static final String     ZOOKEEPER_SERVER = "192.168.1.105:2181";
    
       
    public static void main(String[] args) throws Exception
    {
     //保存所有zkClient的列表
        List<ZkClient>  clients = new ArrayList<ZkClient>();
        //保存所有服务的列表
        List<WorkServer>  workServers = new ArrayList<WorkServer>();
 
        try
        {
            for ( int i = 0; i < CLIENT_QTY; ++i )
            {
            //创建zkClient
                ZkClient client = new ZkClient(ZOOKEEPER_SERVER, 5000, 5000, new SerializableSerializer());
                clients.add(client);
                //创建serverData
                RunningData runningData = new RunningData();
                runningData.setCid(Long.valueOf(i));
                runningData.setName("Client #" + i);
                //创建服务
                WorkServer  workServer = new WorkServer(runningData);
                workServer.setZkClient(client);
                
                workServers.add(workServer);
                workServer.start();
            }
 
            System.out.println("敲回车键退出!\n");
            new BufferedReader(new InputStreamReader(System.in)).readLine();
        }
        finally
        {
            System.out.println("Shutting down...");
 
            for ( WorkServer workServer : workServers )
            {
            try {
               workServer.stop();
          } catch (Exception e) {
            e.printStackTrace();
          }           
            }
            for ( ZkClient client : clients )
            {
            try {
               client.close();
          } catch (Exception e) {
            e.printStackTrace();
          }           
            }
        }        
    }
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/134588.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

傻白入门芯片设计,如何做文献笔记(十九)

Article: 文献出处&#xff08;方便再次搜索&#xff09; 作者文献题目文献时间Data: 文献数据&#xff08;总结归纳&#xff0c;方便理解&#xff09; 这篇文章的目的结论背景介绍结果方法&#xff08;可选&#xff09;Comments: 对文献的想法 &#xff08;强迫自己思考&#…

Java人脸识别相册分类按时间分类相册按城市分类相册app源码

简介 后台Java&#xff0c;前台mui开发的android app&#xff1b;主要是按拍摄时间&#xff0c;人脸&#xff0c;城市进行相册照片的分类。 演示视频 https://www.bilibili.com/video/BV1XP4y187rA/?share_sourcecopy_web&vd_sourceed0f04fbb713154db5cc611225d92156 技…

MySQL调优-Explain详解和索引最佳实践

目录 Explain工具介绍 Explain分析示例 explain 两个变种 explain中的列 1.id列 2.select_type列 3. table列 4.type列 5. possible_keys列 6. key列 7. key_len列 8. ref列 9. rows列 10.Extra列 索引最佳实践 1.全值匹配 2.最左前缀法则 3.不在索引列上做任何操…

2D 平台动作冒险游戏

本文实现比较流畅的跑和跳跃 跑的动画需要从idle经历到walk再到run的过程&#xff0c;这个过程可以用融合树实现 也可以让玩家在按下按键时先固定播放完一个walk的动画&#xff0c;然后再自动切换到run的状态。 只不过在任何状态时&#xff0c;只要玩家松开了按键&#xff0c;…

钧瓷产业数字化,将促使禹州走向更高级的社会形态——钧共体

讲好钧瓷产业的故事 有深度的故事,有温度的内容 有态度的文字,有立场的思考 版权声明:钧瓷内参独家发布,侵权必究 第334期 钧瓷内参 2023年1月1日 这里的上市指沪深的主板,创业板和科创板,区域的挂牌不算。 这个数据是根据禹州钧瓷产业2022…

GPU服务器之Colab配置及使用教程

在进行深度学习过程中&#xff0c;不可避免需要进行炼丹的操作&#xff0c;而博主的电脑本身性能就很拉跨&#xff0c;一旦再运行其他的应用便是寸步难行&#xff0c;最好的办法便是再买一台&#xff0c;哈哈哈&#xff0c;当然也可以使用一些云服务器来进行&#xff0c;博主这…

MySQL调优-深入理解MySQL索引底层数据结构与算法

目录 索引的定义 B-Tree (1) 非叶子节点不存储data数据&#xff0c;只进行存储索引(这个索引是冗余的索引&#xff0c;多余的)&#xff0c;可以放更多的索引 (2) 叶子节点包含所有的索引字段 (3) 叶子节点用指针相互连接&#xff0c;提高区间访问的性能 Hash (1) 对索引的…

基于pybind11的c++开发cuda算子用于python调用

一、环境 win10VS2022python39pybind11最新版git下载源码,后边会用:https://github.com/pybind/pybind11同时通过pip install pybind11,python环境下也要安装cuda环境配置参考:https://zhuanlan.zhihu.com/p/488518526二、cuda核函数动态库生成 步骤一:创建cuda项目 创…

VueElement

一、vue 1.1 概述 接下来我们学习一款前端的框架&#xff0c;就是VUE。 Vue 是一套前端框架&#xff0c;免除原生JavaScript中的DOM操作&#xff0c;简化书写。 我们之前也学习过后端的框架 Mybatis &#xff0c; Mybatis 是用来简化 jdbc 代码编写的&#xff1b;而 VUE 是前…

绝对路径和相对路径

目录 1说明 2.相对路径的优势 3.注意 4./说明 1说明 绝对路径&#xff1a;文件真实的存放位置 例&#xff1a;D:\data\applogs\xxl-job\xxl-job-admin.log 不需要知道其他任何信息就可以根据绝对路径判断出文件的位置 相对路径&#xff1a;相对于当前位置的路径 前端开…

QT学 控件(四)步长调节框(QSpinBox + QDateTimeEdit)

文章目录QSpinBoxQDateTimeEditQSpinBox 允许用户通过单击向上/向下按钮或按键盘上的上/下来选择一个值来增加/减少当前显示的值。用户还可以手动键入值 常用于处理 选择 &#xff1a; 【1-99】 【星期1一 - 星期天】【1月-12月】 样式&#xff1a; 继承自&#xff1a; QAb…

网络协议(二):MAC地址、IP地址、子网掩码、子网和超网

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 网络协议(二)&#xff1a;MAC地址、IP地址、子网掩码、子网和超网 目录一、MAC地址二、IP地址1、IP地址的组成2、IP地址的分类三、子网划分1、等长子网划分2、变长子网划分四、超网五、判断一个网段…

DIY NAS服务器之OMV 5.6入坑指南(四) -安装docker和Portainer

系列文章目录 DIY NAS服务器之OMV 5.6入坑指南&#xff08;一&#xff09;-openmediavalut 5.6安装DIY NAS服务器之OMV 5.6入坑指南&#xff08;二&#xff09;- 安装omv-extras插件DIY NAS服务器之OMV 5.6入坑指南&#xff08;三&#xff09;- 切换系统源​​​​​​​ ​​…

CentOS安装Vscode-yum+Vscode前端开发必安装的插件

CentOS安装Vscode-yum Visual Studio Code 是 Microsoft 产品和开源跨平台代码编辑器。 它提供内置调试支持、代码完成、集成终端语法高亮、嵌入式 Git 控制、代码重构和代码片段。 在本教程中&#xff0c;我们将介绍如何使用 CentOS 7 机器上的官方代码存储库安装最新版本的…

Python--你见过雪飘人间吗?

happy new year 突然想来一点雪花特效。 其实Python做前端效果还是很少的&#xff0c;也就大概记录一下画法啦 对了祝大家新的一年快乐&#xff0c;早点脱单吧&#xff01;&#xff01;&#xff01; 附上一张女神的照片 Python-turtle 科赫曲线是一种分形。其形态似雪花&am…

地宫夺宝(三种方法)(第五届蓝桥杯省赛C++A/B/C组,第五届蓝桥杯省赛JAVAB/C组)

PS:方法一和方法看起来复杂&#xff0c;但其实较容易理解&#xff0c;大家不要跳过哦。至于方法三的动态规划则可能有点抽象&#xff0c;理解起来有点难度。 目录 题目描述&#xff1a; 三种方法&#xff1a; 方法一&#xff1a;暴力枚举&#xff08;该方法只能获得30分&…

函数传参问题,桶排序去重,分治递归,摩尔投票求数组众数,数组中心下标求法

TIPS 1. 我们都知道&#xff0c;地址&#xff0c;指针这两者是完全等价的概念&#xff0c;但是有微小的差别。地址的话是不能够修改的&#xff08;比如说数组名就是违法的&#xff09;&#xff0c;而指针的话可以与--。 2. 以后一旦在代码里面看到字符char类型的&#xff0c;…

安全回顾总结

xss反射型漏洞复现 观察源码&#xff0c;可以看出源码中通过get传参到变量xss&#xff0c;并将一些特殊符号过滤了&#xff0c;则后续需要考虑该规则的绕过 echo “<img src”{$xss}">"; img标签 <img src“aaa” οnerrοr“alert(1)” 如果img图片不存在…

自然语言处理-01神经网络

数学和PY 向量是同时拥有大小和方向的量。向量可以表示为排成一排的数字集合&#xff0c;在 Python 实现中可以处理为一维数组。 向量和矩阵可以分别用一维数组和二维数组表示。另外&#xff0c;在矩阵中&#xff0c;将水平方向上的排列称为行&#xff08;row&#xff09;&…

2.SpringBoot-Condition

一、 参考 04-SpringBoot自动配置-切换内置web服务器_哔哩哔哩_bilibili 二、 Condition 顾名思义&#xff1a;条件。有点类似于if语句&#xff0c;只不过是通过注解的形式来实现。 以一个实际需求来学习该原理&#xff1a;有一个实体类User&#xff0c;想要创建该实例化对象…