zookeeper master 选举

原文地址:

http://www.cnblogs.com/nevermorewang/p/5611807.html

选主原理介绍:zookeeper的节点有两种类型,持久节点跟临时节点。临时节点有个特性,就是如果注册这个节点的机器失去连接(通常是宕机),那么这个节点会被zookeeper删除。选主过程就是利用这个特性,在服务器启动的时候,去zookeeper特定的一个目录下注册一个临时节点(这个节点作为master,谁注册了这个节点谁就是master),注册的时候,如果发现该节点已经存在,则说明已经有别的服务器注册了(也就是有别的服务器已经抢主成功),那么当前服务器只能放弃抢主,作为从机存在。同时,抢主失败的当前服务器需要订阅该临时节点的删除事件,以便该节点删除时(也就是注册该节点的服务器宕机了或者网络断了之类的)进行再次抢主操作。从机具体需要去哪里注册服务器列表的临时节点,节点保存什么信息,根据具体的业务不同自行约定。选主的过程,其实就是简单的争抢在zookeeper注册临时节点的操作,谁注册了约定的临时节点,谁就是master。

主要有两个类,WorkServer为主服务类,RunningData用于记录运行数据。因为是简单的demo,我们只做抢master节点的编码,对于从节点应该去哪里注册服务列表信息,不作编码。

  采用zkClient实现,代码如下:

  WorkServer类

package com.zookeeper.master;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkInterruptedException;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.apache.zookeeper.CreateMode;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by nevermore on 16/6/22.
 */
public class WorkServer {

    //客户端状态
    private volatile boolean running = false;

    private ZkClient zkClient;

    //zk主节点路径
    public static final String MASTER_PATH = "/master";

    //监听(用于监听主节点删除事件)
    private IZkDataListener dataListener;

    //服务器基本信息
    private RunningData serverData;
    //主节点基本信息
    private RunningData masterData;

    //调度器
    private ScheduledExecutorService delayExector = Executors.newScheduledThreadPool(1);
    //延迟时间5s
    private int delayTime = 5;

    public WorkServer(RunningData runningData){
        this.serverData = runningData;
        this.dataListener = new IZkDataListener() {
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                //takeMaster();

                if(masterData != null && masterData.getName().equals(serverData.getName())){
                    //若之前master为本机,则立即抢主,否则延迟5秒抢主(防止小故障引起的抢主可能导致的网络数据风暴)
                    takeMaster();
                }else{
                    delayExector.schedule(new Runnable() {
                        @Override
                        public void run() {
                            takeMaster();
                        }
                    },delayTime, TimeUnit.SECONDS);
                }

            }
        };
    }

    //启动
    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 stopped.....");
        }
        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() {//测试抢主用,每5s释放一次主节点
                @Override
                public void run() {
                    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 runningData = zkClient.readData(MASTER_PATH);
            masterData = runningData;
            if (masterData.getName().equals(serverData.getName())) {
                return true;
            }
            return false;

        }catch (ZkNoNodeException e){//节点不存在
            return  false;
        }catch (ZkInterruptedException e){//网络中断
            return checkMaster();
        }catch (Exception e){//其它
            return false;
        }
    }

    public void setZkClient(ZkClient zkClient) {
        this.zkClient = zkClient;
    }

    public ZkClient getZkClient() {
        return zkClient;
    }
}

RunningData类:

package com.zookeeper.master;

import java.io.Serializable;

/**
 * Created by nevermore on 16/6/22.
 */
public class RunningData implements Serializable {

    private static final long serialVersionUID = 4260577459043203630L;

    //服务器id
    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;
    }
}

说明:在实际生产环境中,可能会由于插拔网线等导致网络短时的不稳定,也就是网络抖动。由于正式生产环境中可能server在zk上注册的信息是比较多的,而且server的数量也是比较多的,那么每一次切换主机,每台server要同步的数据量(比如要获取谁是master,当前有哪些salve等信息,具体视业务不同而定)也是比较大的。那么我们希望,这种短时间的网络抖动最好不要影响我们的系统稳定,也就是最好选出来的master还是原来的机器,那么就可以避免发现master更换后,各个salve因为要同步数据等导致的zk数据网络风暴。所以在WorkServer中,54-63行,我们抢主的时候,如果之前主机是本机,则立即抢主,否则延迟5s抢主。这样就给原来主机预留出一定时间让其在新一轮选主中占据优势,从而利于环境稳定。

测试代码:

package com.zookeeper.master;

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;

/**
 * Created by nevermore on 16/6/23.
 */
public class LeaderSelectorZkClient {

    //启动的服务个数
    private static final int        CLIENT_QTY = 10;
    //zookeeper服务器的地址
    private static final String     ZOOKEEPER_SERVER = "localhost: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();
                }
            }
        }
    }
}

原文地址:https://www.cnblogs.com/newlangwen/p/10143987.html

时间: 2024-11-12 08:51:32

zookeeper master 选举的相关文章

ZooKeeper场景实践:(6)集群监控和Master选举

1. 集群机器监控 这通常用于那种对集群中机器状态,机器在线率有较高要求的场景,能够快速对集群中机器变化作出响应.这样的场景中,往往有一个监控系统,实时检测集群机器是否存活. 利用ZooKeeper有两个特性(读可监控,临时节点),就可以实现一种集群机器存活性监控系统: 1. 客户端在节点 x 上注册一个Watcher,那么如果x的子节点变化了,会通知该客户端 2. 创建EPHEMERAL类型的节点,一旦客户端和服务器的会话结束或过期,那么该节点就会消失 利用这两个特性,可以分别实现对客服端的状

zookeeper典型应用场景之一:master选举

对于zookeeper这种东西,仅仅知道怎么安装是远远不够的,至少要对其几个典型的应用场景进行了解,才能比较全面的知道zk究竟能干啥,怎么玩儿,以后的日子里才能知道这货如何能为我所用.于是,有了如下的学习: 我们知道zookeeper可以用于搭建高可用服务框架,主要先看以下几个应用场景:1. master的选举基本思路和编码实现2. 数据的发布和订阅3. 软负载均衡4. 分布式队列5. 分布式锁6. 命名服务 目前zookeeper常用的开发包有zkclient跟curator,后者更为方便,日

使用zookeeper实现分布式master选举(c 接口版本)

zookeeper,已经被很多人所熟知,主要应用场景有(数据订阅/发布 ,负载均衡, 命名服务, 分布式协调/通知,集群管理,Master选举,分布式锁,分布式队列). C接口的描述  主要参考 Haippy 的文章 :Zookeeper C API 指南 (感谢大神) 但是网上的C++版 示例代码少之又少,作为一个小白,自己摸索,给大家参考. Master选举的需求主要如下: 1.多台机器同时进行选举,产生唯一的一台机器作为Master,其它的机器作为slave. 2.当Master宕机后,需

Zookeeper系列五:Master选举、ZK高级特性:基本模型

一.Master选举 1. master选举原理: 有多个master,每次只能有一个master负责主要的工作,其他的master作为备份,同时对负责工作的master进行监听,一旦负责工作的master挂掉了,其他的master就会收到监听的事件,从而去挣脱负责工作的权利,其他没有争夺到负责主要工作的master转而去监听负责工作的新master. 本质其实是利用zookeeper的临时节点的特性:临时节点随着会话的消亡二消亡,同一个临时节点只能创建一个,创建失败的节点(从master)对创

(原)3.1 Zookeeper应用 - Master选举

本文为原创文章,转载请注明出处,谢谢 Master 选举 1.原理 服务器争抢创建标志为Master的临时节点 服务器监听标志为Master的临时节点,当监测到节点删除事件后展开新的一轮争抢 某个服务器成功创建则为Master 2.架构图 Master:服务器争抢节点 Servers:服务器列表节点 work Server:服务器节点 3.流程图 4.核心代码 workServer监听 public WorkServer(final ServerData serverData) { this.s

品味Zookeeper之选举及数据一致性_3

品味Zookeeper之选举及数据一致性 本文思维导图 前言 为了高可用和数据安全起见,zk集群一般都是由几个节点构成(由n/2+1,投票机制决定,肯定是奇数个节点).多节点证明它们之间肯定会有数据的通信,同时,为了能够使zk集群对外是透明的,一个整体对外提供服务,那么客户端访问zk服务器的数据肯定是要数据同步,也即数据一致性. zk集群是Leader/Follower模式来保证数据同步的.整个集群同一时刻只能有一个Leader,其他都是Follower或Observer.Leader是通过选举

Zookeeper leader选举

Zookeeper leader选举 由 xpproen 创建,youj 最后一次修改 2016-12-27 让我们分析如何在ZooKeeper集合中选举leader节点.考虑一个集群中有N个节点.leader选举的过程如下: 所有节点创建具有相同路径 /app/leader_election/guid_ 的顺序.临时节点. ZooKeeper集合将附加10位序列号到路径,创建的znode将是 /app/leader_election/guid_0000000001,/app/leader_el

ZooKeeper(六)-- ZAB协议、分布式锁/master选举

一.CAP理论和BASE理论 1.CAP理论 CAP理论,指的是在一个分布式系统中,不可能同时满足Consistency(一致性). Availability(可用性).Partition tolerance(分区容错性)这三个基本需求,最多只能满足其中的两项. 对于分布式系统而言,分区容错性是一个最基本的要求,因为分布式系统中的组件必然需要部署到不通的节点,必然会出现子网络,在分布式系统中,网络问题是必定会出现的异常.因此分布式系统只能在C(一致性)和A(可用性)之间进行权衡.  (1)Con

zookeeper的选举机制

1)半数机制:集群中半数以上机器存活,集群可用.所以zookeeper适合装在奇数台机器上. 2)Zookeeper虽然在配置文件中并没有指定master和slave.但是,zookeeper工作时,是有一个节点为leader,其他则为follower,Leader是通过内部的选举机制临时产生的 3)以一个简单的例子来说明整个选举的过程. 假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器