可以利用ZooKeeper在集群的各個節點之間緩存數據。每個節點都可以得到最新的緩存的數據。Curator提供了三種類型的緩存方式:Path Cache,Node Cache 和Tree Cache。
1.Path Cache
Path Cache用來監控一個ZNode的子節點。當一個子節點增加,更新,刪除時,Path Cache會改變它的狀態,會包含最新的子節點,子節點的數據和狀態。
1.Path Cache介紹
Path Cache的主要用途是監控某個節點的子節點,由於Zookeeper原生API的watch監控節點時注冊一次只能觸發一次,而
Path Cache彌補了這個不足,它注冊一次可以一直監控觸發。
實際使用時會涉及到四個類:
- PathChildrenCache - Path Cache主要實現類
- PathChildrenCacheEvent - 監聽觸發時的事件對象,包含事件相關信息
- PathChildrenCacheListener - 監聽器接口
- ChildData - 子節點數據封裝類
通過下面的構造函數創建Path Cache:
public PathChildrenCache(CuratorFramework client, String path, boolean cacheData)
注意:使用cache,必須調用它的start方法,不用之后調用close方法。其中的
cacheData
參數用來設置是否緩存節點數據。
start有兩個,其中一個可以傳入StartMode,用來為初始的cache設置暖場方式(warm):
1.
NORMAL: 初始時為空。
2.
BUILD_INITIAL_CACHE: 在這個方法返回之前調用rebuild()。
3.
POST_INITIALIZED_EVENT: 當Cache初始化數據后發送一個PathChildrenCacheEvent.Type#INITIALIZED事件
PathChildrenCache.getListenable().addListener(PathChildrenCacheListener listener)可以增加listener監聽緩存的改變。
getCurrentData()方法返回一個List對象,可以遍歷所有的子節點。
2.編寫示例程序
public class PathCacheTest
{
private static final String PATH = "/example/cache";
public static void main(String[] args) throws Exception
{
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
PathChildrenCache cache = new PathChildrenCache(client, PATH, true);
cache.start();
PathChildrenCacheListener cacheListener = new PathChildrenCacheListener()
{
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
{
System.out.println("事件類型:" + event.getType());
System.out.println("節點數據:" + event.getData().getPath() + " = " + new String(event.getData().getData()));
}
};
cache.getListenable().addListener(cacheListener);
client.create().forPath("/example/cache/test01", "01".getBytes());
Thread.sleep(10);
client.create().forPath("/example/cache/test02", "02".getBytes());
Thread.sleep(10);
client.setData().forPath("/example/cache/test01", "01_V2".getBytes());
Thread.sleep(10);
for (ChildData data : cache.getCurrentData())
{
System.out.println("getCurrentData:" + data.getPath() + " = " + new String(data.getData()));
}
client.delete().forPath("/example/cache/test01");
Thread.sleep(10);
client.delete().forPath("/example/cache/test02");
Thread.sleep(1000 * 5);
cache.close();
client.close();
System.out.println("OK!");
}
}
注意:如果
new
PathChildrenCache
(
client
,
PATH
,
true
)
中的參數
cacheData
值設置為false,則示例中的
event
.
getData
().
getData
()
、
data
.
getData
()
將返回null,cache將不會緩存節點數據。
注意:示例中的
Thread
.
sleep
(
10
)
可以注釋,但是注釋后事件監聽的觸發次數會不全,這可能與cache的實現原理有關,不能太過頻繁的觸發事件!
3.示例程序運行結果
運行結果控制台:
事件類型:CHILD_ADDED
節點數據:/example/cache/test01 = 01
事件類型:CHILD_ADDED
節點數據:/example/cache/test02 = 02
事件類型:CHILD_UPDATED
節點數據:/example/cache/test01 = 01_V2
getCurrentData:/example/cache/test01 = 01_V2
getCurrentData:/example/cache/test02 = 02
事件類型:CHILD_REMOVED
節點數據:/example/cache/test01 = 01_V2
事件類型:CHILD_REMOVED
節點數據:/example/cache/test02 = 02
OK!
2.Node Cache
Path Cache用來監控一個節點的子節點。當節點的數據修改或者刪除時,Node Cache能更新它的狀態包含最新的改變。
1.Node Cache介紹
Node Cache與
Path Cache類似,Node Cache只是監聽某一個特定的節點。它
涉及到下面的三個類:
- NodeCache - Node Cache實現類
- NodeCacheListener - 節點監聽器
- ChildData - 節點數據
注意:使用cache,依然要調用它的start方法,不用之后調用close方法。
getCurrentData()將得到節點當前的狀態,通過它的狀態可以得到當前的值。
2.編寫示例程序
public class NodeCacheExample
{
private static final String PATH = "/example/cache";
public static void main(String[] args) throws Exception
{
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
final NodeCache cache = new NodeCache(client, PATH);
cache.start();
NodeCacheListener listener = new NodeCacheListener()
{
@Override
public void nodeChanged() throws Exception
{
ChildData data = cache.getCurrentData();
if (null != data)
{
System.out.println("節點數據:" + new String(cache.getCurrentData().getData()));
}
else
{
System.out.println("節點被刪除!");
}
}
};
cache.getListenable().addListener(listener);
client.create().creatingParentsIfNeeded().forPath(PATH, "01".getBytes());
Thread.sleep(10);
client.setData().forPath(PATH, "02".getBytes());
Thread.sleep(10);
client.delete().deletingChildrenIfNeeded().forPath(PATH);
Thread.sleep(1000 * 2);
cache.close();
client.close();
System.out.println("OK!");
}
}
注意:示例中的
Thread
.
sleep
(
10
)
可以注釋,但是注釋后事件監聽的觸發次數會不全,這可能與cache的實現原理有關,不能太過頻繁的觸發事件!
3.示例程序運行結果
運行結果控制台:
節點數據:01
節點數據:02
節點被刪除!
OK!
3.Tree Node
這種類型的即可以監控節點的狀態,還監控節點的子節點的狀態,類似上面兩種cache的組合。這也就是Tree的概念。它監控整個樹中節點的狀態。
1.Tree Node介紹
Tree Node可以監控整個樹上的所有節點,
涉及到下面四個類。
- TreeCache - Tree Cache實現類
- TreeCacheListener - 監聽器類
- TreeCacheEvent - 觸發的事件類
- ChildData - 節點數據
注意:使用cache,依然要調用它的start方法,不用之后調用close方法。
getCurrentChildren(path)返回監控節點下的某個節點的
直接子節點數據,類型為Map。 而getCurrentData()返回監控節點的數據。
2.編寫示例程序
public class TreeCacheExample
{
private static final String PATH = "/example/cache";
public static void main(String[] args) throws Exception
{
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
client.start();
TreeCache cache = new TreeCache(client, PATH);
cache.start();
TreeCacheListener listener = new TreeCacheListener()
{
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception
{
System.out.println("事件類型:" + event.getType() + " | 路徑:" + event.getData().getPath());
}
};
cache.getListenable().addListener(listener);
client.create().creatingParentsIfNeeded().forPath("/example/cache/test01/child01");
client.setData().forPath("/example/cache/test01", "12345".getBytes());
client.delete().deletingChildrenIfNeeded().forPath(PATH);
Thread.sleep(1000 * 2);
cache.close();
client.close();
System.out.println("OK!");
}
}
注意:
在此
示例中沒有使用
Thread
.
sleep
(
10
)
,但是事件觸發次數也是正常的。
3.示例程序運行結果
運行結果控制台:
事件類型:NODE_ADDED | 路徑:/example/cache
事件類型:NODE_ADDED | 路徑:/example/cache/test01
事件類型:NODE_ADDED | 路徑:/example/cache/test01/child01
事件類型:NODE_UPDATED | 路徑:/example/cache/test01
事件類型:NODE_REMOVED | 路徑:/example/cache/test01/child01
事件類型:NODE_REMOVED | 路徑:/example/cache/test01
事件類型:NODE_REMOVED | 路徑:/example/cache
OK!