zookeeper curator选主(Leader)

在分布式系统设计中,选主是一个常见的场景。选主是一个这样的过程,通过选主,主节点被选择出来控制其他节点或者是分配任务。

选主算法要满足的几个特征:

1)各个节点均衡的获得成为主节点的权利,一旦主节点被选出,其他的节点可以感知到谁是主节点,被服从分配。

2)主节点是唯一存在的

3)一旦主节点失效,宕机或者断开连接,其他的节点能够感知,并且重新进行选主算法。

zookeeper实现了安全可靠的选主机制。

作为zookeeper的高级api封装库curator选主算法主要有以下两个:Leader LatchLeader Election

1、Leader Latch

实例被选为leader后,执行isLeader中的逻辑。当领导权易主之后才会再次执行isLeader。

直接看代码吧,注释里面已经有说明了。

/*
    *  Leader Latch(群首闩)
    *  isLeader 中的方法会在实例被选为主节点后被执行, 而notLeader中的不会被执行
    *  如果主节点被失效, 会进行重新选主
    * */
    public void setLeaderLatch(String path) {
        try {
            String id = "client#" + InetAddress.getLocalHost().getHostAddress();
            leaderLatch = new LeaderLatch(client, path, id);
            LeaderLatchListener leaderLatchListener = new LeaderLatchListener() {
                @Override
                public void isLeader() {
                    logger.info("[LeaderLatch]我是主节点, id={}", leaderLatch.getId());
                }

                @Override
                public void notLeader() {
                    logger.info("[LeaderLatch]我不是主节点, id={}", leaderLatch.getId());
                }
            };
            leaderLatch.addListener(leaderLatchListener);
            leaderLatch.start();
        } catch (Exception e) {
            logger.error("c创建LeaderLatch失败, path={}", path);
        }
    }

    /*
    *   判断实例是否是主节点
    * */
    public boolean hasLeadershipByLeaderLatch() {
        return leaderLatch.hasLeadership();
    }

    /*
    *   阻塞直到获得领导权
    * */
    public void awaitByLeaderLatch() {
        try {
            leaderLatch.await();
        } catch (InterruptedException | EOFException e) {
            e.printStackTrace();
        }
    }

    /*
    *   尝试获得领导权并超时
    * */
    public boolean awaitByLeaderLatch(long timeout, TimeUnit unit) {
        boolean hasLeadership = false;
        try {
            hasLeadership = leaderLatch.await(timeout, unit);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return  hasLeadership;
    }

2、Leader Election

当实例被选为leader之后,调用takeLeadership方法进行业务逻辑处理,处理完成即释放领导权。

其中autoRequeue()方法的调用确保此实例在释放领导权后还可能获得领导权。

/*
    *   Leader Election模式
    *   实例被选主后执行takeLeadership, 执行完之后立刻释放领导权, 再次选主, 所以这里sleep 10秒
    * */
    public void setLeaderSelector(String path) {
        try {
            final String id = "client#" + InetAddress.getLocalHost().getHostAddress();
            LeaderSelectorListener leaderSelectorListener = new LeaderSelectorListener() {
                @Override
                public void takeLeadership(CuratorFramework client) throws Exception {
                    logger.info("[LeaderSelector]我是主节点, id={}", id);
                    Thread.sleep(10000);
                }

                @Override
                public void stateChanged(CuratorFramework client, ConnectionState newState) {

                }
            };
            leaderSelector = new LeaderSelector(client, path, leaderSelectorListener);
            leaderSelector.autoRequeue();
            leaderSelector.start();
        } catch (Exception e) {
            logger.error("c创建LeaderLatch失败, path={}", path);
        }
    }

LeaderLatch instances add a ConnectionStateListener to watch for connection problems. If SUSPENDED or LOST is reported, the LeaderLatch that is the leader will report that it is no longer the leader (i.e. there will not be a leader until the connection is re-established). If a LOST connection is RECONNECTED, the LeaderLatch will delete its previous ZNode and create a new one.

Users of LeaderLatch must take account that connection issues can cause leadership to be lost. i.e. hasLeadership() returns true but some time later the connection is SUSPENDED or LOST. At that point hasLeadership() will return false. It is highly recommended that LeaderLatch users register a ConnectionStateListener.

LeaderSelectorListener类继承了ConnectionStateListener。一旦LeaderSelector启动,它会向curator客户端添加监听器。 使用LeaderSelector必须时刻注意连接的变化。一旦出现连接问题如SUSPENDED,curator实例必须确保它可能不再是leader,直至它重新收到RECONNECTED。如果LOST出现,curator实例不再是leader并且其takeLeadership()应该直接退出。

推荐的做法是,如果发生SUSPENDED或者LOST连接问题,最好直接抛CancelLeadershipException,此时,leaderSelector实例会尝试中断并且取消正在执行takeLeadership()方法的线程。 建议扩展LeaderSelectorListenerAdapter, LeaderSelectorListenerAdapter中已经提供了推荐的处理方式 。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏calmound

hust The mell hell

http://acm.sdibt.edu.cn:8080/judge/contest/view.action?cid=573#problem/E 题意:每个人需...

31450
来自专栏极客慕白的成长之路

jQuery深入——动画、常用工具、JSON、Ajax

4、停止动画 - stop([stopAll [, goToEnd]]) stopAll 布尔值,规定是否停止被选元素的所有加入队列的动画。默认是 false。...

14310
来自专栏pangguoming

tomcat 用AXIS2发布WebService 网站的方法

Axis2+tomcat7.0 实现webService 服务端发布与客户端的调用。   Aixs2开发webService的方法有很多,在此只介绍一种比较简单...

56260
来自专栏企鹅号快讯

Python编写渗透工具学习笔记二

1 用pxssh暴力破解ssh密码 因为默认情况下只有linux有ssh服务,所以此脚本只适用于在linux下使用 靶机 10.10.10.128 kali6...

20560
来自专栏抠抠空间

rest_framework之解析器、路由控制、分页

17600
来自专栏JavaEE

mybatis-plus的使用 ------ 进阶

关于mybatis-plus的简介以及基本使用,我在《mybatis-plus的使用 ------ 入门》一文中已做介绍,此处不再赘述。本文主要对mybatis...

84470
来自专栏技术专栏

慕课网Flask高级编程实战-11.Python与Flask的结合应用

视图函数接受用户填写的email账号,如果不存在应该跳转到404界面,这个逻辑flask-sqlalchemy为我们提供了良好的封装,不需要手动去处理,只需要调...

42630
来自专栏jeremy的技术点滴

Retrying_Library_For_Java

34450
来自专栏向治洪

dex分包方案

当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILE...

22550
来自专栏向治洪

android分包方案

当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILE...

214100

扫码关注云+社区

领取腾讯云代金券