Curator--3 Master选举LeaderLatch与LeaderSelector

1 LeaderSelector

0 基于InterProcessMutex分布式锁进行抢主,抢到锁的即为Leader
1 当实例被选为leader之后,调用takeLeadership方法进行业务逻辑处理,处理完成即释放领导权。
2 autoRequeue()方法的调用确保此实例在释放领导权后还可能获得领导权。默认为false。

1.1 组成

构造函数
client zk客户端实例
leaderPath Leader选举根节点路径
executorService master选举使用的线程池
listener 节点成为Leader后的回调

    public LeaderSelector(CuratorFramework client, String leaderPath, ThreadFactory threadFactory, Executor executor, LeaderSelectorListener listener)
    {
        this(client, leaderPath, new CloseableExecutorService(wrapExecutor(executor), true), listener);
    }

    /**
     * @param client          the client
     * @param leaderPath      the path for this leadership group
     * @param executorService thread pool to use
     * @param listener        listener
     */
    public LeaderSelector(CuratorFramework client, String leaderPath, ExecutorService executorService, LeaderSelectorListener listener)
    {
        this(client, leaderPath, new CloseableExecutorService(executorService), listener);
    }

    /**
     * @param client          the client
     * @param leaderPath      the path for this leadership group
     * @param executorService thread pool to use
     * @param listener        listener
     */
    public LeaderSelector(CuratorFramework client, String leaderPath, CloseableExecutorService executorService, LeaderSelectorListener listener)
    {
        Preconditions.checkNotNull(client, "client cannot be null");
        PathUtils.validatePath(leaderPath);
        Preconditions.checkNotNull(listener, "listener cannot be null");

        this.client = client;
        this.listener = new WrappedListener(this, listener);
        hasLeadership = false;

        this.executorService = executorService;
        mutex = new InterProcessMutex(client, leaderPath)
        {
            @Override
            protected byte[] getLockNodeBytes()
            {
                return (id.length() > 0) ? getIdBytes(id) : null;
            }
        };
    }

1.2 源码

    //循环选举
    public void autoRequeue()
    {
        autoRequeue.set(true);
    }
   //start()
   //   -- requeue()
   //       -- internalRequeue() 
   private synchronized boolean internalRequeue()
    {
    	//没有进入抢主并且已经调用过start()方法
        if ( !isQueued && (state.get() == State.STARTED) )
        {
            isQueued = true;
            Future<Void> task = executorService.submit(new Callable<Void>()
            {
                @Override
                public Void call() throws Exception
                {
                    try
                    {
                    	//开始抢主
                        doWorkLoop();
                    }
                    finally
                    {
                        clearIsQueued();
                        //如果设置了释放权限自动抢主 则重新开始抢主
                        if ( autoRequeue.get() )
                        {
                            //递归调用
                            internalRequeue();
                        }
                    }
                    return null;
                }
            });
            ourTask.set(task);

            return true;
        }
        return false;
    }
void doWork() throws Exception
    {
        hasLeadership = false;
        try
        {
        	//利用Curator的分布式锁InterProcessMutex抢锁
            mutex.acquire();

            hasLeadership = true;
            try
            {
            	//测试用 可以忽略
                if ( debugLeadershipLatch != null )
                {
                    debugLeadershipLatch.countDown();
                }
                if ( debugLeadershipWaitLatch != null )
                {
                    debugLeadershipWaitLatch.await();
                }
                //抢锁成功 触发监听器takeLeadership()回掉方法
                listener.takeLeadership(client);
            }
            catch ( InterruptedException e )
            {
                Thread.currentThread().interrupt();
                throw e;
            }
            catch ( Throwable e )
            {
                ThreadUtils.checkInterrupted(e);
            }
            finally
            {
                clearIsQueued();
            }
        }
        catch ( InterruptedException e )
        {
            Thread.currentThread().interrupt();
            throw e;
        }
        finally
        {
        	//触发完监听器方法后 释放leader权限 释放分布式锁
            if ( hasLeadership )
            {
                hasLeadership = false;
                try
                {
                    mutex.release();
                }
                catch ( Exception e )
                {
                    ThreadUtils.checkInterrupted(e);
                    log.error("The leader threw an exception", e);
                    // ignore errors - this is just a safety
                }
            }
        }
    }


2 LeaderLatch

0 需要手动调用close()方法来释放leader权限释放leader才会进行下一轮选举
1 添加回调实现成功选举和失败选举。

2.0 主要方法 :

//调用start方法开始抢主
void start()

//调用close方法释放leader权限
void close()

//await方法阻塞线程,尝试获取leader权限,但不一定成功,超时失败
boolean await(long, java.util.concurrent.TimeUnit)

//判断是否拥有leader权限
boolean hasLeadership()

2.1核心流程 :

1 zk客户端往同一路径下创建临时节点,创建后回调callBack
2 在回调事件中判断自身节点是否是节点编号最小的一个
3 如果是,则抢主成功,如果不是,设置对前一个节点(编号更小的)的删除事件的监听器,删除事件触发后重新进行抢主

3 区别

1 leaderlatch需要调用close方法才能释放主导权,并且不能重新获得。leaderselector当执行完takeleadership方法后自动释放主导权,并且可以设置autorequeue重新再获取领导权
2 实现方式不同leaderselector使用分布式锁InterProcessMutex实现
3 LeaderSelector相对LeaderLatch也更灵活,在执行完takerLeaderShip中的逻辑后会自动释放Leader权限,也能调用autoRequeue自动重新抢主

参考

https://blog.csdn.net/hosaos/article/details/88727817

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值