天天看點

基于Zookeeper實作配置中心

在Zookeeper的主要應用場景中,其中之一是作為分布式系統的配置中心。

實作原理

在Zookeeper建立一個根節點,比如

/CONFIG

,代表某個配置檔案。将配置檔案中的資訊作為根節點的子節點存儲,比如配置項

timeout=3000

,在Zookeeper中展現為:

/CONFIG/timeout

,節點内容是3000。然後讓所有使用到該配置資訊的應用機器內建Zookeeper并監控

/CONFIG

的狀态,一旦配置資訊也就是子節點發生變化,每台應用機器就會收到ZK的通知,然後從ZK中擷取新的配置資訊應用到系統中。

基于Zookeeper實作配置中心

以下代碼僅用于展現實作思路,具體生産還需要根據實際場景處理和優化

我們使用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實作配置中心

至此,我們使用Zookeeper實作了一個簡單的共享配置中心。

------------本文結束感謝您的閱讀------------

繼續閱讀