接上节内容:
1、Getting MasterShip(获取主人身份)
创建一个 /master 需要做两件事情,第一:初始化节点数据,第二:需要ACL(Access control list)访问控制表
ACL是一个常量ZooDefs.Ids.OPEN_ACL_UNSAFE(这表明不是安全的,一般用于安全的环境下)
随机生成节点数据:String serverId = Integer.toHexString(random.nextInt());
接口:
void runForMaster(){
zk.create("/master",
serverId.getBytes(),
OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
}
注释:
- 第一个参数是要创建的节点为master,如果存在将会创建失败
- 第二个参数表示存储节点的数据是字节数组
- 第三个参数使用ACL
- 第四个参数表示创建一个瞬时节点
创建节点会抛出两个异常:KeeperException(ConnectionLossException是它子类) 和InterruptedException
首先创建一个节点,然后获取master是不是我刚才创建master节点。(启动Zookeeper服务)
package learn;
import java.io.IOException;
import java.util.Random;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.ConnectionLossException;
import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class Master implements Watcher{
ZooKeeper zk;
String hostPort;
private Random random = new Random();
String serverId = Integer.toHexString(random .nextInt());
/**
* 判断当前领导是否是我,不是返回false,是返回True
*
* @return
*/
boolean checkMaster(){
while(true){
try{
Stat stat = new Stat();
byte data[] = zk.getData("/master", false, stat);
isLeader = new String (data).equals(serverId);
return true;
} catch (NoNodeException e){
return false;
}catch (ConnectionLossException e){
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 创建节点失败表示已经有领导者,如果成功,去检查当前领导是否为刚才创建的领导者
* @throws InterruptedException
*/
void runForMaster() throws InterruptedException{
while(true){
try{
zk.create("/master", serverId.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
isLeader = true;
break;
} catch (NodeExistsException e) {
isLeader = false;
break;
} catch(ConnectionLossException e){
} catch (KeeperException e) {
e.printStackTrace();
}
if (checkMaster()) break;
}
}
static boolean isLeader = false;
Master(String hostPort){
this.hostPort = hostPort;
}
void startZK() throws IOException{
zk = new ZooKeeper(hostPort, 15000, this);
}
public void process(WatchedEvent e) {
System.out.println(e);
}
void stopZK() throws Exception{ //关闭zk
zk.close();
}
public static void main(String[] args) throws Exception {
Master m = new Master(args[0]);
m.startZK();
m.runForMaster();
if(isLeader){
System.out.println("我是领导者");
Thread.sleep(60000);
}else {
System.out.println("已经有领导者");
}
Thread.sleep(60000);
m.stopZK();
}
}
2、通过异步获取主人身份
接口与同步类似,只是增加两个参数
void create(String path,
byte[] data,
List<ACL> acl,
CreateMode createMode,
AsyncCallback.StringCallback cb,
Object ctx)
一个是回调函数:类似js的ajax,回调函数
一个上下文对象:打包的数据(包括异常信息)
需要实现如下回调接口
void processResult(int rc, String path, Object ctx, String name)
rc : 返回码,例如OK
path:创建节点路径
ctx : 打包上下文对象
name : 创建的节点的名称
一般创建成功path和name相等,但CreateMode.SEQUENTIAL除外。
package learn;
import java.io.IOException;
import java.util.Random;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.KeeperException.ConnectionLossException;
import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class Master implements Watcher{
static ZooKeeper zk;
String hostPort;
private static Random random = new Random();
static String serverId = Integer.toHexString(random .nextInt());
/**
* 判断当前领导是否是我,不是返回false,是返回True
*
* @return
*/
static boolean checkMaster(){
while(true){
try{
Stat stat = new Stat();
byte data[] = zk.getData("/master", false, stat);
isLeader = new String (data).equals(serverId);
return true;
} catch (NoNodeException e){
return false;
}catch (ConnectionLossException e){
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 创建节点失败表示已经有领导者,如果成功,去检查当前领导是否为刚才创建的领导者
* @throws InterruptedException
*/
void runForMaster() throws InterruptedException{
zk.create("/master", serverId.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,
masterCreateCallback, null);
}
static boolean isLeader = false;
//回调函数
static StringCallback masterCreateCallback = new StringCallback(){
public void processResult(int rc, String path, Object ctx, String name) {
switch (Code.get(rc)) {
case CONNECTIONLOSS:
checkMaster();
return;
case OK:
isLeader = true;
break;
default:
isLeader=false;
break;
}
System.out.println("我" + (isLeader?"是":"不是") +"领导");
}
};
Master(String hostPort){
this.hostPort = hostPort;
}
void startZK() throws IOException{
zk = new ZooKeeper(hostPort, 15000, this);
}
public void process(WatchedEvent e) {
System.out.println(e);
}
void stopZK() throws Exception{ //关闭zk
zk.close();
}
public static void main(String[] args) throws Exception {
Master m = new Master(args[0]);
m.startZK();
m.runForMaster();
if(isLeader){
System.out.println("我是领导者");
Thread.sleep(60000);
}else {
System.out.println("已经有领导者");
}
Thread.sleep(60000);
m.stopZK();
}
}
通过重写DataCallback回调函数
static DataCallback masterCheckCallback = new DataCallback(){
public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
switch(Code.get(rc)){
case CONNECTIONLOSS:
checkMaster();
return;
case NONODE:
try {
runForMaster();
} catch (InterruptedException e) {
e.printStackTrace();
}
return;
default:
break;
}
}
};
void checkMaster() {
zk.getData("/master", false, masterCheckCallback, null);
}
3、设置元数据
/tasks, /assign, 和/workers等根节点。通过回调函数创建节点
package learn;
import java.io.IOException;
import java.util.Random;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class Master implements Watcher{
static ZooKeeper zk;
String hostPort;
private static Random random = new Random();
static String serverId = Integer.toHexString(random .nextInt());
Master(String hostPort){
this.hostPort = hostPort;
}
void startZK() throws IOException{
zk = new ZooKeeper(hostPort, 15000, this);
}
public void boostrap(){
createParent("/workers", new byte[0]);
createParent("/assign", new byte[0]);
createParent("/tasks", new byte[0]);
createParent("/status", new byte[0]);
}
private void createParent(String path, byte[] data) {
zk.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT,
createParentCallback, data);
}
StringCallback createParentCallback = new StringCallback() {
public void processResult(int rc, String path, Object ctx, String name) {
switch (Code.get(rc)) {
case CONNECTIONLOSS:
createParent(path,(byte[]) ctx);
break;
case OK:
System.out.println("父级节点创建成功");
break;
case NODEEXISTS:
System.out.println("父级节点已经存在:" +path);
break;
default:
System.out.println("某个地方出现异常:"+ KeeperException.create(Code.get(rc), path));
break;
}
}
};
public void process(WatchedEvent e) {
System.out.println(e);
}
void stopZK() throws Exception{ //关闭zk
zk.close();
}
public static void main(String[] args) throws Exception {
Master m = new Master(args[0]);
m.startZK();
m.boostrap();
Thread.sleep(60000);
m.stopZK();
}
}
4、注册工作者
步骤1:连接服务器
步骤2:创建节点
步骤3:回调函数处理
package learn;
import java.io.IOException;
import java.util.Random;
import org.apache.zookeeper.AsyncCallback.DataCallback;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.KeeperException.ConnectionLossException;
import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class Master implements Watcher{
static ZooKeeper zk;
String hostPort;
private static Random random = new Random();
static String serverId = Integer.toHexString(random .nextInt());
Master(String hostPort){
this.hostPort = hostPort;
}
void startZK() throws IOException{
zk = new ZooKeeper(hostPort, 15000, this);
}
void register(){
zk.create("/workers/worker-" +serverId, "Idle".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL,
createWorkerCallback, null);
}
StringCallback createWorkerCallback = new StringCallback() {
public void processResult(int rc, String path, Object ctx, String name) {
switch (Code.get(rc)) {
case CONNECTIONLOSS: //表示断开需要重新创建
register();
break;
case OK:
System.out.println("Worker节点创建成功:" +serverId);
break;
case NODEEXISTS:
System.out.println("Worker节点已经存在:" +serverId);
break;
default:
System.out.println("某个地方出现异常:"+ KeeperException.create(Code.get(rc), path));
break;
}
}
};
public void process(WatchedEvent e) {
System.out.println(e);
}
void stopZK() throws Exception{ //关闭zk
zk.close();
}
public static void main(String[] args) throws Exception {
Master m = new Master(args[0]);
m.startZK();
m.register();
Thread.sleep(60000);
m.stopZK();
}
}
更新工作者状态
5、队列任务
为工作者分配任务
package learn;
import java.io.IOException;
import java.util.Random;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException.ConnectionLossException;
import org.apache.zookeeper.KeeperException.NodeExistsException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class Master implements Watcher{
static ZooKeeper zk;
String hostPort;
private static Random random = new Random();
static String serverId = Integer.toHexString(random .nextInt());
Master(String hostPort){
this.hostPort = hostPort;
}
void startZK() throws IOException{
zk = new ZooKeeper(hostPort, 15000, this);
}
String queueCommand(String command) throws Exception {
while(true){
try{
String name = zk.create("/tasks/task-", command.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
return name;
}catch (NodeExistsException e){
throw new Exception(command +"已经存在运行task任务");
} catch (ConnectionLossException e){
}
}
}
public void process(WatchedEvent e) {
System.out.println(e);
}
void stopZK() throws Exception{ //关闭zk
zk.close();
}
public static void main(String[] args) throws Exception {
Master m = new Master(args[0]);
m.startZK();
String name = m.queueCommand("11");
System.out.println("创建task节点: " + name);
Thread.sleep(60000);
m.stopZK();
}
}
6、创建简单一个管理客户端 , 打印当前服务器节点master,worker,task数据
package learn;
import java.util.Date;
import org.apache.zookeeper.KeeperException.NoNodeException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class AdminClient implements Watcher{
ZooKeeper zk;
String hostPort;
AdminClient(String hostPort) {
this.hostPort = hostPort;
}
void listState() throws Exception {
try {
Stat stat = new Stat();
byte masterData[] = zk.getData("/masters", false, stat);
Date startDate = new Date(stat.getCtime());
System.out.println("Master: " + new String(masterData) + "时间为:" + startDate);
}catch (NoNodeException e) {
System.out.println("没有master");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("工作者:");
for(String w:zk.getChildren("/workers", false)){
byte data[] = zk.getData("/workers" + w, false, null);
String state = new String(data);
System.out.println("\t" +w + ": " + state);
}
System.out.println("任务:");
for(String t:zk.getChildren("/assign", false)){
System.out.println("\t" + t);
}
}
void start() throws Exception {
zk = new ZooKeeper(hostPort, 15000, this);
}
public void process(WatchedEvent e) {
System.out.println(e);
}
public static void main(String[] args) throws Exception {
AdminClient c = new AdminClient("127.0.0.1:2181");
c.start();
c.listState();
}
}