what that?
Zookeeper is frequently used in distributed development, but many frameworks encapsulate it. Beginners may not understand its working principle well. This article demonstrates the simple demo of using zookeeper to realize service registration and service discovery, hoping to achieve the effect of attracting valuable ideas;
why need RegisterCenter?
The reason why access registration and service discovery are needed is that in the distributed system, services need to call each other, but if each service maintains a copy of dependent service information, it is very troublesome, and the data maintained by itself cannot guarantee its timeliness. When the dependent service information changes, it cannot be updated in time. The solution is to introduce a registration center, The service provider writes its own information to the registration center, and the service user obtains the service information from the registration center, as shown in the following figure:
client represents service user, server represents service provider
Effect: the client can automatically discover the service information. When the service status changes (online, offline, change address), the client can respond to the change in a timely manner. The effect is as follows:
realization
-
First, ensure that Zookeeper can be installed and started, and can be accessed normally
-
Create Maven project and add the Java client dependency of Zookeeper (note that the version number should be > 3.6)
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.6.1</version> </dependency>
-
Write service provider
package com.jerry; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import java.io.IOException; import java.io.InputStream; import java.net.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Enumeration; import static java.net.InetAddress.getLocalHost; public class UserService { public static void main(String[] args) throws IOException, InterruptedException, KeeperException { new UserService().serving(); } public void serving() throws IOException, KeeperException, InterruptedException { //Get local ip address String ip = null; Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces(); while (networkInterfaces.hasMoreElements()) { NetworkInterface ni = (NetworkInterface) networkInterfaces.nextElement(); Enumeration<InetAddress> nias = ni.getInetAddresses(); while (nias.hasMoreElements()) { InetAddress ia = (InetAddress) nias.nextElement(); if (!ia.isLinkLocalAddress() && !ia.isLoopbackAddress() && ia instanceof Inet4Address) { ip = ia.getHostAddress(); } } } int port = 8988; //Start service ServerSocket socket = new ServerSocket(port); System.out.println("Server started..."); //Registration services serverRegister(ip, port); //Process request clientHandler(socket); } private void clientHandler(ServerSocket socket) throws IOException { while (true) { Socket accept = socket.accept(); InputStream inputStream = accept.getInputStream(); byte[] barr = new byte[1024]; while (true) { int size = inputStream.read(barr); if (size == -1) { //System.out.println("client closed.."); accept.close(); break; } String s = new String(barr, 0, size); //Output client message System.out.println(accept.getInetAddress().getHostAddress() + ": " + s); } } } private void serverRegister(String ip, int port) throws IOException, KeeperException, InterruptedException { //Registration services ZooKeeper zooKeeper = new ZooKeeper("10.211.55.4", 2181, null); try { ArrayList<ACL> acl = new ArrayList<>(); acl.add(new ACL(31, ZooDefs.Ids.ANYONE_ID_UNSAFE)); zooKeeper.create("/userServer", (ip + ":" + port).getBytes(StandardCharsets.UTF_8), acl, CreateMode.EPHEMERAL); System.out.println("Service published successfully!"); } catch (KeeperException | InterruptedException e) { e.printStackTrace(); throw e; } } }
-
Write service user
package com.yyh; import org.apache.zookeeper.*; import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.util.Scanner; public class UserClient implements Watcher { String node = "/userServer"; //The service provider and service consumer of the node where the service information is located are the same private ZooKeeper zooKeeper; String server_ip; int server_port; public static void main(String[] args) throws Exception { //Start service listening UserClient userClient = new UserClient(); userClient.run(); //Interact with services when access is available Scanner scanner = new Scanner(System.in); while (true){ System.out.println("Enter information to send(e:sign out)"); String text = scanner.next(); if (text.equals("e"))System.exit(-1); if (userClient.server_ip == null){ System.err.println("No services available..."); }else { userClient.sendToServer(text); } } } private void run() throws Exception { //Connect zookeeper zooKeeper = new ZooKeeper("10.211.55.4:2181", 3000, null); //Try to get service information getServerInfo(); //Add permanent listening to service information zooKeeper.addWatch(node,this,AddWatchMode.PERSISTENT); } //Get service information private void getServerInfo() { try { byte[] data = zooKeeper.getData(node, false, null); String[] infos = new String(data).split(":"); server_ip = infos[0]; server_port = Integer.parseInt(infos[1]); System.out.println("Access to service information succeeded!"); System.out.println(server_ip+":"+ server_port); } catch (KeeperException e) { System.err.println("Service information does not exist! Waiting for the service to go online........"); } catch (InterruptedException e) { e.printStackTrace(); } } //This method (notification processing) will be executed when the node status sends changes @Override public void process(WatchedEvent event) { if (event.getPath().equals(node)) { //Different event types are handled according to the specific logic. Only the creation, deletion and update of nodes are concerned here if (event.getType() == Event.EventType.NodeCreated) { System.err.println("The service is online"); getServerInfo(); } else if (event.getType() == Event.EventType.NodeDataChanged) { System.err.println("Service updated"); getServerInfo(); }else if (event.getType()== Event.EventType.NodeDeleted){ server_ip = null; server_port = 0; System.err.println("The service is offline"); } } } public void sendToServer(String text) { InetSocketAddress server_address = new InetSocketAddress(server_ip, server_port); Socket socket = new Socket(); try { socket.connect(server_address); //System.out.println("server connection succeeded!"); OutputStream outputStream = socket.getOutputStream(); outputStream.write(text.getBytes()); System.out.println("Message sent successfully!"); } catch (IOException e) { e.printStackTrace(); } try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
-
Package the server code. This step can be ignored. It is only for testing the correctness of the client. In order to attach all its dependencies when packaging, here add the following content in pom with the help of Spring's packaging plug-in:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>1.5.6.RELEASE</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Note: the spring boot packaging plug-in will automatically obtain the main function in the project. It must be ensured that there is only one main function, so it is necessary to temporarily annotate the main function of the client, and finally execute the maven package to get the jar package
-
Upload jar to virtual machine and run
java -jar ZookeeperTest-1.0-SNAPSHOT.jar
If there are no other problems, the client can still connect to the server to send messages;
The above is the specific steps of using Zookeeper to realize service registration and service discovery. In actual development, we may also deploy the services provided as a cluster. At this time, we can register each service information in the cluster as a child node under the specified node. The client listens for the changes of the node, obtains the list of child nodes, and obtains the list of services, On this basis, load balancing algorithm can be added to realize reasonable access to the service list, as shown in the figure: