zookeeper高可用集群方案

文章介绍了使用Zookeeper进行分布式系统中Leader选举的三种策略:最小节点获胜、抢建唯一节点和法官判决。每种策略都涉及创建特定类型的ephemeral_sequential节点,利用Zookeeper的Watch机制监听节点变化,从而确定Leader身份或实现分布式锁。
摘要由CSDN通过智能技术生成

1、最小节点获胜

1. 设计 Path
集群共用父节点 parent znode,集群中的每个节点在 parent 目录下创建自己的 znode。
2. 选择节点类型
当 Leader 节点挂掉的时候,持有最小编号 znode 的集群节点成为新的 Leader,因此用
ephemeral_sequential 类型 znode。
3. 设计节点数据
可以根据业务需要灵活写入各种数据。
4. 设计 Watch
1. 节点启动或者重连后,在 parent 目录下创建自己的 ephemeral_sequntial znode;
2. 创建成功后扫描 parent 目录下所有 znode,如果自己的 znode 编号是最小的,则成为
Leader,否则 watch parent 目录;
3. 当 parent 目录有节点删除的时候,首先判断其是否是 Leader 节点,然后再看其编号是否
正好比自己小1,如果是则自己成为 Leader,如果不是继续 watch。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
    </dependency>
</dependencies>

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

@SpringBootApplication
public class ZooKeeperLeaderElectionApplication implements Watcher {

    private static final String ZOOKEEPER_CONNECTION_STRING = "localhost:2181";
    private static final int SESSION_TIMEOUT = 3000;
    private static final String ELECTION_NAMESPACE = "/election";

    @Autowired
    private ZooKeeper zooKeeper;

    @Bean
    public ZooKeeper zooKeeper() throws IOException {
        return new ZooKeeper(ZOOKEEPER_CONNECTION_STRING, SESSION_TIMEOUT, this);
    }

    @Override
    public void process(WatchedEvent event) {
        // Process ZooKeeper events
    }

    public void createElectionNode() throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists(ELECTION_NAMESPACE, false);
        if (stat == null) {
            zooKeeper.create(ELECTION_NAMESPACE, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    public void joinElection() throws KeeperException, InterruptedException {
        String currentNodePath = zooKeeper.create(ELECTION_NAMESPACE + "/node", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("Joined election with path: " + currentNodePath);
    }

    public void electLeader() throws KeeperException, InterruptedException {
        List<String> allNodes = zooKeeper.getChildren(ELECTION_NAMESPACE, false);
        Collections.sort(allNodes);

        String smallestNode = allNodes.get(0);
        String currentNode = currentNodePath.substring(currentNodePath.lastIndexOf("/") + 1);
        if (currentNode.equals(smallestNode)) {
            System.out.println("I am the leader!");
            // TODO: Execute leader-specific logic here
        } else {
            System.out.println("I am not the leader. Waiting for the leader to emerge...");
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        SpringApplication.run(ZooKeeperLeaderElectionApplication.class, args);
    }
}

2、抢建唯一节点

1. 设计 Path
集群所有节点只有一个 leader znode,本质上就是一个分布式锁。
2. 选择 znode 类型
当 Leader 节点挂掉的时候,剩余节点都来创建 leader znode,看谁
能最终抢到 leader znode,因此用 ephemeral 类型。
3. 设计节点数据
可以根据业务需要灵活写入各种数据。
4. 设计 Watch
1. 节点启动或者重连后,尝试创建 leader znode,尝试失败则
watch leader znode;
2. 当收到 leader znode 被删除的事件通知后,再次尝试创建 leader
znode,尝试成功则成为 leader ,失败则 watch leader znode。
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

@SpringBootApplication
public class ZooKeeperExclusiveNodeApplication implements Watcher {

    private static final String ZOOKEEPER_CONNECTION_STRING = "localhost:2181";
    private static final int SESSION_TIMEOUT = 3000;
    private static final String EXCLUSIVE_NODE_PATH = "/exclusive_node";

    @Autowired
    private ZooKeeper zooKeeper;

    @Bean
    public ZooKeeper zooKeeper() throws IOException {
        return new ZooKeeper(ZOOKEEPER_CONNECTION_STRING, SESSION_TIMEOUT, this);
    }

    @Override
    public void process(WatchedEvent event) {
        // Process ZooKeeper events
    }

    public void createExclusiveNode() throws KeeperException, InterruptedException {
        Stat stat = zooKeeper.exists(EXCLUSIVE_NODE_PATH, false);
        if (stat == null) {
            zooKeeper.create(EXCLUSIVE_NODE_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }

    public boolean tryAcquireExclusiveNode() throws KeeperException, InterruptedException {
        String nodePath = zooKeeper.create(EXCLUSIVE_NODE_PATH + "/lock", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

        // Get all children and check if this node has the smallest sequence number
        String[] children = zooKeeper.getChildren(EXCLUSIVE_NODE_PATH, false).toArray(new String[0]);
        String thisNode = nodePath.substring(nodePath.lastIndexOf("/") + 1);
        int thisNodeSequence = Integer.parseInt(thisNode.substring(thisNode.length() - 10));
        boolean isExclusiveNode = true;

        for (String child : children) {
            int childSequence = Integer.parseInt(child.substring(child.length() - 10));
            if (childSequence < thisNodeSequence) {
                isExclusiveNode = false;
                break;
            }
        }

        return isExclusiveNode;
    }

    public void doWorkAsLeader() throws InterruptedException {
        System.out.println("I am the leader! Performing leader-specific tasks...");

        // TODO: Execute leader-specific logic here

        // Sleep for a while to simulate leader work
        Thread.sleep(5000);
    }

    public void waitForLeader() throws KeeperException, InterruptedException {
        CountDownLatch latch = new CountDownLatch(1);

        while (true) {
            String[] children = zooKeeper.getChildren(EXCLUSIVE_NODE_PATH, new LeaderWatcher(latch));

            if (children.length == 0) {
                System.out.println("Waiting for the leader to establish...");
                latch.await();
            } else {
                System.out.println("Leader is already established. Starting as a follower...");
                break;
            }
        }
    }
}

4、法官判决

1. 设计Path
集群共用父节点 parent znode,集群中的每个节点在 parent 目录下创建自己的 znode。
2. 选择节点类型
当 Leader 节点挂掉的时候,持有最小编号 znode 的集群节点成为 “法官” ,因此用 ephemeral_sequential 类型
znode。
3. 设计节点数据
可以根据业务需要灵活写入各种数据,例如写入当前存储的最新的数据对应的事务 ID。
4. 设计Watch
1. 节点启动或者重连后,在 parent 目录下创建自己的 ephemeral_sequntial znode,并 watch
parent 目录;
2. 当 parent 目录有节点删除的时候,所有节点更新自己的 znode 里面和选举相关的数据;
3. “法官”节点读取所有 znode 的数据,根据规则或者算法选举新的 Leader,将选举结果写入 parent
znode;
4. 所有节点 watch parent znode,收到变更通知的时候读取 parent znode 的数据,发现是自己则成
为 Leader。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值