目录
一、概述
在分布式系统中,每个微服务可能都会有自己的配置文件信息,比如数据库连接、用户名和密码信息都配置在配置文件中,微服务读取配置文件,将配置文件信息存入缓存中。
假设我们的配置信息发生变化时,我们还需要重新加载缓存,这比较麻烦。在zookeeper中,我们学习了watcher监听机制,利用监听机制可能轻松实现当配置信息发生变化时,应用程序第一时间发现配置变化并重新加载最新的配置信息。
二、案例
这里我们以一个简单的案例说明在zookeeper中如何利用watcher监听机制实现客户端对配置信息的动态感知。
实现步骤大体如下:
- 1、使用终端在zookeeper中事先创建一些配置信息;
- 2、Java客户端连接到zookeeper服务器;
- 3、客户端读取zookeeper中的配置信息,并且注册watcher监听,将配置信息保存起来;
- 4、使用终端对zookeeper中的配置信息进行修改;
- 5、客户端监听到zookeeper中的配置已经更改,通过watcher的回调方法捕获到节点数据变化事件;
- 6、客户端重新获取到最新的配置;
【a】使用终端在zookeeper中事先创建一些配置信息
[zk: localhost:2181(CONNECTED) 43] create /dbconfig "dbconfig"
Created /dbconfig
[zk: localhost:2181(CONNECTED) 44] create /dbconfig/url "jdbc:oracle:thin:@192.168.2.58:1521:orcl"
Created /dbconfig/url
[zk: localhost:2181(CONNECTED) 45] create /dbconfig/username "wfwzhxg"
Created /dbconfig/username
[zk: localhost:2181(CONNECTED) 46] create /dbconfig/password "wfwzhxg"
Created /dbconfig/password
[zk: localhost:2181(CONNECTED) 47] ls /dbconfig
[password, url, username]
以上我们创建了三个节点:
- url:jdbc:oracle:thin:@192.168.2.58:1521:orcl
- username:wfwzhxg
- password:wfwzhxg
【b】Java客户端相关代码
import com.wsh.zookeeper.zookeeperapidemo.watcher.ZookeeperWatcherExists;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class ZookeeperConfigDemo {
private String url;
private String username;
private String password;
private static final String ZOOKEEPER_SERVER_ADDRESS = "192.168.179.133:2181";
private static final Logger logger = LoggerFactory.getLogger(ZookeeperWatcherExists.class);
private static ZooKeeper zooKeeper = null;
public ZookeeperConfigDemo() {
try {
Watcher watcher = new Watcher() {
@Override
public void process(WatchedEvent event) {
try {
// 捕获事件状态
if (event.getType() == Event.EventType.None) {
if (event.getState() == Event.KeeperState.SyncConnected) {
logger.info("连接成功...");
} else if (event.getState() == Event.KeeperState.Disconnected) {
logger.info("连接断开...");
} else if (event.getState() == Event.KeeperState.Expired) {
logger.info("连接超时...");
// 超时后服务器端已经将连接释放,需要重新连接服务器端
zooKeeper = new ZooKeeper(ZOOKEEPER_SERVER_ADDRESS, 3000, this);
} else if (event.getState() == Event.KeeperState.AuthFailed) {
logger.info("验证失败...");
}
} else if (event.getType() == Event.EventType.NodeDataChanged) {
// 当配置信息发生变化时
initValue();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
zooKeeper = new ZooKeeper(ZOOKEEPER_SERVER_ADDRESS, 3000, watcher);
initValue();
} catch (IOException e) {
e.printStackTrace();
}
}
private void initValue() {
this.url = getDbUrl();
this.username = getDbUsername();
this.password = getDbPassword();
}
private String getDbUrl() {
try {
byte[] urlData = zooKeeper.getData("/dbconfig/url", true, null);
return new String(urlData);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
private String getDbUsername() {
try {
byte[] data = zooKeeper.getData("/dbconfig/username", true, null);
return new String(data);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
private String getDbPassword() {
try {
byte[] data = zooKeeper.getData("/dbconfig/password", true, null);
return new String(data);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static void main(String[] args) throws InterruptedException {
ZookeeperConfigDemo zookeeperConfigDemo = new ZookeeperConfigDemo();
for (int i = 0; i < 30; i++) {
TimeUnit.SECONDS.sleep(10);
System.out.println("dburl : " + zookeeperConfigDemo.getDbUrl());
System.out.println("dbusername : " + zookeeperConfigDemo.getDbUsername());
System.out.println("dbpassword : " + zookeeperConfigDemo.getPassword());
System.out.println("####################################################");
}
}
}
【c】使用终端对zookeeper中的配置信息进行修改
[zk: localhost:2181(CONNECTED) 53] set /dbconfig/username zhxg2 #修改用户名
cZxid = 0xfa
ctime = Fri Dec 25 10:41:09 CST 2020
mZxid = 0x106
mtime = Fri Dec 25 11:03:15 CST 2020
pZxid = 0xfa
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 54] set /dbconfig/password zhxg2 #修改密码
cZxid = 0xfb
ctime = Fri Dec 25 10:41:16 CST 2020
mZxid = 0x107
mtime = Fri Dec 25 11:03:18 CST 2020
pZxid = 0xfb
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 55] set /dbconfig/url jdbc:oracle:thin:@192.168.35.106:1521:orcl #修改数据库连接URL
cZxid = 0xf9
ctime = Fri Dec 25 10:40:58 CST 2020
mZxid = 0x108
mtime = Fri Dec 25 11:03:21 CST 2020
pZxid = 0xf9
cversion = 0
dataVersion = 2
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 42
numChildren = 0
【d】客户端动态感知配置变化
观察后端日志:
dburl : jdbc:oracle:thin:@192.168.2.58:1521:orcl
dbusername : zhxg2
dbpassword : zhxg
####################################################
dburl : jdbc:oracle:thin:@192.168.2.58:1521:orcl
dbusername : zhxg2
dbpassword : zhxg2
####################################################
dburl : jdbc:oracle:thin:@192.168.35.106:1521:orcl
dbusername : zhxg2
dbpassword : zhxg2
####################################################
可以看到,客户端实时监听到zookeeper服务端配置信息的变化。