03_Zookeeper集群启动、API

复习环境变量

  • export A=1 定义的变量,会对自己所在的shell进程以及子进程生效
  • B=1 定义的变量,只对自己所在的shell进程生效
  • script.sh中定义的变量,在当前登录的shell进程中 source script.sh

启动zookeeper集群

  • 在mini1上启动mini2上的zookeeper
    ssh mini2 "source /etc/profile;/apps/zookeeper/zookeeper-3.4.5/zkServer.sh start"

  • 启动zookeeper集群中的所有zookeeper(mini1、mini2、mini3)的脚本
    startzk.sh

#!/bin/sh
echo "start zkServer..."
for i in 1 2 3
do
ssh mini$i "source /etc/profile;/apps/zookeeper/zookeeper-3.4.5/bin/zkServer.sh start"
done

Zookeeper-API

基本使用

org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话
它提供了表 1 所示几类主要方法 :

Zookeeper的增删改查

package cn.huachao.zookeeper01;

import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

public class TestZK {
    /**
     * 如果zookeeper集群的配置文件zoo.conf使用的mini1,则在此必须使用mini1
     */
    private static final String connectString = "mini1:2181,mini2:2181,mini3:2181";
    private static final int sessionTimeout = 2000;
    private ZooKeeper client = null;
    @Before
    public void init() throws Exception{
        client = new ZooKeeper(connectString , sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.getType() +" --> "+ event.getPath());
                try {
                    client.getChildren("/", true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    // 创建数据节点到zk中
    @Test
    public void save() throws Exception{
        /*
         *  参数1:要创建的节点的路径 
         *  参数2:节点大数据 
         *  参数3:节点的权限 
         *  参数4:节点的类型
         */
        //上传的数据可以是任何类型,但都要转成byte[]
        String res = client.create("/api", "this is my api".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        System.out.println("create-->"+res);
    }
    @Test
    public void exist() throws Exception{
        Stat stat = client.exists("/api", false);
        System.out.println(stat==null?"not exist":"exist");
    }
    // 获取子节点
    @Test
    public void getChildren() throws Exception {
        List<String> children = client.getChildren("/", true);
        for (String child : children) {
            System.out.println(child);
        }
        Thread.sleep(Long.MAX_VALUE);
    }
    //获取znode的数据
    @Test
    public void getData() throws Exception {
        byte[] data = client.getData("/api", false, null);
        System.out.println(new String(data));
    }
    //删除znode
    @Test
    public void deleteZnode() throws Exception {
        
        //参数2:指定要删除的版本,-1表示删除所有版本
        client.delete("/api", -1);
    }
    //删除znode
    @Test
    public void setData() throws Exception {
        
        client.setData("/app1", "imissyou angelababy".getBytes(), -1);
        
        byte[] data = client.getData("/api", false, null);
        System.out.println(new String(data));
        
    }
}

Zookeeper应用

实现分布式应用的(主节点HA)及客户端动态更新主节点状态

某分布式系统中,主节点可以有多台,可以动态上下线
任意一台客户端都能实时感知到主节点服务器的上下线

  • DistributedServer,服务端,连接zookeeper,注册server节点
package cn.huachao.zkdist;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;

public class DistributedServer {
    private static final String connectString = "mini1:2181,mini2:2181,mini3:2181";
    private static final int sessionTimeout = 2000;
    
    private static final String parentNode = "/servers";
    private ZooKeeper zkClient = null;
    
    /*
     * 创建zk客户端
     */
    public void getConnection() throws Exception{
        zkClient = new ZooKeeper(connectString , sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.getType() +" --> "+ event.getPath());
                try {
                    zkClient.getChildren("/", true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * 注册服务
     * @param hostname
     * @throws Exception
     */
    public void registerServer(String hostname) throws Exception{
        exist();
        String res = zkClient.create(parentNode+"/server", hostname.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(hostname+" is online..."+res);
    }
    /**
     * 根节点不在的,就创建
     * @throws Exception
     */
    @Test
    public void exist() throws Exception{
        Stat stat = zkClient.exists(parentNode, false);
        if(stat==null){
            zkClient.create(parentNode, "servers".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
    }
    
    /**
     * 业务处理
     * @param hostname
     * @throws Exception
     */
    public void handleBussiness(String hostname) throws Exception{
        System.out.println(hostname+" is working ...");
        Thread.sleep(Integer.MAX_VALUE);
    }
    public static void main(String[] args) throws Exception {
        String hostname = "mini2";
        DistributedServer server = new DistributedServer();
        server.getConnection();
        
        server.registerServer(hostname);
        
        server.handleBussiness(hostname);
    }
}
  • DistributeClient,客户端,连接zookeeper,查看服务节点,并监听节点变化
package cn.huachao.zkdist;

import java.util.ArrayList;
import java.util.List;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

public class DistributeClient {
    private static final String connectString = "mini1:2181,mini2:2181,mini3:2181";
    private static final int sessionTimeout = 2000;
    
    private volatile List<String> serverList;
    
    private static final String parentNode = "/servers";
    private ZooKeeper zkClient = null;
    /*
     * 创建zk客户端
     */
    public void getConnection() throws Exception{
        zkClient = new ZooKeeper(connectString , sessionTimeout, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.getType() +" --> "+ event.getPath());
                try {
                    getServerList();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    /**
     * 获取服务器信息列表
     * @throws Exception
     */
    public void getServerList() throws Exception{
        List<String> children = zkClient.getChildren(parentNode, true);
        List<String> servers = new ArrayList<>();
        for(String child : children){
            byte[] data = zkClient.getData(parentNode+"/"+child, false, null);
            String server = new String(data);
            servers.add(server);
            System.out.println(server);
        }
        serverList = servers;
    }
    /**
     * 业务功能
     * 
     * @throws InterruptedException
     */
    public void handleBussiness() throws InterruptedException {
        System.out.println("client start working.....");
        Thread.sleep(Long.MAX_VALUE);
    }
    public static void main(String[] args) throws Exception {
        DistributeClient client = new DistributeClient();
        client.getConnection();
        
        client.getServerList();
        client.handleBussiness();
    }
}

分布式共享锁的简单实现

分布式共享资源锁的需求及实现思路
package cn.huachao.zklock;

import java.util.Collections;
import java.util.List;
import java.util.Random;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class DistributedClientLock {
    // 会话超时
    private static final int SESSION_TIMEOUT = 2000;
    // zookeeper集群地址
    private String hosts = "mini1:2181,mini2:2181,mini3:2181";
    private String groupNode = "locks";
    private String subNode = "sub";
    private boolean haveLock = false;

    private ZooKeeper zk;
    // 记录自己创建的子节点路径
    private volatile String thisPath;

    /**
     * 连接zookeeper
     */
    public void connectZookeeper() throws Exception {
        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {
            public void process(WatchedEvent event) {
                try {

                    // 判断事件类型,此处只处理子节点变化事件
                    if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {
                        //获取子节点,并对父节点进行监听
                        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);
                        String thisNode = thisPath.substring(("/" + groupNode + "/").length());
                        // 去比较是否自己是最小id
                        Collections.sort(childrenNodes);
                        if (childrenNodes.indexOf(thisNode) == 0) {
                            //访问共享资源处理业务,并且在处理完成之后删除锁
                            doSomething();
                            
                            //重新注册一把新的锁
                            thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                                    CreateMode.EPHEMERAL_SEQUENTIAL);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 1、程序一进来就先注册一把锁到zk上
        thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);

        // wait一小会,便于观察
        Thread.sleep(new Random().nextInt(1000));

        // 从zk的锁父目录下,获取所有子节点,并且注册对父节点的监听
        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

        //如果争抢资源的程序就只有自己,则可以直接去访问共享资源 
        if (childrenNodes.size() == 1) {
            doSomething();
            thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
        }
    }

    /**
     * 处理业务逻辑,并且在最后释放锁
     */
    private void doSomething() throws Exception {
        try {
            System.out.println("gain lock: " + thisPath);
            Thread.sleep(2000);
            // do something
        } finally {
            System.out.println("finished: " + thisPath);
            // 
            zk.delete(this.thisPath, -1);
        }
    }

    public static void main(String[] args) throws Exception {
        DistributedClientLock dl = new DistributedClientLock();
        dl.connectZookeeper();
        Thread.sleep(Long.MAX_VALUE);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容