ZooKeeper—master选举(笔记)

Curator实现简单的master选举

1.在zookeeper服务器上创建一个节点用于存储master服务器地址

2.若master服务器宕机,则删除master节点,同时发送消息给所有服务器开始争抢新一轮的master

3.所有服务器开始在zookeeper服务器上创建master节点,master节点数据内容为当前争抢的服务器地址

4.若有服务器成功第一个创建master节点则此服务器为master

5.之后的服务器创建master节点会提示节点已存在,则获取master节点数据,记录下新一轮的master服务器地址

6.为防止网络抖动,可以在每次争抢master时优先让上一轮的master服务器创建master节点

public class RunningData implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 5782460288263167189L;

    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;
    }


}
public class WorkServer {

    private volatile boolean running = false;//记录服务器的状态

    private static final String MASTER_PATH = "/master";

    private static final String SERVER_IP = "192.168.0.3:2181";

    private PathChildrenCache cache;

    private CuratorFramework client;

    private RunningData serverData; //记录当前服务器基本信息

    private RunningData masterData = new RunningData();//记录集群中master的基本信息

    private ScheduledExecutorService delayExecutor = Executors.newScheduledThreadPool(1);

    private int delayTime = 5;

    public WorkServer(RunningData rd) throws Exception {
        this.serverData = rd;

    }

    public void start() throws Exception {
        if(running) {
            throw new Exception("server has startup...");
        }

        running = true;
        RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);
        client = CuratorFrameworkFactory.newClient(SERVER_IP, 5000, 5000, retry);
        client.start();
        cache = new PathChildrenCache(client,MASTER_PATH,true);
        cache.start();
        cache.getListenable().addListener(new PathChildrenCacheListener() {

            @Override
            public void childEvent(CuratorFramework curator, PathChildrenCacheEvent event) throws Exception {
                switch (event.getType()) {
                case CHILD_ADDED:
                    break;
                case CHILD_UPDATED:
                    break;
                case CHILD_REMOVED:
                    takeMaster();
                    //防止网络抖动选出来的master和上一次master一样
                    //System.out.println("remove");
                    /*if(masterData != null && masterData.getName().equals(serverData.getName())) {//当前服务器是上次master
                        takeMaster();
                    }
                    else{
                        delayExecutor.schedule(new Runnable(){//否则延迟5秒争抢master

                            @Override
                            public void run() {
                                try {
                                    takeMaster();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }

                        }, delayTime, TimeUnit.SECONDS);
                    }*/
                    break;
                default:
                    break;
                }
            }

        });
        //System.out.println("now start:" + serverData.getCid());
        takeMaster();

    }

    public void stop() throws Exception {
        if(!running) {
            throw new Exception("server has stoped!");
        }

        running = false;
        releaseMaster();
        client.close();
    }

    /*
     * 争抢master
     */
    private void takeMaster() throws Exception {
        if(!running) {
            return;
        }
        //System.out.println("now takemaster:" + serverData.getCid());
        try {  
            Long cid = serverData.getCid();
            String s = String.valueOf(cid);
            client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(MASTER_PATH+MASTER_PATH,s.getBytes());
            masterData.setCid(serverData.getCid());
            masterData.setName(serverData.getName());
            System.out.println("master is " + masterData.getName());
            //测试代码
            delayExecutor.schedule(new Runnable(){

                @Override
                public void run() {
                    try {
                        releaseMaster();
                    }catch(Exception e) {
                        e.printStackTrace();
                    }
                }

            }, delayTime, TimeUnit.SECONDS);
        }catch(NodeExistsException e) {
            byte[] bytes1 = client.getData().forPath(MASTER_PATH+MASTER_PATH);
            String s = new String(bytes1);
            if(bytes1 == null) {
                takeMaster();
            }else {
                if(!s.equals("")){
                    Long cid = Long.valueOf(s);
                    masterData.setCid(cid);
                    masterData.setName("client: " + cid);
                    //System.out.println("now ok:" + serverData.getCid());
                }
            }
        }
    }

    /*
     * 释放master权利
     */
    private void releaseMaster() throws Exception {
        if(checkMaster()) {
            client.delete().guaranteed().deletingChildrenIfNeeded().forPath(MASTER_PATH);
        }

    }

    /*
     * 检测自己是否为Master
     */
    private boolean checkMaster() {

       try{ 
             byte[] bytes = client.getData().forPath(MASTER_PATH+MASTER_PATH);
             String s = new String(bytes);
             if(!s.equals("")) {
                 Long cid = Long.valueOf(s);

                 if(serverData.getCid().equals(cid)) {
                     return true;
                 }
             }
        } catch(NoNodeException e1) {
            return false;
        } catch(InterruptedException e2) {
            return checkMaster();
        } catch(Exception e) {  
             System.out.println("translation" + e.getMessage());  
             e.printStackTrace();  
        } 

        return false;
    }
}

启动:

public class LeaderSelector {
    //启动服务个数
    private static final int CLIENT_QTY = 4;

    private static final String SERVER_IP = "192.168.0.3:2181";

    public static void main(String[] args) throws Exception {
        List<WorkServer> workServers = new ArrayList<>();

        try {
            /*RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);
            CuratorFramework client = CuratorFrameworkFactory.newClient(SERVER_IP, 5000, 5000, retry);
            client.start();
            Thread.sleep(5000);*/
            for(int i=1; i<=CLIENT_QTY; i++) {


                RunningData runningData = new RunningData();
                runningData.setCid(Long.valueOf(i));
                runningData.setName("client: " + i);

                WorkServer workServer = new WorkServer(runningData);
                workServer.start();
                workServers.add(workServer);
            }

            Thread.sleep(Integer.MAX_VALUE);
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("Shutdown。。。");
            for(WorkServer workServer : workServers) {
                try{
                    workServer.stop();
                    System.out.println("close");
                }catch(Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}

console:

master is client: 1
master is client: 1
master is client: 2
master is client: 3
master is client: 1
master is client: 1
master is client: 1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值