Curator 客户端选举

本文介绍Apache Curator中LeaderLatch和LeaderSelector两种客户端选举方式的区别及使用方法。通过具体示例展示了如何利用这两种方式实现分布式系统的领导者选举。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近使用当当Elastic-job分布式任务调度,了解当当任务具体如何调度执行的,其中涉及到apche Curator客户端选举;对其补充一下这方面知识,curator主要提供两种客户端选举方式LeaderLatch和LeaderSelector

具体使用参考官方http://curator.apache.org/getting-started.html

  • LeaderLatch
    通过hasLeadership()查看自己是否是leader, 如果是的话返回true
    可以通过.getLeader().getId()可以得到当前的leader的传入自定义的ID
    只能通过close释放当前的领导权
    await是一个阻塞方法, 尝试获取leader地位,但是未必能上位,最终获取到leader返回
    start启动LeaderLatch

    LeaderLatch提供两个构造函数:

    //不带ID构造
    public LeaderLatch(CuratorFramework client, String latchPath) {
        this(client, latchPath, "", LeaderLatch.CloseMode.SILENT);
    }
    //传入自定义ID的构造
    public LeaderLatch(CuratorFramework client, String latchPath, String id) {
        this(client, latchPath, id, LeaderLatch.CloseMode.SILENT);
    }
    判断是否选举后的leader:
    public boolean hasLeadership() {
        return this.state.get() == LeaderLatch.State.STARTED && this.hasLeadership.get();
    }
    LeaderLatch添加删除监听:
    //添加监听
    public void addListener(LeaderLatchListener listener) {
        this.listeners.addListener(listener);
    }
    //带执行器监听
    public void addListener(LeaderLatchListener listener, Executor executor) {
        this.listeners.addListener(listener, executor);
    }
    //删除监听
    public void removeListener(LeaderLatchListener listener) {
        this.listeners.removeListener(listener);
    }

    LeaderLatch简单使用:
  • public static void main(String[] args) {
        List<LeaderLatch> leaders = Lists.newArrayList();
        List<CuratorFramework> clients = Lists.newArrayList();
    
        try {
            for (int i = 0; i < 10; i++) {
                CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.20.34:2181,192.168.20.33:2181", new ExponentialBackoffRetry(1000, 3));
                clients.add(client);
    
                final LeaderLatch leaderLatch = new LeaderLatch(client, "/motan", "client-" + i);
                leaderLatch.addListener(new LeaderLatchListener() {
                    @Override
                    public void isLeader() {
                        System.out.println("I am Leader:" + leaderLatch.getId());
                    }
    
                    @Override
                    public void notLeader() {
                        System.out.println("I am not Leader");
                    }
                });
                leaders.add(leaderLatch);
    
                client.start();
                leaderLatch.start();
    
            }
            //等待选举结果
            Thread.sleep(10000);
            for (LeaderLatch leaderLatch : leaders) {
                //判断是否leader
                if (leaderLatch.hasLeadership()) {
                    System.out.println("===================" + leaderLatch.getId());
                }
            }
    
            System.out.println("Press enter/return to quit\n");
            new BufferedReader(new InputStreamReader(System.in)).readLine();
        } catch (Exception e) {
    
        } finally {
            for (CuratorFramework client : clients) {
                CloseableUtils.closeQuietly(client);
            }
            for (LeaderLatch leaderLatch : leaders) {
                CloseableUtils.closeQuietly(leaderLatch);
            }
        }
    
    }
  • LeaderSelector
    LeaderSelector主要涉及到以下四个类:
    LeaderSelector
    LeaderSelectorListener
    LeaderSelectorListenerAdapter
    CancelLeadershipException

    start/close和LeaderLatch一样需要启动关闭才行
    leaderSelector.autoRequeue保证在此实例释放领导权之后还可能获得领导权
    takeLeadership方法如果想要某个被选举后的leader一直保持不变,将takeLeadership方法体内容加入死循环即可

    LeaderSelector简单使用:
    package com.lianpo.rpc.zk.curator;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.framework.recipes.leader.LeaderSelector;
    import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;
    import org.apache.curator.retry.ExponentialBackoffRetry;
    import org.apache.curator.utils.CloseableUtils;
    import java.io.BufferedReader;
    import java.io.Closeable;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.UUID;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import lombok.Getter;
    
    
    /**
     * Created by liz on 2017/1/13.
     *
     * @auther liz
     */
    @Getter
    public class CuratorFrame {
    
        private CuratorFramework client;
    
        public void init() {
            CuratorFrameworkFactory.Builder Builder = CuratorFrameworkFactory.builder()
                    .connectString("192.168.20.34:2181")
                    .retryPolicy(new ExponentialBackoffRetry(1000, 3, 3000))
                    //.namespace("")
                    .sessionTimeoutMs(3000)
                    .connectionTimeoutMs(3000);
    
            client = Builder.build();
            /*client.start();
            try {
                if (!client.blockUntilConnected(1000 * 3, TimeUnit.MILLISECONDS)) {
                    client.close();
                    throw new KeeperException.OperationTimeoutException();
                }
                //CHECKSTYLE:OFF
            } catch (final Exception ex) {
                ex.printStackTrace();
            }*/
    
        }
    
    
    
        //1、Recipes模块:Elections(选举),Locks(锁),Barriers(关卡),Atomic(原子量),Caches,Queues等
    
        /**
         * 本类基于leaderSelector实现,所有存活的client会公平的轮流做leader
         * 如果不想频繁的变化Leader,需要在takeLeadership方法里阻塞leader的变更! 或者使用 {@link}
         * LeaderLatchClient
         */
        class LeaderSelectorClient extends LeaderSelectorListenerAdapter implements Closeable {
            private final String name;
            private final LeaderSelector leaderSelector;
            private final String PATH = "/motan";
            private final AtomicInteger leaderCount = new AtomicInteger(1);
    
            public LeaderSelectorClient(CuratorFramework client, String name) {
                this.name = name;
                this.leaderSelector = new LeaderSelector(client, PATH, this);
                //设置一下随机ID
                this.leaderSelector.setId(UUID.randomUUID().toString());
                //保证此实例在释放领导权后还可能获得领导权
                this.leaderSelector.autoRequeue();
            }
    
            @Override
            public void close() throws IOException {
                this.leaderSelector.close();
            }
    
            public void start() throws IOException {
                this.leaderSelector.start();
            }
    
            @Override
            public void takeLeadership(CuratorFramework client) throws Exception {
                int waitSeconds = (int) (5 * Math.random() + 1);
                System.out.println(name + ":是当前客户端leader,选举次数:" + leaderCount.getAndIncrement() + ",选举ID:" + this.leaderSelector.getId());
    
                try {
                    Thread.sleep(TimeUnit.SECONDS.toMillis(waitSeconds));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    Thread.currentThread().interrupt();
                } finally {
                    System.out.println(name + ":让出领导权,选举ID:" + this.leaderSelector.getId());
                }
            }
    
        }
    
    
        //2、locks
    
    
    
        public static void main(String[] args) {
    
            List<CuratorFramework> clients = new ArrayList<CuratorFramework>();
            List<LeaderSelectorClient> selectorClients = new ArrayList<LeaderSelectorClient>();
            try {
                for (int i = 0; i < 10; i++) {
                    CuratorFrame curatorFrame = new CuratorFrame();
                    curatorFrame.init();
                    clients.add(curatorFrame.client);
                    CuratorFrame.LeaderSelectorClient leaderSelectorClient = curatorFrame.new LeaderSelectorClient(curatorFrame.client, "client#" + i);
                    selectorClients.add(leaderSelectorClient);
    
                    curatorFrame.client.start();
                    leaderSelectorClient.start();
    
                    //Stat stat = curatorFrame.client.checkExists().forPath("/motan");
                    //System.out.println("----------------------------stat--" + stat);
                }
    
                System.out.println("----------先观察一会选举的结果-----------");
                Thread.sleep(10000);
    
                System.out.println("----------关闭前5个客户端,再观察选举的结果-----------");
                for (int i = 0; i < 5; i++) {
                    clients.get(i).close();
                }
                System.out.println("--------------------------------------------------");
                // 这里有个小技巧,让main程序一直监听控制台输入,异步的代码就可以一直在执行。不同于while(ture)的是,按回车或esc可退出
                new BufferedReader(new InputStreamReader(System.in)).readLine();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("===================finally=======================");
                for (LeaderSelectorClient selectorClient : selectorClients) {
                    CloseableUtils.closeQuietly(selectorClient);
                }
                for (CuratorFramework client : clients) {
                    CloseableUtils.closeQuietly(client);
                }
            }
    
        }
    
    }

 总结:LeaderSelector与LeaderLatch, 通过LeaderSelectorListener可以对领导权进行控制, 在适当的时候释放领导权,这样每个节点都有可能获得领导权。 而LeaderLatch一根筋到死, 除非调用close方法,否则它不会释放领导权

转载于:https://my.oschina.net/u/3180962/blog/826485

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值