• (35)分布式应用系统服务器上下线动态感知程序开发


    实现思路:

    一个应用系统中,对外提供服务的服务器有多台,而服务器的数量动态地变化。

    客户端每次只能请求一个服务器,因此服务器的变化(上下线)必须通知到客户端,客户端必须知道当前哪些服务器在,哪些服务器不在。

    实现方法:

    利用zookeeper集群。

    服务器方面:服务器启动时到zookeeper上去注册,注册的节点必须为临时节点,因为产生临时节点的客户端一旦断开连接就会被zookeeper自动删除,进而产生事件被客户端感知。

    客户端方面:客户端启动后,调用getChildren('/servers/', watch) 获取有哪些机器在线,选择连接数最小的服务器进行连接(做到负载均衡),并且注册监听,一旦有服务器宕机或上线,就会通知到客户端,客户端调用process()函数进行响应(重新获取服务器列表并注册监听)。

    具体代码:

    1.分布式系统的服务器

    import org.apache.zookeeper.ZooKeeper;

    public class DistributedServer{

           private static final String connectString="192.168.179.200:2181,192.168.179.201:2181,192.168.179.202:2181";

           private static final int sessionTimeout = 2000;

           private ZooKeeper zk = null;

           private static final String parentNode = "/servers";

           // 创建到zk的客户端连接

           public void getConnect() throws Exception{

                   

                         zk = new ZooKeeper(connectString,sessionTimeout,new Watcher() {

                         @Override
                         public void process(WatchedEvent event) {

                                // 收到事件通知后的回调函数(事件处理逻辑)
                               System.out.println(event.getType() + "---" + event.getPath());

                               try {

                                    zk.getChildren("/", true);    //再次绑定监听器,因为监听器只生效一次。这样做可以实现永久的监听
                               } catch (Exception e) {
                               }


                         }

                  });

           } 

           // 向zk集群注册服务器信息

           public void registerServer(String hostname) throws Exception{

                  String create = zk.create(parentNode + "/server",  hostname.getBytes() , Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

                  System.out.println(hostname + "is online.." + create);

           }

           // 业务功能

           public void handleBusiness() throws InterruptedException{

                 Thread.sleep(Long.MAX_VALUE);

           }

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

                  // 获取zk连接

                  DistributedServer server = new DistributedServer();

                  server.getConnect();

                 // 利用zk连接注册服务器信息

          server.registerServer(args[0]);

                 // 启动业务功能

                 server.handleBusiness();

           }

    }

     2.分布式系统的客户端

    public class DistributedClient{  

           private static final String connectString="192.168.179.200:2181,192.168.179.201:2181,192.168.179.202:2181";

           private static final int sessionTimeout = 2000;

           private volatile List<String> serverList;

           private ZooKeeper zk = null;

           private static final String parentNode = "/servers";

           // 创建到zk的客户端连接

           public void getConnect() throws Exception{

                   

                         zk = new ZooKeeper(connectString,sessionTimeout,new Watcher() {

                         @Override
                         public void process(WatchedEvent event) {

                                // 收到事件通知后的回调函数(事件处理逻辑)

                               try {

                                     getServerList();   // 更新服务器列表,并且注册了监听
                               } catch (Exception e) {
                               }


                         }

                  });

           }  

           // 获取服务器信息列表

           public void getServerList() throws Exception{

                  //获取服务器子节点信息,并对父节点进行监听

                  List<String> children = zk.getChildren(parentNode, true);

                  //先创建一个局部的list来存服务器信息

                  List<String> servers = new ArrayList<String>();

                  for(String child:children){

                         byte[] data = zk.getData(parentNode+"/"+child, false, null);

                         servers.add(new String(data));

                  }

                  // 把servers赋值给成员变量serverList,提供给各业务线程使用

                  serveList = servers;

           }

         

           // 业务功能

           public void handleBusiness() throws InterruptedException{

                 Thread.sleep(Long.MAX_VALUE);

           }

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

                  // 获取zk连接

                  DistributedClient client = new DistributedClient();

                   client.getConnect();

                  // 获取servers的子节点信息(并监听),从中获取服务器信息列表

                   client.getServerList();

                  // 业务线程启动

                   client.handleBusiness();

           }

    }

    补充:volatile关键字

    对象serverList在java的堆内存中。

    java程序中有多个线程,每个线程有自己的工作栈空间,若多个线程都要对serverList对象进行修改操作,它们在使用对象serverList时,会对serverList中自己要操作的数据拷贝一个副本到自己的工作栈中,对副本进行相应操作,再把更改后的副本同步到堆内存的serverList对象上。这样可能会导致各个线程所看到的serverList对象是不同的。

    如果给对象添加了volatile关键字,则对象不会再被拷贝到线程的工作栈中了,所有线程访问的都是该对象本身,且一个线程对对象操作完成之后才允许下一个线程进行操作。因此每个线程所观察到的serverList对象是同一个版本,这样就保证了该对象在所有线程上的一致性。

    效果测试:

    1.将DistributedServer.java和DistributedClient.java打成jar包:

    找到以上文件所在的包,右击 - Export - Runnable JAR file - Launch configuration(DistributedServer/DistributedClient) - Export destination(C:server.jar) - finish

    2.运行jar包:

    进入jar包所在的目录 , 运行命令  java -jar server.jar (main方法的参数)

  • 相关阅读:
    sqlalchemy的orm的高级用法,分组,排序,聚合等方法
    flask的SQLAlchemy,连接数据库的增删改查操作
    wtforms的form表单的高级用法
    初始wtforms表单,以及简单使用
    命令启动flask以及自定义命令
    MySQL5.5安装教程
    Java设计模式-策略模式实际应用场景
    Java设计模式-策略模式详解
    Oracle数据库之FORALL与BULK COLLECT语句
    代理模式详解(静态代理和动态代理的区别以及联系)
  • 原文地址:https://www.cnblogs.com/paradis/p/11397780.html
Copyright © 2020-2023  润新知