Zookeeper-【1】初体验--通过Curator实现业务HA

言于头: 前几天在学习Flink的时候,看到了flink利用zookeeper实现jobmanager的高可用,所以下来我就在思考,我们得业务是否也可以利用这个来提高核心功能的稳定性呢?想到平常接触到的kfk集群啥的,在加上在网上找的相关资料,所以本次尝试利用zk的封装模块Curator来实现业务的HA。下面为本次记录过程。

1 下载Zookeeper

下载地址:http://archive.apache.org/dist/zookeeper/,本次选择版本 apache-zookeeper-3.6.0-bin.tar.gz (如图)。
在这里插入图片描述

2 安装Zookeeper

将下载后的apache-zookeeper-3.6.0-bin.tar.gz放到服务器上相关目录
执行解压:
$ tar zxvf apache-zookeeper-3.6.0-bin.tar.gz
解压后进入,创建数据目录
$ cd apache-zookeeper-3.6.0-bin
$ mkdir data
进入配置文件目录,复制一个配置文件
$ cp zoo_sample.cfg zoo.cfg
修改配置文件 (修改部分如图)
$ vim zoo.cfg
修改完毕退回上层启动zookeeper
$ ./bin/zkServer.sh start

修改配置截图:

在这里插入图片描述

启动Zookeeper截图:

在这里插入图片描述

启动Zookeeper后状态检查截图: 执行状态查询命令显示如下则启动成功.

在这里插入图片描述

3 通过Curator实现业务HA
3.1 环境准备

1.项目结构如下所示,所需jar可在仓库https://search.maven.org/ 里面下载,主要为Zookeeper相关三个jar(可在上述安装包lib中获取)、Curator所需的jar、日志以及单元测试jar。
2.代码部分为一个业务集成类 + 单元测试类(模拟多机部署)。
3.此处的HA实现是使用Curator的LeaderLatch类,听说它还有LeaderSelector类可实现。两者区别为:LeaderLatch是一旦选举出Leader,除非有客户端挂掉重新触发选举,否则不会交出领导权,而LeaderSelector是所有存活的客户端不间断的轮流做Leader,机会均等。

在这里插入图片描述

3.2 BKZkLeaderLatch类实现
package com.bkdemo.zk;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.leader.LeaderLatch;
import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;

/**
 * @Description
 * @date: 2020/11/27 14:54
 */
public class BKZkLeaderLatch {
    private static final Logger logger = LoggerFactory.getLogger(BKZkLeaderLatch.class);
    private static final Integer INT_3=3;
    private static final Integer INT_1000=1000;
    private static final Integer INT_6000=6000;
    private  CuratorFramework zkClient;
    private  LeaderLatch leaderLatch;
    private String connectString;
    private String masterKey;
    private String zkId;
    /**
 	* @Description
 	* connectString:zk连接串
 	* masterKey:节点目录,多机部署时此处需要相同
 	* zkId:机器ID
	* @date: 2020/11/27 14:54
 	*/
    public BKZkLeaderLatch(String connectString, String masterKey, String zkId) {
        this.connectString = connectString;
        this.masterKey = masterKey;
        this.zkId = zkId;
    }
    public void start() {
        try {
            String id = String.format("BKZkLeaderLatch#%s-#%s", InetAddress.getLocalHost().getHostAddress(), zkId);
            logger.info("zk {} 客户端初始化... server:{}, masterKey:{}",id,connectString,masterKey);
            RetryPolicy retryPolicy = new ExponentialBackoffRetry(INT_1000, INT_3);
            zkClient = CuratorFrameworkFactory.builder().connectString(connectString)
                    .sessionTimeoutMs(INT_6000).retryPolicy(retryPolicy).build();
            logger.info("zk 客户端启动....");
            zkClient.start();
            leaderLatch = new LeaderLatch(zkClient, masterKey,id);
            LeaderLatchListener leaderLatchListener = new LeaderLatchListener() {
                @Override
                public void notLeader() {
                    logger.info("客户端: {} 不是主节点. ",id);
                }
                @Override
                public void isLeader() {
                    logger.info("客户端: {} 成为主节点. YEAH!",id);
                }
            };
            leaderLatch.addListener(leaderLatchListener);
            logger.info("leaderLatch启动....");
            leaderLatch.start();
            // 设置数据标志(无具体作用、只为了测试其API)
            zkClient.setData().forPath(masterKey,id.getBytes());
        } catch(Exception e) {
            logger.error("客户端初始化异常. "+e.getMessage(),e);
        }
    }
    /**
 	* @Description 确认当前是否是Leader
	* @date: 2020/11/27 14:54
 	*/
    public boolean isLeader() {
        return leaderLatch.hasLeadership();
    }
    public CuratorFramework getClient(){
        return zkClient;
    }
    public LeaderLatch getLatch(){
        return leaderLatch;
    }
}
3.3 ZKTestHA类实现
package com.bkdemo.zk;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * @Description 测试利用zk实现高可用样例 主从选择
 * @date: 2020/11/27 14:35
 */
public class ZKTestHA {
    private static final Logger LOGGER = LoggerFactory.getLogger(ZKTestHA.class);
    // ZK地址
    private static  final String ZK_CONNECT_STR="24.**.**.66:2181";
    // 存储路径
    private static  final String ZK_MASTER_PATH="/ZKTestHA01";
    @Test
    public void testZkInstantce1() throws Exception{
        BKZkLeaderLatch bkZkLeaderLatch = new BKZkLeaderLatch(ZK_CONNECT_STR, ZK_MASTER_PATH, "1");
        bkZkLeaderLatch.start();
        while (true){
            Thread.sleep(1000l);
        }
    }
    @Test
    public void testZkInstantce2() throws Exception{
        BKZkLeaderLatch bkZkLeaderLatch = new BKZkLeaderLatch(ZK_CONNECT_STR, ZK_MASTER_PATH, "2");
        bkZkLeaderLatch.start();
        while (true){
            Thread.sleep(1000l);
        }
    }
    @Test
    public void testZkInstantce3() throws Exception{
        BKZkLeaderLatch bkZkLeaderLatch = new BKZkLeaderLatch(ZK_CONNECT_STR, ZK_MASTER_PATH, "3");
        bkZkLeaderLatch.start();
        while (true){
            Thread.sleep(1000l);
        }
    }
}
3.4 启动结果

启动 ZKTestHA 类里面的单元测试后可以在服务器上的zk安装目录下执行相关命令观察到我们保存的节点信息 /ZKTestHA01(如图)。
登录zk
$ ./bin/zkCli.sh -server 24.X.X.66:2181

在这里插入图片描述

在单元测试 ZKTestHA类启动三个后,可以在 /ZKTestHA01节点下看到三个子节点,这代表着有三个客户端共同使用该节点,并且观察每个节点里面的数据就是我们在BKZkLeaderLatch 中设置的值(如图)。

在这里插入图片描述
在这里插入图片描述

在单元测试 ZKTestHA类关闭1节点后,可以发现日志显示重新选择了3节点作为Leader(3.1中日志显示1节点最初为Leader),并且在服务器上看到的节点信息会相应的减少1节点(如图),表明此时在程序崩溃后ZK重新选择了Leader。

在这里插入图片描述
在这里插入图片描述

尽于尾:最后,本次测试基本完毕,但是却有一个小疑问:上述单元测试在全部停止后一段时间(据观察是将近5、6秒左右)在服务器上查看相关节点信息就全部没有了,查询资料显示Zookeeper的节点创建模式分为四种:
1.PERSISTENT:持久化
2.PERSISTENT_SEQUENTIAL:持久化并且带序列号
3.EPHEMERAL:临时
4.EPHEMERAL_SEQUENTIAL:临时并且带序列号

那么此处通过LeaderLatch创建的节点属于哪一类呢?是临时么?

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值