using zookeeper to realize distributed leader node election
Dependence PrincipleAdd basic nodes in ZK, path program definition, node type as persistent node (persistent). For each process that requires campaign leader, add the child nodes of the base node in ZK separately, the type is a temporary self numbering node (ephemeral_sequential), and save the actual node path that the creation returns. Delete the child nodes created by this process as a way to exit the leader state. The child node type of the base node is a temporary ephemeral_sequential node, and when the process is disconnected from the ZK connection, ZK automatically deletes the node, ensuring that other processes are leader after the end of the link. Since ZK's numbering path is incremented, it is possible to determine whether a leader status is obtained by determining whether the node of the minimum path number number in the child node of the base node is a new node in this process.
schematic diagram
The principle of the Distributed leader node election implemented by ZK is as follows:
Several processes have tried to campaign leader, as follows:
-(1) 8 processes Create a temporary, numbered node under the ZK Basic node to obtain the actual path after the successful creation
-(2) in the Base node list, determine if this process creates a node number that is minimal
-(3) Minimum numbering process to obtain leader status
The leader program exits abnormally or the server exception causes the leader process to fail to perform the leader function:
-(1) The process will remove the corresponding temporary node in ZK, at which point the Sub node with the smallest path under the basic node will gain leader status
-(2) The process disconnected from ZK due to network or other reason, ZK automatically deletes its corresponding temporary node
-(3) New processes join the leader campaign, create temporary nodes under ZK, wait in line
Scheme One: parent node listening mode Implementation Principle
The program flowchart is as follows:
Implement code
Package xuyihao.zktest.server.zk.leader;
Import org.apache.zookeeper.*;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import java.util.List; /** * The distributed leader node election based on ZK * <pre> * scheme I: parent node monitoring mode * Implementation idea: Monitoring the parent node state * 1. Create a temporary node under the parent node (persisted), and the actual node path created is based on the number
The volume is increased (ZK creates nodes from the numbering method). * 2. After the node is created successfully, get the list of child nodes under the parent node, and determine if the path suffix number of this thread is the smallest of all child nodes, and if it becomes leader, monitor the change state of the parent node (registered watcher by the GetChildren () method) * 3. When the parent node state changes Move (mainly the child node list changes) after watcher will receive notification, then judge the parent node of the child node sorting state, if the path suffix to meet this thread is the smallest leader, vice versa continue to register watcher Monitoring parent node status * </pre> * <p
> * Created by XUYH at 2017/11/24 9:19.
* * Public class Zkleader {private static Zkleader zkleader;
Private Logger Logger = Loggerfactory.getlogger (Zkleader.class);
Private final static String Base_node_path = "/zkleader_leader";
Private final static String Node_path = "Host_process_no_";
Private String Finalnodepath;
is the primary node flag bit private Boolean leader = false;
Private String host = "127.0.0.1"; Private String Port = "2181";
Private Zookeeper zookeeper;
Private Fatherwatcher Fatherwatcher;
Connect success Flag bit Private Boolean connected = false;
public static Zkleader Create (string host, string port) {Zkleader Zkleader = new Zkleader (host, Port);
Zkleader.connectzookeeper ();
return zkleader;
Public Boolean leader () {return leader;
public void Close () {disconnectzookeeper ();
Private Zkleader (string host, string port) {this.host = host;
This.port = port;
This.fatherwatcher = new Fatherwatcher (this); Private Boolean Connectzookeeper () {try {zookeeper = new Zookeeper (host + ":" + port, 60000, Event-> {if (event.getstate () = = Watcher.Event.KeeperState.AuthFailed) {leader =
False
else if (event.getstate () = = Watcher.Event.KeeperState.Disconnected) {leader = false; else if (event.getstate () = = Watcher.Event.KeeperState.Expired) {leader = false; else {if (event.gettype () = = Watcher.Event.EventType.None) {//Description the connection succeeded Conne
CTED = true;
}
}
});
int i = 1;
while (!connected) {//wait for the asynchronous connection to succeed, over time 30s then exit wait if (i = =) break;
Thread.Sleep (300);
i++;
} if (connected) {if (Zookeeper.exists (Base_node_path, false) = null) {//Create parent node
Zookeeper.create (Base_node_path, "". GetBytes (), ZooDefs.Ids.OPEN_ACL_UNSAFE, createmode.persistent); ///Create child nodes Finalnodepath = zookeeper.create (Base_node_path + "/" + Node_path, "". Getbyt
Es (), ZooDefs.Ids.OPEN_ACL_UNSAFE, createmode.ephemeral_sequential); Check whether it is the master node cheCkleader (); else {Logger.warn ("Connect zookeeper failed.")
Time consumes S ");
return false;
The catch (Exception e) {Logger.warn (E.getmessage (), E);
return false;
return true;
Private Boolean Disconnectzookeeper () {if (zookeeper = null) return false;
try {connected = false;
Leader = false;
Zookeeper.close (); The catch (Exception e) {Logger.warn (String.Format) ("ZK disconnect failed.")
[%s] ", E.getmessage ()), e);
return true;
private void Checkleader () {if (!connected) return; try {//Get child node list register again for listening list<string> childrenlist = Zookeeper.getchildren (Base_node_path, FA
Therwatcher);
if (Judgepathnummin (childrenlist)) {leader = true; catch (Exception e) {Logger.warn (E.getmessage (), E); } Private Boolean judgepathnummin (list<string> paths) {if (Paths.isempty ()) return T
Rue
if (Paths.size () >= 2) {//The path list for the unordered state is sorted in ascending order numbering Paths.sort (STR1, str2)-> {
int num1;
int num2;
String string1 = str1.substring (Node_path.length (), str1.length ());
String string2 = str2.substring (Node_path.length (), str2.length ());
NUM1 = Integer.parseint (string1);
num2 = Integer.parseint (string2);
if (Num1 > Num2) {return 1;
else if (Num1 < num2) {return-1;
else {return 0;
}
});
String MiniD = paths.get (0);
Return Finalnodepath.equals (Base_node_path + "/" + MiniD); } Private Class FatherWatcher implements Watcher {private Zkleader context;
Fatherwatcher (Zkleader context) {This.context = context; @Override public void Process (Watchedevent event) {if (event.gettype) = = Event.eventtype.
nodechildrenchanged) {//child nodes have a change context.checkleader ();
}
}
}
}
Test
Test Program
private void Zkleaderonetestwithmultithread () throws Exception {list<leaderonethread> leaderonethreads = new Ar
Raylist<> (); for (int i = 0; i < i++) {Leaderonethreads.add (New Leaderonethread (Zkleader.create ("127.0.0.1", "2181"), I
));
} leaderonethreads.foreach (Leaderonethread::start);
Thread 0 Disconnected thread.sleep (20000);
Leaderonethreads.get (0). Getzkleader (). Close ();
Thread.Sleep (2000);
System.out.println (String.Format ("Thread: [%s] disconnected", 0));
Thread 1 disconnected thread.sleep (20000);
Leaderonethreads.get (1). Getzkleader (). Close ();
System.out.println (String.Format ("Thread: [%s] Disconnected", 1));
Thread 3 disconnected thread.sleep (20000);
Leaderonethreads.get (3). Getzkleader (). Close ();
System.out.println (String.Format ("Thread: [%s] Disconnected", 3));
Thread 4 disconnected thread.sleep (20000);
Leaderonethreads.get (4). Getzkleader (). Close ();
System.out.println (String.Format ("Thread: [%s] Disconnected", 4));
Thread 2 disconnected thread.sleep (20000); LeaderonethReads.get (2). Getzkleader (). Close ();
System.out.println (String.Format ("Thread: [%s] Disconnected", 2));
Thread.Sleep (60000);
Private class Leaderonethread extends Thread {private Zkleader zkleader;
private int threadnum;
Public Zkleader Getzkleader () {return zkleader;
} leaderonethread (Zkleader zkleader, int threadnum) {this.zkleader = Zkleader;
This.threadnum = Threadnum;
@Override public void Run () {while (true) {try {thread.sleep (5000);
catch (Exception e) {e.printstacktrace ();
Date dt = new Date ();
SimpleDateFormat SDF = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");
String currenttime = sdf.format (DT);
if (Zkleader.leader ()) {System.out.println (String.Format ("[%s] Thread: [%s] is the primary node", CurrentTime, Threadnum)); }
}
}
}
Result:
[2017-11-30 17:05:02] Thread: [0] is the master node [2017-11-30 17:05:07] Thread: [0] is the master node [2017-11-30 17:05:12] Thread: [0] is the master node thread: [0] disconnected [201 7-11-30 17:05:22] Thread: [1] is the master node [2017-11-30 17:05:27] Thread: [1] is the master node [2017-11-30 17:05:32] Thread: [1] is the master node [2017-11-30 17:05:37] Thread: [1] is the primary node thread: [1] disconnected [2017-11-30 17:05:42] Thread: [2] is the master node [2017-11-30 17:05:47] Thread: [2] is the master node [2017-11-30 17:05:52] Thread: [2] is the primary node [2017-11-30 17:05:57] Thread: [2] is the primary node thread: [3] disconnected [2017-11-30 17:06:02] Thread: [2] is the master node [2017-11-30 17:06:07] Thread: [2] is the master node [2017-11-30 17:06:12] Thread: [2] is the master node [2017-11-30 17:06:17] Thread: [2] is the primary node thread: [4] disconnected [2017-11-30 17:06:22] Thread: [2] is the main section Point [2017-11-30 17:06:27] Thread: [2] is the master node [2017-11-30 17:06:32] Thread: [2] is the master node [2017-11-30 17:06:37] Thread: [2] is the master node thread: [2] disconnected [2 017-11-30 17:06:42] Thread: [5] is the master node [2017-11-30 17:06:47] Thread: [5] is the master node [2017-11-30 17:06:52] Thread: [5] is the master node [2017-11-30 17:06:5 7] Thread: [5] is the master node [2017-11-30 17:07:02] Thread: [5] is the master node [2017-11-30 17:07:07] Thread: [5] is the master node [2017-11-30 17:07:12] Thread: [5] is the primary node [ 2017-11-30 17:07:17] Thread: [5] is the master node [2017-11-30 17:07:22] Thread: [5] is the main node [2017-11-30 17:07:27] Thread: [5] is the master node [2017-11-30 17:07:32] Thread: [5] is the primary node [2017-1 1-30 17:07:37] Thread: [5] is the primary node
Scheme one pros and cons
AdvantagesTo implement the monitoring of the change state of the parent node (mainly the change of the sub-node list) when the list of child nodes changes, ZK notifies the listening process, each process query child node state to the parent node to monitor, to achieve relatively simple
DisadvantageEach process listens to the parent node State, that is, when the parent node changes (mainly the list of child nodes), the ZK server needs to notify all registered listening processes, network consumption and resource waste is greater
Scheme Three: sub-node listening mode
Implementation Principle
The program flowchart is as follows:
Implementation Code
Import org.apache.zookeeper.*;
Import Org.apache.zookeeper.data.Stat;
Import Org.slf4j.Logger;
Import Org.slf4j.LoggerFactory;
Import java.util.List;
/** * Created by XUYH at 2017/11/30 14:40. * <p> * * * * * * * * * * * * * Plan III: Sub-node Monitoring mode * * Implementation: Monitoring child node Status * 1. Creates a temporary node under the parent node (persisted), and the actual node path created is based on the quantity
Line self-increasing (ZK creates nodes from numbering). * 2. After the successful creation of the node, first get the list of child nodes under the parent node, to determine if this thread's path suffix number is the smallest of all child nodes, if it becomes leader, on the contrary, listen to a node before this node (path sorting is the node path number minus one node) change state (through the GetData () Method Registration Watcher) * 3. When the Monitoring object state changes (node deletion state) after the watcher will receive notification, then again to determine the parent node in the order of the child node, if the path suffix to meet this thread is the smallest number of leader,
Conversely continue to register watcher listening to the previous node state * * Public class Zkleadertwo {private static zkleadertwo zkleadertwo;
Private Logger Logger = Loggerfactory.getlogger (Zkleader.class);
Private final static String Base_node_path = "/zkleader_leader";
Private final static String Node_path = "Host_process_no_";
Private String Finalnodepath;
is the primary node flag bit private Boolean leader = false;
Private String host = "127.0.0.1"; Private String PORT = "2181";
Private Zookeeper zookeeper;
Private Previousnodewatcher Previousnodewatcher;
Connect success Flag bit Private Boolean connected = false; public static Zkleadertwo Create (string host, string port) {Zkleadertwo zkleadertwo = new Zkleadertwo (host, Port)
;
Zkleadertwo.connectzookeeper ();
return zkleadertwo;
Public Boolean leader () {return leader;
public void Close () {disconnectzookeeper ();
Private Zkleadertwo (string host, string port) {this.host = host;
This.port = port;
This.previousnodewatcher = new Previousnodewatcher (this); Private Boolean Connectzookeeper () {try {zookeeper = new Zookeeper (host + ":" + port, 60000, Event-> {if (event.getstate () = = Watcher.Event.KeeperState.AuthFailed) {leader =
False
else if (event.getstate () = = Watcher.Event.KeeperState.Disconnected) { Leader = false;
else if (event.getstate () = = Watcher.Event.KeeperState.Expired) {leader = false; else {if (event.gettype () = = Watcher.Event.EventType.None) {//Description the connection succeeded Conne
CTED = true;
}
}
});
int i = 1;
while (!connected) {//wait for the asynchronous connection to succeed, over time 30s then exit wait if (i = =) break;
Thread.Sleep (300);
i++;
} if (connected) {if (Zookeeper.exists (Base_node_path, false) = null) {//Create parent node
Zookeeper.create (Base_node_path, "". GetBytes (), ZooDefs.Ids.OPEN_ACL_UNSAFE, createmode.persistent); ///Create child nodes Finalnodepath = zookeeper.create (Base_node_path + "/" + Node_path, "". Getbyt
Es (), ZooDefs.Ids.OPEN_ACL_UNSAFE, createmode.ephemeral_sequential);
Check whether the primary node is Checkleader (); else {Logger.warn ("Connect zookeeper failed.")
Time consumes S ");
return false;
The catch (Exception e) {Logger.warn (E.getmessage (), E);
return false;
return true;
Private Boolean Disconnectzookeeper () {if (zookeeper = null) return false;
try {zookeeper.close ();
connected = false;
Leader = false; The catch (Exception e) {Logger.warn (String.Format) ("ZK disconnect failed.")
[%s] ", E.getmessage ()), e);
return true;
private void Checkleader () {if (!connected) return; try {//Get child node list, if not become leader, register listener, listener object should be a node that is smaller than the path number of this node (or in front of the first bit) list<string> childrenlist =
Zookeeper.getchildren (Base_node_path, false); if (Judgepathnummin (childreNlist)) {leader = true;//becomes leader} else {Watchpreviousnode (childrenlist);
The catch (Exception e) {Logger.warn (E.getmessage (), E); } Private Boolean judgepathnummin (list<string> paths) {if (Paths.isempty ()) return T
Rue
if (Paths.size () >= 2) {//The path list for the unordered state is sorted in ascending order numbering Paths.sort (STR1, str2)-> {
int num1;
int num2;
String string1 = str1.substring (Node_path.length (), str1.length ());
String string2 = str2.substring (Node_path.length (), str2.length ());
NUM1 = Integer.parseint (string1);
num2 = Integer.parseint (string2);
if (Num1 > Num2) {return 1;
else if (Num1 < num2) {return-1;
else {return 0;
} });
String MiniD = paths.get (0);
Return Finalnodepath.equals (Base_node_path + "/" + MiniD); } private void Watchpreviousnode (list<string> paths) {if (Paths.isempty () | | paths.size (