|NO.Z.00009|——————————|BigDataEnd|——|Hadoop&Zookeeper.V09|——|Zookeeper.v09|应用实践|服务器动态上下线.v01|

一、Zookeeper应用实践
### --- [zookeeper]

~~~     [zookeeper应用实践之服务器动态上下线监听]
~~~     [zookeeper应用实践之服务器动态上下线总结]
### --- Zookeeper实践

~~~     ZooKeeper是一个典型的发布/订阅模式的分布式数据管理与协调框架,
~~~     我们可以使用它来进行分布式数据的发布与订阅。
~~~     另一方面,通过对ZooKeeper中丰富的数据节点类型进行交叉使用,
~~~     配合Watcher事件通知机制,可以非常方便地构建一系列分布式应用中都会涉及的核心功能,
~~~     如数据发布/订阅、命名服务、集群管理、Master选举、分布式锁和分布式队列等。
~~~     那接下来就针对这些典型的分布式应用场景来做下介绍
### --- Zookeeper的两大特性:

~~~     # 客户端如果对Zookeeper的数据节点注册Watcher监听,
~~~     那么当该数据节点的内容或是其子节点列表发生变更时,
~~~     Zookeeper服务器就会向订阅的客户端发送变更通知。
~~~     # 对在Zookeeper上创建的临时节点,
~~~     一旦客户端与服务器之间的会话失效,那么临时节点也会被自动删除

~~~     # 利用其两大特性,
~~~     可以实现集群机器存活监控系统,
~~~     若监控系统在/clusterServers节点上注册一个Watcher监听,那么但凡进行动态添加机器的操作,
~~~     就会在/clusterServers节点下创建一个临时节点:/clusterServers/[Hostname],
~~~     这样,监控系统就能够实时监测机器的变动情况。
二、 服务器动态上下线监听
### --- 服务器动态上下线监听

~~~     # 思路分析
~~~     分布式系统中,主节点会有多台,主节点可能因为任何原因出现宕机或者下线,
~~~     而任意一台客户端都要能实时感知到主节点服务器的上下线。
### --- 具体实现:

~~~     # 服务端
package com.yanqi.zk.onoffline;

import org.I0Itec.zkclient.ZkClient;

//服务端主要提供了client需要的一个时间查询服务,服务端向zk建立临时节点
public class Server {

    //获取zkclient
    ZkClient zkClient = null;

    private void connectZk() {
        // 创建zkclient
        zkClient = new ZkClient("linux121:2181,linux122:2181");
        //创建服务端建立临时节点的目录
        if (!zkClient.exists("/servers")) {
            zkClient.createPersistent("/servers");
        }
    }

    //告知zk服务器相关信息
    private void saveServerInfo(String ip, String port) {
        final String sequencePath = zkClient.createEphemeralSequential("/servers/server", ip + ":" + port);
        System.out.println("----->>> ,服务器:" + ip + ":" + port + ",向zk保存信息成功,成功上线可以接受client查询");
    }

    public static void main(String[] args) {
        //准备两个服务端启动上线(多线程模拟,一个线程代表一个服务器)
        final Server server = new Server();
        server.connectZk();
        server.saveServerInfo(args[0], args[1]);
        //提供时间服务的线程没有启动,创建一个线程类,可以接收socket请求
        new TimeService(Integer.parseInt(args[1])).start();
    }
}
~~~     # 服务端提供时间查询的线程类

package com.yanqi.zk.onoffline;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

//提供时间查询服务
public class TimeService extends Thread {
    private int port = 0;

    public TimeService(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        //通过socket与client进行交流,启动serversocket监听请求
        try {
            //指定监听的端口
            final ServerSocket serverSocket = new ServerSocket(port);

            //保证服务端一直运行
            while (true) {
                final Socket socket = serverSocket.accept();
                //不关心client发送内容,server只考虑发送一个时间值
                final OutputStream out = socket.getOutputStream();
                out.write(new Date().toString().getBytes());
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
### --- client端

package com.yanqi.zk.onoffline;

import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

// 注册监听zk指定目录,
//维护自己本地一个servers信息,收到通知要进行更新
//发送时间查询请求并接受服务端返回的数据
public class Client {
    //获取zkclient
    ZkClient zkClient = null;

    //维护一个serversi 信息集合
    ArrayList<String> infos = new ArrayList<String>();

    private void connectZk() {
        // 创建zkclient
        zkClient = new ZkClient("linux121:2181,linux122:2181");
        //第一次获取服务器信息,所有的子节点
        final List<String> childs = zkClient.getChildren("/servers");
        for (String child : childs) {
            //存储着ip+port
            final Object o = zkClient.readData("/servers/" + child);
            infos.add(String.valueOf(o));
        }

        //对servers目录进行监听
        zkClient.subscribeChildChanges("/servers", new IZkChildListener() {
            public void handleChildChange(String s, List<String> children) throws Exception {
                //接收到通知,说明节点发生了变化,client需要更新infos集合中的数据
                ArrayList<String> list = new ArrayList<String>();
                //遍历更新过后的所有节点信息
                for (String path : children) {
                    final Object o = zkClient.readData("/servers/" + path);
                    list.add(String.valueOf(o));
                }

                //最新数据覆盖老数据
                infos = list;
                System.out.println("--》接收到通知,最新服务器信息为:" + infos);
            }
        });
    }

    //发送时间查询的请求
    public void sendRequest() throws IOException {
        //目标服务器地址
        final Random random = new Random();
        final int i = random.nextInt(infos.size());
        final String ipPort = infos.get(i);
        final String[] arr = ipPort.split(":");

        //建立socket连接

        final Socket socket = new Socket(arr[0], Integer.parseInt(arr[1]));
        final OutputStream out = socket.getOutputStream();
        final InputStream in = socket.getInputStream();
        //发送数据
        out.write("query time".getBytes());
        out.flush();
        //接收返回结果
        final byte[] b = new byte[1024];
        in.read(b);//读取服务端返回数据
        System.out.println("client端接收到server:+" + ipPort + "+返回结果:" + new String(b));


        //释放资源
        in.close();
        out.close();
        socket.close();
    }

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

        final Client client = new Client();
        client.connectZk();   //监听器逻辑
        while (true) {
            try {
                client.sendRequest(); //发送请求
            } catch (IOException e) {
                e.printStackTrace();
                try {
                    client.sendRequest();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            //每隔几秒中发送一次请求到服务端
            Thread.sleep(2000);
        }
    }
}

 
 
 
 
 
 
 
 
 

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
                                                                                                                                                   ——W.S.Landor

 

 

posted on   yanqi_vip  阅读(6)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示