100303- ZooKeeper 配置管理代码实现案例

ZooKeeper配置管理实战
本文介绍使用ZooKeeper进行配置管理的方法,包括配置信息的存储、变更通知及客户端自动同步更新等关键环节。
一、ZooKeeper的配置管理( Configuration Management)使用场景
配置的管理在分布式应用环境中很常见,例如同一个应用系统需要多台 PC Server 运行,但是它们运行的应用系统的某些配置项是相同的,如果要修改这些相同的配置项,那么就必须同时修改每台运行这个应用系统的 PC Server,这样非常麻烦而且容易出错。像这样的配置信息完全可以交给 Zookeeper 来管理,将配置信息保存在 Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化每台应用机器就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中。



二、配置管理结构图

三、实战案例 
3.1 工作中有这样的一个场景:  数据库用户名和密码信息放在一个配置文件中,应用读取该配置文件,配置文件信息放入缓存。
若数据库的用户名和密码改变时候,还需要重新加载缓存,比较麻烦,通过ZooKeeper可以轻松完成,当数据库发生变化时自动完成
缓存同步
3.2 模拟程序代码
创建SetConfig.java 写配置文件
创建MyClient.java 读取配置文件和注册watcher到zk上
package example;

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

/**
 * <p>
 * write data to zookeeper
 * </p>
 *
 * @author shenfl
 *
 */
public class SetConfig {
     // zk的连接串
     private final static String CONNECT_STR = "192.168.2.35:2181" ;

     // 连接zk的超时时间
     private static final int SESSION_TIMEOUT = 30000;

     // 数据库连接
     private final static String uRLNode = "10.12.1.1";
     private final static String userNameNode = "admin";
     private final static String passwdNode = "admin123";

     // Auth认证
     public static String authType = "digest" ;
     public static String authPasswd = "*ik1234" ;
     
     public static void main(String[] args) {
           try {
              ZooKeeper zk = new ZooKeeper(CONNECT_STR, SESSION_TIMEOUT , new Watcher() {
                    @Override
                    public void process(WatchedEvent e) {
                        System. out.println(" type : " + e.getType() + ",path:" + e .getPath());
                   }
              });

               zk.addAuthInfo( authType, authPasswd.getBytes());
              
               if(zk .exists("/jfconf" , true)==null){
                    zk.create( "/jfconf", uRLNode.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT );
              }
               if (zk .exists("/jfconf/uRLNode" , true) == null) {
                    zk.create( "/jfconf/uRLNode", uRLNode.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT );

              }
               if (zk .exists("/jfconf/userNameNode" , true) == null) {
                    zk.create( "/jfconf/userNameNode", userNameNode .getBytes(), Ids.OPEN_ACL_UNSAFE,
                             CreateMode. PERSISTENT);
              }
               if (zk .exists("/jfconf/passwdNode" , true) == null) {
                    zk.create( "/jfconf/passwdNode", passwdNode.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT );
              }
               zk.close();
          } catch (Exception e ) {
               e.printStackTrace();
          }
     }
}

package example;

import java.io.IOException;

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

/**
 * <p>
 * 创建属于自己的Watcher,该Watcher监控 zk上的/jfconf 节点, 当该节点下的文件发生变化重新加载缓存
 * </p>
 *
 * <p>
 * ZooKeeper通过 Auth和ACL完成节点的权限控制
 * </p>
 *
 * <p>
 * Auth表示某种认证,由于一个ZooKeeper集群可能被多个项目使用,各个项目属于不同的项目组,
 * 他们在进行开发时肯定不想其他项目访问与自己相关的节点,这时可以通过为每个项目组分配一个 Auth
 * 然后每个项目组先通过 Auth认证以后再继续相关的操作,这样甲 Auth认证的用户就不能操作其他
 * Auth认证后创建的节点,从而实现各个项目之间的隔离。ZooKeeper提供了如下方法完成认证
 * </p>
 *
 *
 * @author shenfl
 *
 */
public class MyClient implements Watcher {

     // zk的连接串
     private final static String CONNECT_STR = "192.168.2.35:2181" ;
     // 连接zk的超时时间
     private static final int SESSION_TIMEOUT = 30000;

     // client获取的数据库信息
     private String uRL;
     private String userName;
     private String passwd;

     // Auth认证
     public static String authType = "digest" ;
     public static String authPasswd = "*ik1234" ;

     public MyClient() {
          initValue();
     }

     public static void main(String[] args) {
          MyClient client = new MyClient();
           int i = 0;
           try {
              ZooKeeper zk = null;
               // 连接zk
               zk = new ZooKeeper(CONNECT_STR, SESSION_TIMEOUT , client );
               // 判断权限是否能访问/ jfconf目录
                zk.addAuthInfo( authType,authPasswd .getBytes());

               while (true ) {
                   System. out.println("url[" + i + "]=" + client.getuRL());
                   System. out.println("userName[" + i + "]=" + client .getUserName());
                   System. out.println("passwd[" + i + "]=" + client .getPasswd());
                   Thread. sleep(10 * 1000);
                    i++;
                    if (i == 10) {
                         break;
                   }
              }
               zk.close();
          } catch (Exception e ) {
               e.printStackTrace();
          }

     }

     /**
      * 获取 zk中相关信息
      *
      * @throws Exception
      */
     private void initValue() {
           try {
              ZooKeeper zk = getZk();
              
               /**
               * return true: znode happened changed,uRL update.
               */
               this.uRL = new String(zk.getData("/jfconf/uRLNode" , true, null));
               this.userName = new String(zk.getData("/jfconf/userNameNode" , true, null));
               this.passwd = new String(zk.getData("/jfconf/passwdNode" , true, null));
          } catch (Exception e ) {
               e.printStackTrace();
          }
     }

     /**
      * 获取 zk连接
      *
      * @return
      * @throws IOException
      */
     public ZooKeeper getZk() {
          ZooKeeper zk = null;
           try {
               zk = new ZooKeeper(CONNECT_STR, SESSION_TIMEOUT , this);
          } catch (IOException e ) {
               e.printStackTrace();
          }
           // 判断权限是否能访问/ jfconf目录
           zk.addAuthInfo( authType,authPasswd .getBytes());
           return zk ;
     }

     /**
      * <p>
      * 如何服务器中的配置信息发生变化,通知process方法,把 zk中的数据重新获取,然后放到缓存中
      * </p>
      */
     @Override
     public void process(WatchedEvent event ) {
          String message = "";
          EventType type = event.getType();
           if (type .equals(Watcher.Event.EventType.None)) {
               message = "connect zk sucess!!!";
          } else if (type.equals(Watcher.Event.EventType.NodeCreated)) {
               message = "znode create sucess!!!";
          } else if (type.equals(Watcher.Event.EventType.NodeChildrenChanged)) {
               message = "child of znode create sucess!!!";
          } else if (type.equals(Watcher.Event.EventType.NodeDataChanged)) {
               message = "znode update success!!!,reload db's information";
              initValue();
          } else if (type.equals(Watcher.Event.EventType.NodeDeleted)) {
               message = "znode delete success!!!";
          }
          System. out.println(message );
     }

     public String getuRL() {
           return uRL ;
     }

     public void setuRL(String uRL ) {
           this.uRL = uRL ;
     }

     public String getUserName() {
           return userName ;
     }

     public void setUserName(String userName ) {
           this.userName = userName ;
     }

     public String getPasswd() {
           return passwd ;
     }

     public void setPasswd(String passwd ) {
           this.passwd = passwd ;
     }
}


3.3 验证Watcher
通过run as 运行MyClient.java,并查看结果
connect zk sucess!!!
url[0]=10.12.1.1
userName[0]=admin
passwd[0]=admin123
url[1]=10.12.1.1
userName[1]=admin
passwd[1]=admin123
url[2]=10.12.1.1
userName[2]=admin
passwd[2]=admin123
connect zk sucess!!!
url[3]=10.12.1.1
userName[3]=admin
passwd[3]=admin123
connect zk sucess!!!

然后修改/jfconf/userNameNode下的数据,再次检查结果
znode update success!!!,reload db's information
url[4]=10.12.1.1
userName[4]=adminadmin
passwd[4]=admin123
url[5]=10.12.1.1
userName[5]=adminadmin
passwd[5]=admin123
url[6]=10.12.1.1
userName[6]=adminadmin
passwd[6]=admin123
url[7]=10.12.1.1
userName[7]=adminadmin
passwd[7]=admin123
url[8]=10.12.1.1
userName[8]=adminadmin
passwd[8]=admin123
url[9]=10.12.1.1
userName[9]=adminadmin
passwd[9]=admin123

总结: 创建一个Watcher,然后注册到zk上,通过下面的代码完成注册
zk = new ZooKeeper( CONNECT_STR , SESSION_TIMEOUT, client);


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾文教编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值