Zookeeper动态更新服务器列表

--------------------------------------------------------------------------------------

[版权申明:本文系作者原创,转载请注明出处]

文章出处:http://www.cnblogs.com/sdksdk0/p/5585192.html

作者: 朱培              ID:sdksdk0

-----------------------------------------------------------------------------------

今天分享的是大数据实践的zookeeper。

zookeeper内部就是一个集群,主节点是选举出来的,外部看起来就像只有一台一样,保存的是一份状态数据。 做分布式应用协调的时候,可以降低开发难度。

具有高可用性,松耦合交互方式。

关于zookeeper的配置可以查看我的文章:http://blog.csdn.net/sdksdk0/article/details/51517460,在这里不再重复讲解安装配置。

一、zookeeper的API接口

String create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
Stat exists(String path, boolean watch)
void delete(String path, int version)
List<String> getChildren(String path, boolean watch)
List<String> getChildren(String path, boolean watch)
Stat setData(String path, byte[] data, int version)
byte[] getData(String path, boolean watch, Stat stat)
void addAuthInfo(String scheme, byte[] auth)
Stat setACL(String path, List<ACL> acl, int version)
List<ACL> getACL(String path, Stat stat)

zookeeper一般来说保管的数据不超过1M.主要是保存一些配置信息,主要特点是监听数据实时更新。

二、主要应用

1、集群管理:规定编号最小的为master,所以当我们对SERVERS节点做监控的时候,得到服务器列表,只要所有集群机器逻辑认为最小编号节点为master,那么master就被选出,而这个master宕机的时候,相应的znode会消失,然后新的服务器列表就被推送到客户端,然后每个节点逻辑认为最小编号节点为master,这样就做到动态master选举。

2、配置的管理:在分布式应用环境中很常见,例如同一个应用系统需要多台 PC Server 运行,但是它们运行的应用系统的某些配置项是相同的,如果要修改这些相同的配置项,那么就必须同时修改每台运行这个应用系统的 PC Server,这样非常麻烦而且容易出错。 将配置信息保存在 Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中。

3、共享锁:在同一个进程中很容易实现,但是在跨进程或者在不同 Server 之间就不好实现了。Zookeeper 却很容易实现这个功能,实现方式也是需要获得锁的 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,然后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是不是就是自己创建的目录节点,如果正是自己创建的,那么它就获得了这个锁,如果不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到自己创建的节点是列表中最小编号的目录节点,从而获得锁,释放锁很简单,只要删除前面它自己所创建的目录节点就行了。

4、队列管理:Zookeeper 可以处理两种类型的队列:当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列;队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型

三、使用eclipse连接zookeeper

在eclipse中,我们可以导入需要的包,然后对节点进行增删改查操作。 当连接的时候可以这样,这里我是采用了3台zookeeper来进行操作的。ubuntu1,2,3都分别是主机名

ZooKeeper zk = null;

@Before
public void init() throws Exception{

    zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() {

        //监听事件发生时的回调方法
        @Override
        public void process(WatchedEvent event) {
            System.out.println(event.getPath());
            System.out.println(event.getType());
        }
    });

}

创建节点: 这里我是采用创建一个永久节点,在zookeeper节点中有临时节点和永久节点之分。在跟目录下创建一个eclipse节点,内容的编码格式是utf-8,Ids是指权限控制,我这里采用的是开放ACL权限控制。最后需要把流关闭。

@Test
public void testZkNode() throws Exception {

    String path = zk.create("/eclipse", "指令汇科技".getBytes("utf-8"), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    System.out.println("创建了一个永久节点: " + path);
    zk.close();

}

然后是注册监听器,毕竟zookeeper有一个很重要的功能就是是用来监听整个服务的状态。

@Test
public void testGet() throws Exception {

    //监听器的注册只能生效一次
    byte[] data = zk.getData("/eclipse", true, new Stat());
    System.out.println(new String(data,"utf-8"));
    Thread.sleep(Long.MAX_VALUE);

}

在main方法中调用执行。

@Test
public void testSet() throws UnsupportedEncodingException, KeeperException, InterruptedException{

    zk.setData("/eclipse", "谁是英雄".getBytes("utf-8"), -1);
    zk.close();

}

四、动态服务器

因为我主要分享的是如何在客户端上动态的监听服务器的上线和离线,所以我们先来写一个服务器的进程。

首先我们需要把后面需要的节点信息定义一下,先去zookeeper的客户端上面运行一下,创建一个grpnode节点,以便我们的后续操作。

private ZooKeeper zk;
private String groupNode = "grpnode";
private String subNode = "sub";

// 向zookeeper注册信息
public void connectZK(String name) throws KeeperException, InterruptedException, IOException {
    zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() {

                //监听事件发生时的回调方法
                @Override
                public void process(WatchedEvent event) {

                }
            });
    String path = zk.create("/" + groupNode + "/" + subNode, name.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    System.out.println("服务器上线,创建了一个子节点: " + path);

}

接下来就是zookeeper默认的业务逻辑的处理,最后在主方法中调用。当然也可以把这个打成一个jar包放到hadoop上面去运行。

// 业务处理逻辑
public void handle() throws Exception {

    Thread.sleep(Long.MAX_VALUE);

}

public static void main(String[] args) throws Exception {

    if(args.length==0){
        System.err.println("参数个数不对,请附加服务器名作为参数来启动.....");
        System.exit(1);
    }
    // 去向zookeeper注册本服务器信息
    AppServer server = new AppServer();
    server.connectZK(args[0]);
    server.handle();

}

五、动态客户端

服务器写好之后,我们就需要一个客户端来监听这个服务器的上下线操作了。同样使用一个zookeeper的监听回调方法。一旦服务器发生变化,这里就可以动态监听到。主要是监听父子节点的变化情况。

private  volatile   List<String>  servers;
private ZooKeeper zk;
//使用zk的监听器功能触发服务器更新的动作
public void connectZK() throws IOException, KeeperException, InterruptedException{

    zk = new ZooKeeper("ubuntu2:2181,ubuntu1:2181,ubuntu3:2181", 5000, new Watcher() {

                //监听事件发生时的回调方法
                @Override
                public void process(WatchedEvent event) {

                    if("/grpnode".equals(event.getPath()) && event.getType()==EventType.NodeChildrenChanged ){
                    //触发更新服务器列表的动作
                    try {
                        updateServerList();
                    } catch (Exception e) {
                        e.printStackTrace();
                    } 

                    }
                }
            });
            updateServerList();
        }

动态获取服务器列表,这里主要就是监听父子节点的变化。

//动态获取服务器列表
public void updateServerList() throws KeeperException, InterruptedException, UnsupportedEncodingException{
    ArrayList<String>  serverList=new ArrayList<String>();

    //监听子节点,并且对父节点注册监听器
    List<String>  childer=zk.getChildren("/grpnode", true);

    //遍历子节点
    for(String child:childer){
        byte[] data=zk.getData("/grpnode/"+child,false, new Stat());
        String server=new String(data,"utf-8");
        //将获取到的服务器名称存入list
        serverList.add(server);
    }
    //把暂存的list放到全局的list中
    servers=serverList;
    System.out.println("最新的在线服务器是:"+serverList);
}

最后就是我们最熟悉的main方法了

//客户端的业务功能
public void handle() throws InterruptedException{

    Thread.sleep(Long.MAX_VALUE);
}

public static void main(String[] args) throws IOException, InterruptedException, KeeperException{

    AppClient client=new AppClient();
    client.connectZK();
    client.handle();

}

在hadoop中运行结果如下:

总结:Zookeeper 作为 Hadoop 项目中的一个子项目,是 Hadoop 集群管理的一个必不可少的模块,它主要用来控制集群中的数据,如它管理 Hadoop 集群中的 NameNode,还有 Hbase 中 Master Election、Server 之间状态同步等。 Zoopkeeper 提供了一套很好的分布式集群管理的机制,就是它这种基于层次型的目录树的数据结构,并对树中的节点进行有效管理,从而可以设计出多种多样的分布式的数据管理模型。

时间: 2024-10-15 16:08:05

Zookeeper动态更新服务器列表的相关文章

新品【国内动态】服务器列表

北京联通① bj1.1100.pro北京联通② bj2.1100.pro 上海市联通① shlt1.1100.pro上海市联通② shlt2.1100.pro 重庆市电信① cq2.1100.pro重庆市电信② cq3.1100.pro 广东省混播 60.190.114.212 广东省广东湛江电信① gdzj1.1100.pro广东湛江电信② gdzj2.1100.pro广东江门电信① gdjm1.1100.pro广东江门电信② gdjm2.1100.pro广东珠海电信① gdzh1.1100.

【国内动态】服务器列表

北京联通:bjlt01.adslip.cc北京联通:bjlt02.adslip.cc 上海电信:sh01.adslip.cc上海电信:sh02.adslip.cc 广州电信:gz01.adslip.cc广东阳江电信:yjdx.adslip.cc广东东莞电信:dgdx.adslip.cc广东河源电信:hydx.adslip.cc广东深圳电信:sz01.adslip.cc广东惠州电信:hzdx.adslip.cc广东佛山电信:fs01.adslip.cc广东湛江电信:zj01.adslip.cc广东

ZooKeeper动态增加Server(动态增加节点)的研究(待实践)

说明:是动态增加Server,不是动态增加连接到ZK Server的Client. 场景如下(转自外文): 1.在t=t_1->[peer-1(Leader),peer-2],peer-1是主节点,所有客户端连接到该节点. 2.在t=t_2->[peer-1(Leader),peer-2,peer-3],稍后的时候,同行3加入了该组.是否可以“动态地”将动态列表添加到zookeeper服务器列表(即,在对等体1上不重新启动ZooKeeper)? 3.在t=t_3->[peer-3(Lea

手游的一些事儿 - 动态更新

标题本来想叫"手游那些事儿",想了想还是算了,不想盗用"明朝那些事儿" 的"招牌"(其实还是有盗用的嫌疑,哈哈).   为了抹掉打广告的嫌疑,这里暂以已经比较火的或者腾讯出品的游戏举例(外加吐槽) 腾讯的<游龙英雄> 游久的<酷酷爱魔兽> 腾讯的<怪物弹珠>   目前国内手游2d开发以cocos2d-x js/lua为主流,3d多使用unity3d,类似网易这种做过端游的游戏厂商则倾向于使用在端游已经成熟的引擎

iOS 程序插件及功能动态更新思路

所用框架及语言 iOS客户端-Wax(开发愤怒的小鸟的连接Lua 和 Objc的框架),Lua,Objc, 服务端-Java(用于返回插件页面) 工具框架链接地址:Wax - https://github.com/probablycorey/wax  Netty - https://netty.io/  用做Http服务器,返回页面 由于Lua脚本语言,不需要编译即可运行,这点是我的这个思路可以执行的大前提,再加上苹果允许像Lua这样的脚本的存在,这一思路才能得以实现.个人感觉这一思路有点类似于

iOS 动态更新

iOS 动态更新 App 动态更新 1.控件到 window 的层级关系: 2.分析控件的详细路径: 3.动态修改控件: 4.工具篇: 视图的层级关系: 每个 App , 至少有一个根 Window , 通常情况下我们只用一个 .window 有一个 rootViewController , 这就是我们所谓的根视图 , 我们所有的控制器都是放在 rootViewController 里面的. 这个是最简单的层级关系 如果在项目里有了这么一个路径 , 我们可以做什么呢? 在当项目很复杂 , 可以其

ajax动态更新下拉列表

前面做了一个ajax的小demo,今天看一个动态更新下拉列表,或者也叫级联更新下拉列表,这个也是利用ajax的异步调用去后台实现数据请求,然后回到前台完成下拉列表数据的更新,以增强web应用的交互性. 后台servlet package com.ajax; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annot

定时动态更新图表

在进行实现动态更新图表时主要使用AJAX技术,主要分两种实现方法,一种是通过ASP.NET特有的AJAX控件,UpdatePanel.Timer控件+ASP.NET自带的Chart控件实现:另一种为使用第三方的图表库+JQUERY\AJAX实现. ASP.NET控件实现 实现: 前台将要定时刷新的内容放到updatePanel中即可,前台代码如下: <form id="form1" runat="server"> <asp:ScriptManage

android中实现service动态更新UI界面

案例:通过service向远程服务器发送请求,根据服务器返回的结果动态更新主程序UI界面,主程序可实时关闭或重启服务. 注册BroadcastReceiver 在主程序activity中注册一个BroadcastReceiver,用于接收Service发布的广播. @Override protected void onStart() {//重写onStart方法 dataReceiver = new DataReceiver(); IntentFilter filter = new Intent