ZooKeeper is a distributed, open-source distributed application coordination service. It is an open-source implementation of Chubby of Google and an important component of Hadoop and Hbase. It is a software that provides consistency services for distributed applications. Its functions include configuration maintenance, domain name service, distributed synchronization, group service and so on.
Basic operation process of ZooKeeper:
1. Elect leaders.
2. Synchronize data.
3. There are many algorithms in the process of electing leaders, but the election standards to be achieved are consistent.
4. The Leader should have the highest execution ID, similar to root permission.
5. Most of the machines in the cluster get the response and accept the selected Leader.
The following examples mainly focus on node node management and event push in zk: encapsulate zookeeper data node operations into tool classes based on java;
pom.xml
<!-- integrate zookeeper --> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</version> </dependency>
ZkClientUtils.java
import org.apache.zookeeper.*; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @Description zookeeper Node tool management class * @Version V1.0 */ public class ZkClientUtils implements Watcher { /** CreateMode There are four types 1.PERSISTENT--Persistent 2.PERSISTENT_SEQUENTIAL--Persistent sequential type 3.EPHEMERAL--Temporary type 4.EPHEMERAL_SEQUENTIAL--Temporary sequential type Note: 1,2 Two types of clients will not disappear after being disconnected 3,4 If there is no new connection node within the timeout period after the client is disconnected, a message will be sent */ private volatile static ZkClientUtils zkClient = null; private static String hostPort = "192.168.1.101:2181"; private ZooKeeper zk = null; private NodeDataFunction nodeDataFunction = null; private ZkClientUtils(){ this.initZk(); } /** * Initialize object * @return */ public static ZkClientUtils getInstance(){ if (zkClient == null){ synchronized (ZkClientUtils.class) { if (zkClient == null) zkClient = new ZkClientUtils(); } } return zkClient; } /** * Initialize zk connection object */ private void initZk(){ try { zk = new ZooKeeper(hostPort, 2000, this); }catch(IOException e){ e.printStackTrace(); } } /** * Initialize zk node * @param path */ public void initZkNode(String path){ this.run(()->{ if (zk.exists(path, this) == null) { zk.create(path, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } List<String> zooChildren = listNodes(path); if (zooChildren != null){ System.out.println("Znodes of '"+path+"': "); zooChildren.forEach(o-> System.out.println(o)); } }); } /** * Displays all child nodes under the current path * @param path * @return */ public List<String> listNodes(String path){ List<String> lists = new ArrayList<>(); this.run(()->lists.addAll(zk.getChildren(path, this, null))); return lists; } /** * Create node * @param path * @param data */ public void createNode(String path, String data){ this.run(()->{ if (zk.exists(path, this) == null) { zk.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);//Persistent preservation } else { zk.setData(path, data.getBytes(), -1); } }); } /** * Get the data under the node * @param path * @return */ public String getData(String path){ String data = ""; this.run(()->{ if (zk.exists(path, this) != null) { data.concat(new String(zk.getData(path, this, null))); } }); return data; } /** * Set node data * @param path * @param data */ public void setData(String path, String data){ createNode(path, data); } /** * Delete node * @param path */ public void deleteNode(String path){ this.run(()->zk.delete(path, -1)); } /** * Close ZK connection (it is recommended to close it when the service needs to be stopped, otherwise keep ZK connection open all the time) */ public void close(){ if (zk != null){ try{ zk.close(); } catch (InterruptedException e) { e.printStackTrace(); } } zkClient = null; } /** * Execute node logic * @param interFunction */ private void run(InterFunction interFunction){ try{ interFunction.execute(); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } /** * Register business object * @param nodeDataFunction */ public void register(NodeDataFunction nodeDataFunction){ this.nodeDataFunction = nodeDataFunction; } /** * This method is called back actively by Zk service event * @param watchedEvent */ @Override public void process(WatchedEvent watchedEvent) { //By default, only the methods with nodeDataFunction interface registered can be executed in the external calling code block, otherwise the event logic must be implemented separately if (nodeDataFunction != null) { try { nodeDataFunction.execute(watchedEvent, zk, this); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } @FunctionalInterface interface InterFunction{ void execute() throws KeeperException, InterruptedException; } @FunctionalInterface interface NodeDataFunction{ void execute(WatchedEvent watchedEvent, ZooKeeper zk, Watcher watcher) throws KeeperException, InterruptedException; } /** * Test, event push * @param args */ public static void main(String[] args) { ZkClientUtils zkClientUtils = ZkClientUtils.getInstance(); String path = "/zk_test_node"; zkClientUtils.initZkNode(path); NodeDataFunction nodeData = (watchedEvent, monitorZk, watcher) -> { System.out.println(watchedEvent.getType()); if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) { System.out.println("Node change occurred..."); List<String> zooChildren = monitorZk.getChildren(path, watcher, null); System.out.println("Znodes of '"+path+"': "); for (String child: zooChildren) { System.out.println(child); } }else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) { System.out.println("Data change occurs..."); byte[] data = monitorZk.getData(path, watcher, null); System.out.printf("Current Data @ ZK Path %s: %s \n", path, new String(data)); } else if (watchedEvent.getType() == Event.EventType.NodeDeleted) { System.out.println("Data deletion occurred..."); } System.out.println(); }; zkClientUtils.register(nodeData); // List<String> lists = zkClientUtils.listNodes(path); // lists.forEach(o-> System.out.println(o)); while(true){ try{ Thread.sleep(1000); }catch (Exception e){ } } } }
explain:
People who have worked on projects know that many written reusable code blocks or useful tools are not sorted out. When necessary, they have to open the project to find it. Although it is not difficult to develop functions, they have to spend time and cost to write and test. There are too many times to build wheels repeatedly; Therefore, it is better to keep the wheel for everyone to use together;
1. This wheel can have: this component does not exist when it needs to be used.
2. The wheel is absent when I need it: every technology or tool has its project background. When the code is written in the project, I know that there is this thing. After changing a project or company, there is no backup or record. At this time, if you are absent, you have to spend time typing it again by hand;
3. I don't know whether to build wheels or not: in most cases, it's difficult for beginners to tell whether they are building wheels repeatedly. In fact, building wheels is not my purpose. My goal is to complete the task. The faster the task is completed, the better the quality is. Instead of judging whether you're building a wheel.
4. Don't want to spend time building wheels repeatedly: sometimes you will encounter some things that are not difficult but take up a lot of time. Of course, it takes the least time to have ready-made wheels;
5. I just want to learn wheels: beginners don't build wheels repeatedly, but improve their knowledge and skills after learning.
The wheel has been tested, but it is inevitable that there are mistakes. If there are mistakes, please point out;