Curator之recipes之Cache

参考资料
http://curator.apache.org/curator-recipes/path-cache.html
http://ifeve.com/zookeeper-path-cache/

可利用Zookeeper在集群的各个节点之间数据。每个节点可以得到最新的缓存的数据。分为三种:Path Cache,Node Cache,Tree Cache

Path Cache

Path Cache主要用来监听Zonde的变化 。 增加、更新或者删除一个zNode,path Cache会随之进行更新:包含新的children集合,children上的数据,children状态。

相关的类

  • PathChildrenCache : 主要类
  • PathChildrenCacheEvent : 事件
  • PathChildrenCacheListener : 监听 器
  • ChildData

使用

创建实例

path即监听的path, cacheData如果设为true,则除了缓存节点状态外,节点上的数据也会被缓存 。

public PathChildrenCache(CuratorFramework client,
                         String path,
                         boolean cacheData)
Parameters:
client - the client
path - path to watch
cacheData - if true, node contents are cached in addition to the stat

启动

必须首先通过start()方法启动cache,用完后必须调用close()关闭cache。
start()方法有两个,不带参数的start()会进行默认操作。
start(StartMode)可带一个枚举类型的startMode,设置start的方式

public enum StartMode
{
    /**
     * cache will _not_ be primed. i.e. it will start empty and you will receive
     * events for all nodes added, etc.
     */
    NORMAL,

    /**
     * rebuild() will be called before this method returns in
     * order to get an initial view of the node.
     */
    BUILD_INITIAL_CACHE,

    /**
     * After cache is primed with initial values (in the background) a
     * PathChildrenCacheEvent.Type.INITIALIZED event will be posted
     */
    POST_INITIALIZED_EVENT
}
  • NORMAL: 初始时为空。
  • BUILD_INITIAL_CACHE: 在这个方法返回之前调用rebuild()。
  • POST_INITIALIZED_EVENT: 当Cache初始化数据后发送一个PathChildrenCacheEvent.Type#INITIALIZED事件

获取数据

可通过getCurrentData()返回一个List对象,可以遍历所有的子节点。同时也可设置一个监听:在cache.getListenerable().addListener();

public void addListener(PathChildrenCacheListener listener)
     Add a change listener
Parameters:
listener - the listener

错误处理

PathChildrenCache实例监听了ConnectionStateListener。如果有连接状态改变时,cache会被重置RESET,即PathChildrenCacheListener会收到重置操作。

代码示例

启动pathCache,同时在cache上设置监听( cache.getListenable().addListener(listener);), 根据输入进行相关的操作。
cache.getCurrentData(): 获取当前节点上存储的数据 。

设置/更新、移除其实是使用client (CuratorFramework)来操作, 不通过PathChildrenCache操作:

client.setData().forPath(path, bytes);
client.create().creatingParentsIfNeeded().forPath(path, bytes);
client.delete().forPath(path);

查询缓存:

for (ChildData data : cache.getCurrentData()) {
    System.out.println(data.getPath() + " = " + new String(data.getData()));
}

代码来自于官方

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package cache;

import com.google.common.collect.Lists;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.test.TestingServer;
import org.apache.curator.utils.ZKPaths;
import discovery.ExampleServer;
import org.apache.zookeeper.KeeperException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

/**
 * An example of the PathChildrenCache. The example "harness" is a command processor
 * that allows adding/updating/removed nodes in a path. A PathChildrenCache keeps a
 * cache of these changes and outputs when updates occurs.
 */
public class PathCacheExample
{
    private static final String     PATH = "/example/cache";

    public static void main(String[] args) throws Exception
    {
        TestingServer       server = new TestingServer();
        CuratorFramework    client = null;
        PathChildrenCache   cache = null;
        try
        {
            client = CuratorFrameworkFactory.newClient(server.getConnectString(), new ExponentialBackoffRetry(1000, 3));
            client.start();

            // in this example we will cache data. Notice that this is optional.
            cache = new PathChildrenCache(client, PATH, true);
            cache.start();

            processCommands(client, cache);
        }
        finally
        {
            CloseableUtils.closeQuietly(cache);
            CloseableUtils.closeQuietly(client);
            CloseableUtils.closeQuietly(server);
        }
    }

    private static void addListener(PathChildrenCache cache)
    {
        // a PathChildrenCacheListener is optional. Here, it's used just to log changes
        PathChildrenCacheListener listener = new PathChildrenCacheListener()
        {
            @Override
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
            {
                switch ( event.getType() )
                {
                    case CHILD_ADDED:
                    {
                        System.out.println("Node added: " + ZKPaths.getNodeFromPath(event.getData().getPath()));
                        break;
                    }

                    case CHILD_UPDATED:
                    {
                        System.out.println("Node changed: " + ZKPaths.getNodeFromPath(event.getData().getPath()));
                        break;
                    }

                    case CHILD_REMOVED:
                    {
                        System.out.println("Node removed: " + ZKPaths.getNodeFromPath(event.getData().getPath()));
                        break;
                    }
                }
            }
        };
        cache.getListenable().addListener(listener);
    }

    private static void processCommands(CuratorFramework client, PathChildrenCache cache) throws Exception
    {
        // More scaffolding that does a simple command line processor

        printHelp();

        List<ExampleServer> servers = Lists.newArrayList();
        try
        {
            addListener(cache);

            BufferedReader  in = new BufferedReader(new InputStreamReader(System.in));
            boolean         done = false;
            while ( !done )
            {
                System.out.print("> ");

                String      line = in.readLine();
                if ( line == null )
                {
                    break;
                }

                String      command = line.trim();
                String[]    parts = command.split("\\s");
                if ( parts.length == 0 )
                {
                    continue;
                }
                String      operation = parts[0];
                String      args[] = Arrays.copyOfRange(parts, 1, parts.length);

                if ( operation.equalsIgnoreCase("help") || operation.equalsIgnoreCase("?") )
                {
                    printHelp();
                }
                else if ( operation.equalsIgnoreCase("q") || operation.equalsIgnoreCase("quit") )
                {
                    done = true;
                }
                else if ( operation.equals("set") )
                {
                    setValue(client, command, args);
                }
                else if ( operation.equals("remove") )
                {
                    remove(client, command, args);
                }
                else if ( operation.equals("list") )
                {
                    list(cache);
                }

                Thread.sleep(1000); // just to allow the console output to catch up
            }
        }
        finally
        {
            for ( ExampleServer server : servers )
            {
                CloseableUtils.closeQuietly(server);
            }
        }
    }

    private static void list(PathChildrenCache cache)
    {
        if ( cache.getCurrentData().size() == 0 )
        {
            System.out.println("* empty *");
        }
        else
        {
            for ( ChildData data : cache.getCurrentData() )
            {
                System.out.println(data.getPath() + " = " + new String(data.getData()));
            }
        }
    }

    private static void remove(CuratorFramework client, String command, String[] args) throws Exception
    {
        if ( args.length != 1 )
        {
            System.err.println("syntax error (expected remove <path>): " + command);
            return;
        }

        String      name = args[0];
        if ( name.contains("/") )
        {
            System.err.println("Invalid node name" + name);
            return;
        }
        String      path = ZKPaths.makePath(PATH, name);

        try
        {
            client.delete().forPath(path);
        }
        catch ( KeeperException.NoNodeException e )
        {
            // ignore
        }
    }

    private static void setValue(CuratorFramework client, String command, String[] args) throws Exception
    {
        if ( args.length != 2 )
        {
            System.err.println("syntax error (expected set <path> <value>): " + command);
            return;
        }

        String      name = args[0];
        if ( name.contains("/") )
        {
            System.err.println("Invalid node name" + name);
            return;
        }
        String      path = ZKPaths.makePath(PATH, name);

        byte[]      bytes = args[1].getBytes();
        try
        {
            client.setData().forPath(path, bytes);
        }
        catch ( KeeperException.NoNodeException e )
        {
            client.create().creatingParentContainersIfNeeded().forPath(path, bytes);
        }
    }

    private static void printHelp()
    {
        System.out.println("An example of using PathChildrenCache. This example is driven by entering commands at the prompt:\n");
        System.out.println("set <name> <value>: Adds or updates a node with the given name");
        System.out.println("remove <name>: Deletes the node with the given name");
        System.out.println("list: List the nodes/values in the cache");
        System.out.println("quit: Quit the example");
        System.out.println();
    }
}

输出:

An example of using PathChildrenCache. This example is driven by entering commands at the prompt:

set <name> <value>: Adds or updates a node with the given name
remove <name>: Deletes the node with the given name
list: List the nodes/values in the cache
quit: Quit the example

> set test testdata
Node added: test
> 

Node Cache

Node Cache用来监听 Znode。 数据改变或者Znode被删除,会触发node cache, 数据改变时node cache会改变其状态存储新值,znode删除时 node cache会置为null .

相关的类

  • NodeCache
  • NodeCacheListener
  • ChildData

使用方法

创建实例

public NodeCache(CuratorFramework client,
                         String path)
Parameters:
client - the client
path - path to cache

启动与关闭

start() 启动,使用完成 后,需调用 close()关闭
getCurrentData()获取cache最新状态。也可以通过cahce.getListenerable().addListerner()增加监听 。

public void addListener(NodeCacheListener listener)
     Add a change listener
Parameters:
listener - the listener

错误处理

NodeCache实例监听ConnectionStateListener。可通过其源码看出来,其start()方法中client.getConnectionStateListenable().addListener(connectionStateListener);

 /**
     * Start the cache. The cache is not started automatically. You must call this method.
     *
     * @param mode Method for priming the cache
     * @throws Exception errors
     */
    public void start(StartMode mode) throws Exception
    {
        Preconditions.checkState(state.compareAndSet(State.LATENT, State.STARTED), "already started");
        mode = Preconditions.checkNotNull(mode, "mode cannot be null");

        client.getConnectionStateListenable().addListener(connectionStateListener);

        switch ( mode )
        {
            case NORMAL:
            {
                offerOperation(new RefreshOperation(this, RefreshMode.STANDARD));
                break;
            }

            case BUILD_INITIAL_CACHE:
            {
                rebuild();
                break;
            }

            case POST_INITIALIZED_EVENT:
            {
                initialSet.set(Maps.<String, ChildData>newConcurrentMap());
                offerOperation(new RefreshOperation(this, RefreshMode.POST_INITIALIZED));
                break;
            }
        }
    }

代码示例

package cache;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.test.TestingServer;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.KeeperException;

public class NodeCacheExample {
    private static final String PATH = "/example/cache";

    public static void main(String[] args) throws Exception {
        NodeCache cache = null;
        CuratorFramework client = null;

        try (TestingServer server = new TestingServer()) {
            client = CuratorFrameworkFactory.newClient(server
                    .getConnectString(), new ExponentialBackoffRetry(1000, 3));

            cache = new NodeCache(client, PATH);
            client.start();
            cache.start();

            addListener(cache);

            // 新建节点
            String oldData = "oldtestData";
            try {
                client.setData().forPath(PATH, oldData.getBytes());
            } catch (KeeperException.NoNodeException e) {
                client.create().creatingParentContainersIfNeeded()
                        .forPath(PATH, oldData.getBytes());
            }

            // 修改节点上数据
            String newData = "newtestData";
            try {
                client.setData().forPath(PATH, newData.getBytes());
            } catch (KeeperException.NoNodeException e) {
                client.create().creatingParentsIfNeeded()
                        .forPath(PATH, newData.getBytes());
            }

            // 删除节点
            try {
                client.delete().forPath(PATH);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } finally {
            CloseableUtils.closeQuietly(cache);
            CloseableUtils.closeQuietly(client);
        }

    }

    private static void addListener(final NodeCache cache) {
        NodeCacheListener listener = new NodeCacheListener() {
            @Override
            public void nodeChanged() throws Exception {
                if (cache.getCurrentData() != null) {
                    System.out.println("Node changed: "
                            + cache.getCurrentData().getPath() + ", value: "
                            + new String(cache.getCurrentData().getData()));
                }
            }

        };
        cache.getListenable().addListener(listener);
    }
}

Tree Cache

Tree Cache监控节点的状态,包括子节点的状态。相当于Path Cache 与Node Cache的组合。

相关 的类

  • TreeCache
  • TreeCacheListener
  • TreeCacheEvent
  • ChildData

用法

创建实例

public TreeCache(CuratorFramework client,
                         String path)
Parameters:
client - the client
path - path to watch

启动与停止

通过start() 启动,完成后通过close()关闭。
可调用 getCurrentChildren()获取cache目前的状态,类型为Map

public void addListener(TreeCacheListener listener)
     Add a change listener
Parameters:
listener - the listener

错误处理

TreeCache内部监控ConnectionStateListener。如果发生连接状态改变时,cache会收到相应的改变信息。

代码示例

新建节点,修改节点数据,新建子节点及删除节点时都将触发TreeCacheListener.

package cache;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.test.TestingServer;
import org.apache.curator.utils.CloseableUtils;
import org.apache.curator.utils.ZKPaths;

public class TreeCacheExample {
    private static final String PATH = "/examples/cache";
    private static final String CHILD="/examples/cache/child";

    public static void main(String[] args) throws Exception {
        CuratorFramework client = null;
        TreeCache cache = null;

        try (TestingServer server = new TestingServer()) {
            client = CuratorFrameworkFactory.newClient(server
                    .getConnectString(), new ExponentialBackoffRetry(1000, 3));
            cache = new TreeCache(client, PATH);

            client.start();
            cache.start();

            addListener(cache);

            String oldData = "oldtestData";
            String newData = "newtestData";
            try {
                // 新建节点
                client.create().creatingParentContainersIfNeeded().forPath(PATH, oldData.getBytes());
                // 修改节点上数据
                client.setData().forPath(PATH, newData.getBytes());
                //新建子节点
                client.create().creatingParentContainersIfNeeded().forPath(CHILD, "childData".getBytes());
                // 删除节点
                client.delete().forPath(CHILD);
                client.delete().forPath(PATH);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }finally{
            CloseableUtils.closeQuietly(cache);
            CloseableUtils.closeQuietly(client);
        }
    }

    public static void addListener(TreeCache cache) {
        TreeCacheListener listener = new TreeCacheListener() {

            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event)
                    throws Exception {
                switch (event.getType()) {
                case NODE_ADDED: {
                    System.out
                            .println("Node added: "
                                    + ZKPaths.getNodeFromPath(event.getData()
                                            .getPath()));
                    break;
                }
                case NODE_UPDATED: {
                    System.out
                            .println("Node updated: "
                                    + ZKPaths.getNodeFromPath(event.getData()
                                            .getPath()));
                    break;
                }
                case NODE_REMOVED: {
                    System.out
                            .println("Node removed: "
                                    + ZKPaths.getNodeFromPath(event.getData()
                                            .getPath()));
                    break;
                }
                default:{
                    System.out.println("other event:"+event.getType());
                    break;
                }
                }
            }
        };

        cache.getListenable().addListener(listener);
    }
}

输出结果:

other event:INITIALIZED
Node added: cache
Node updated: cache
Node added: child
Node removed: child
Node removed: cache
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Curator注册MySQL连接节点的完整实现代码: ```java import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.nodes.PersistentNode; import org.apache.curator.framework.recipes.nodes.PersistentNode.Mode; import org.apache.curator.retry.RetryNTimes; import org.apache.zookeeper.CreateMode; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class MySQLConnectionNode { private static final String ZK_CONNECTION_STRING = "localhost:2181"; private static final String ZK_PATH = "/mysql/connection"; private CuratorFramework curatorFramework; private PersistentNode persistentNode; private NodeCache nodeCache; private Connection connection; public MySQLConnectionNode() throws Exception { curatorFramework = CuratorFrameworkFactory.newClient(ZK_CONNECTION_STRING, new RetryNTimes(5, 1000)); curatorFramework.start(); persistentNode = new PersistentNode(curatorFramework, CreateMode.EPHEMERAL, false, ZK_PATH, getConnectionBytes()); persistentNode.start(); nodeCache = new NodeCache(curatorFramework, ZK_PATH); nodeCache.getListenable().addListener(new NodeCacheListener() { @Override public void nodeChanged() throws Exception { byte[] data = nodeCache.getCurrentData().getData(); connection = getConnectionFromBytes(data); } }); nodeCache.start(); } public Connection getConnection() { return connection; } private byte[] getConnectionBytes() throws SQLException { Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "user", "password"); return conn.toString().getBytes(); } private Connection getConnectionFromBytes(byte[] data) throws SQLException { String connStr = new String(data); return DriverManager.getConnection(connStr); } public void close() { nodeCache.close(); persistentNode.close(); curatorFramework.close(); } } ``` 这里我们使用了Curator提供的`PersistentNode`和`NodeCache`来实现注册MySQL连接节点,并监听节点变化。在`getConnectionBytes`方法中,我们创建一个MySQL连接,并将它转换为字节数组存储到ZooKeeper节点中。在`getConnectionFromBytes`方法中,我们从字节数组中解析出MySQL连接对象。通过监听节点变化,我们能够实时获取到MySQL连接对象的变化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值