curator leaderLatch 源码阅读笔记

zookeeper 结构

img

curator api 介绍

CuratorFramework //可以直接看做zkclient 的上层封装,作为client用

image-20210601113534099

基本用法:

//build client
CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder().retryPolicy(
                new ExponentialBackoffRetry(zookeeperProperties.getBaseSleepTimeMs(),
                        zookeeperProperties.getMaxRetries(), zookeeperProperties.getMaxSleepTimeMs()))
                .connectString(zookeeperProperties.getServerList());
client = builder.build();
        client.start();
​
//基本操作
client.create().forPath("/head", new byte[0]);
client.delete().inBackground().forPath("/head");
client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child", new byte[0]);
client.getData().watched().inBackground().forPath("/test");

image-20210601114759021

curator leaderLatch 源码分析

  • 先说构建、开始leader选举和选上或者没选上等待继续选的过程;

//基本用法
LeaderLatch leaderLatch = new LeaderLatch(client, "/leaderLatchTest", UUID.randomUUID().toString());
leaderLatch.addListener(new LeaderLatchListener() {
  @Override
  public void isLeader() {
    System.out.println("isLeader");
  }
​
  @Override
  public void notLeader() {
    System.out.println("notLeader");
  }
});
leaderLatch.start();

看下构造方法,只是在传入操作zk节点的client,涉及到leader选举的主题路径,以及竞争过程中创建出字节点的值

public LeaderLatch(CuratorFramework client, String latchPath, String id)
    {
        this(client, latchPath, id, CloseMode.SILENT);
    }
​
    /**
     * @param client    the client
     * @param latchPath the path for this leadership group
     * @param id        participant ID
     * @param closeMode behaviour of listener on explicit close.
     */
    public LeaderLatch(CuratorFramework client, String latchPath, String id, CloseMode closeMode)
    {
        this.client = Preconditions.checkNotNull(client, "client cannot be null");
        this.latchPath = PathUtils.validatePath(latchPath);
        this.id = Preconditions.checkNotNull(id, "id cannot be null");
        this.closeMode = Preconditions.checkNotNull(closeMode, "closeMode cannot be null");
    }

zk 下节点结构:

image-20210601134742432

image-20210601143807764

public void start() throws Exception
    {
        Preconditions.checkState(state.compareAndSet(State.LATENT, State.STARTED), "Cannot be started more than once");
​
        startTask.set(AfterConnectionEstablished.execute(client, new Runnable()
                {
                    @Override
                    public void run()
                    {
                        try
                        {
                          //这里回监听选举主题下节点的变化,和首次参与选举判断逻辑
                            internalStart();
                        }
                        finally
                        {
                            startTask.set(null);
                        }
                    }
                }));
    } 
private synchronized void internalStart()
    {
        if ( state.get() == State.STARTED )
        {
            client.getConnectionStateListenable().addListener(listener);//这里增加listener
            try
            {
                reset();//选举逻辑
            }
            catch ( Exception e )
            {
                ThreadUtils.checkInterrupted(e);
                log.error("An error occurred checking resetting leadership.", e);
            }
        }
    }

先看reset逻辑

void reset() throws Exception
    {
        setLeadership(false);//初始化:设置为非leader
        setNode(null);//初始化
​
        //创建子节点的回调操作【只是执行异步化,理解时候可以把下面client操作看做同步操作,这里就是同步操作的后续逻辑】
        BackgroundCallback callback = new BackgroundCallback()
        {
            @Override
            public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
            {
                if ( debugResetWaitLatch != null )
                {
                    debugResetWaitLatch.await();
                    debugResetWaitLatch = null;
                }
​
                if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                {
                    //记录子节点路径,。。。
                    setNode(event.getName());
                    if ( state.get() == State.CLOSED )
                    {
                        setNode(null);
                    }
                    else
                    {
                        //首次会走这里,拿到子节点,排序、如果咱排在第一,那就是leader,否则就观察前一个节点(node)的动静
                        getChildren();
                    }
                }
                else
                {
                    log.error("getChildren() failed. rc = " + event.getResultCode());
                }
            }
        };
        //创建临时有序子节点【CreateMode.EPHEMERAL_SEQUENTIAL】
        //路径构造逻辑ZKPaths.makePath(latchPath, LOCK_NAME),这里不细说了,待会看图
        //子节点的值就是构造时传入的 id【LeaderSelector.getIdBytes(id)】
 client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).inBackground(callback).forPath(ZKPaths.makePath(latchPath, LOCK_NAME), LeaderSelector.getIdBytes(id));
    }

Ps:回调事件的code值,0==ok代表操作完成

image-20210601141251701

private void getChildren() throws Exception
    {
        BackgroundCallback callback = new BackgroundCallback()
        {
            ...
            //子节点排序,判断leader
            checkLeadership(event.getChildren());
            ...
        };
  //拿到子节点
        client.getChildren().inBackground(callback).forPath(ZKPaths.makePath(latchPath, null));
    }
private void checkLeadership(List<String> children) throws Exception
    {
        final String localOurPath = ourPath.get();
        //1 排序
        List<String> sortedChildren = LockInternals.getSortedChildren(LOCK_NAME, sorter, children);
        int ourIndex = (localOurPath != null) ? sortedChildren.indexOf(ZKPaths.getNodeFromPath(localOurPath)) : -1;
        ...
        if ( ourIndex == 0 )
        {
          //处理作为leader的后续逻辑
            setLeadership(true);
        }
        else
        {
            String watchPath = sortedChildren.get(ourIndex - 1);
            Watcher watcher = new Watcher()
            {
                @Override
                public void process(WatchedEvent event)
                {
                    if ( (state.get() == State.STARTED) && (event.getType() == Event.EventType.NodeDeleted) && (localOurPath != null) )
                    {
                      ...
                      //前一个节点一有变化【删除】,重新拿到所有子节点排序,判断leader【重复前面操作】
                      getChildren();
                      ... 
                    }
                }
            };
​
            BackgroundCallback callback = new BackgroundCallback()
            {
                @Override
                public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
                {
                    if ( event.getResultCode() == KeeperException.Code.NONODE.intValue() )
                    {
                        // previous node is gone - reset
                        reset();
                    }
                }
            };
          
            //观察前一个节点动静
            // use getData() instead of exists() to avoid leaving unneeded watchers which is a type of resource leak
            client.getData().usingWatcher(watcher).inBackground(callback).forPath(ZKPaths.makePath(latchPath, watchPath));
        }
    }
  • 下面说下,选上之后,以及选上因为断链失去leader如何通知业务代码的逻辑;还有就是自动续期的概念;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值