在Zookeeper的主要應用場景中,其中之一是作為分布式系統的配置中心。
實作原理
在Zookeeper建立一個根節點,比如
/CONFIG
,代表某個配置檔案。将配置檔案中的資訊作為根節點的子節點存儲,比如配置項
timeout=3000
,在Zookeeper中展現為:
/CONFIG/timeout
,節點内容是3000。然後讓所有使用到該配置資訊的應用機器內建Zookeeper并監控
/CONFIG
的狀态,一旦配置資訊也就是子節點發生變化,每台應用機器就會收到ZK的通知,然後從ZK中擷取新的配置資訊應用到系統中。

以下代碼僅用于展現實作思路,具體生産還需要根據實際場景處理和優化
我們使用Curator來實作一個簡易的配置中心,關于Curator架構的使用可參考zookeeper用戶端架構Curator
項目中引入依賴包:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>4.0.1</version>
</dependency>
Config.java 配置類
public class Config {
private Map<String, String> cache = new HashMap<>();
private CuratorFramework client;
private static final String CONFIG_PREFIX = "/CONFIG";
// 初始化zk連接配接
public Config() {
this.client = CuratorFrameworkFactory.newClient("localhost:2181", new RetryNTimes(3, 1000));
this.client.start();
this.init();
}
public void init() {
try {
// 從zk中擷取配置項并儲存到緩存中
List<String> childrenNames = client.getChildren().forPath(CONFIG_PREFIX);
for (String name : childrenNames) {
String value = new String(client.getData().forPath(CONFIG_PREFIX + "/" + name));
cache.put(name, value);
}
// 綁定一個監聽器 cacheData設為true,事件發生後可以拿到節點發送的内容。
// 使用該配置檔案的每個應用機器都需要監聽,這裡隻是用于示範
PathChildrenCache watcher = new PathChildrenCache(client, CONFIG_PREFIX, true);
watcher.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception {
String path = event.getData().getPath();
if (path.startsWith(CONFIG_PREFIX)) {
String key = path.replace(CONFIG_PREFIX + "/", "");
// 子節點新增或變更時 更新緩存資訊
if (PathChildrenCacheEvent.Type.CHILD_ADDED.equals(event.getType()) ||
PathChildrenCacheEvent.Type.CHILD_UPDATED.equals(event.getType())) {
cache.put(key, new String(event.getData().getData()));
}
// 子節點被删除時 從緩存中删除
if (PathChildrenCacheEvent.Type.CHILD_REMOVED.equals(event.getType())) {
cache.remove(key);
}
}
}
});
watcher.start();
} catch (Exception e) {
e.printStackTrace();
}
}
// 儲存配置資訊
public void save(String name, String value) {
String configFullName = CONFIG_PREFIX + "/" + name;
try {
Stat stat = client.checkExists().forPath(configFullName);
if (stat == null) {
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(configFullName, value.getBytes());
} else {
client.setData().forPath(configFullName, value.getBytes());
}
cache.put(name, value);
} catch (Exception e) {
e.printStackTrace();
}
}
// 擷取配置資訊
public String get(String name) {
return cache.get(name);
}
}
Test.java 測試類
public class Main {
public static void main(String[] args) {
Config config = new Config();
// 模拟一個配置項,實際生産中會在系統初始化時從配置檔案中加載進來
config.save("timeout", "1000");
// 每3S列印一次擷取到的配置項
for (int i = 0; i < 10; i++) {
System.out.println(config.get("timeout"));
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
啟動本地zookeeper伺服器,我們來測試下。Main.java執行後會在控制台每隔3S列印一下目前擷取到的配置資訊,當我們使用其它zk用戶端重新設定timeout值時會發現擷取到的資訊及時更新了。
至此,我們使用Zookeeper實作了一個簡單的共享配置中心。
------------本文結束感謝您的閱讀------------