文章目录
zookeeper选举机制——第一次启动
SID:服务器ID。用来唯一标识一台ZooKeeper集群中的机器,每台机器不能重复,和myid一致。
ZXID:事务ID。ZXID是一个事务ID,用来标识一次服务器状态的变更。在某一时刻,集群中的每台机器的ZXID值不一定完全一致,这和ZooKeeper服务器对于客户端“更新请求”的处理逻辑有关。
EPOCH:每个Leader任期的代号。没有Leader时同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加。
zookeeper选举机制——非第一次启动
如果五台服务器都启动了,要进入leader选举,需要:
1.服务器初始化启动,会先自己投自己
2.如果图中的5没办法和leader通信,那就会重新选举
如果原先的leader宕机了,这个时候集群中的其他flower会重新选举leader,选举机制是根据<EPOCH,ZXID,SID>,先比较EPOCH,再比较ZXID,最后比较SID
监听器原理
切记:监听器注册一次只能监听一次,如果想要多次监听,只能多次注册。
监听节点的值用: get -w 路径
监听节点的子节点变化: ls -w 路径
删除节点: delete 路径
删除”大“节点 :deleteall 路径
写数据操作
如果客户端把请求发给了leader
leader收到请求,会先自己内部写数据,再把写数据的命令发给follower,follower写完数据会回复leader,当半数follower写完数据,leader会告知客户端写完
如果客户端把请求发给了follower
follower收到客户端请求后,由于没有权限写数据,会把写数据的请求发给leader,leader收到请求后,先自己写,再把写数据命令发布给其他follower,当半数follower写完数据,leader会告知收到请求的follower已经写完,follower再告知客户端写完数据
实现客户端监听服务端动态上下线
servers:
import org.apache.zookeeper.*;
import java.io.IOException;
public class servers {
String connectString = "192.168.217.132:2181,192.168.217.137:2181,192.168.217.136:2181";
private int sessionTimeout = 2000;
private ZooKeeper zk;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
servers server = new servers();
server.getconnect();
server.register(args[0]);
server.bussiness();
}
private void bussiness() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
private void register(String hostname) throws KeeperException, InterruptedException {
zk.create("/servers/",hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostname+" is online");
}
private void getconnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
}
});
}
}
clients:
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class clients {
private ZooKeeper zk;
String connectString = "192.168.217.132:2181,192.168.217.137:2181,192.168.217.136:2181";
private int sessionTimeout = 2000;
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
clients client = new clients();
client.getconnect();
client.watch();
client.bussiness();
}
private void bussiness() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
private void watch() throws KeeperException, InterruptedException {
ArrayList<String> a = new ArrayList<String>();
List<String> children = zk.getChildren("/servers", true);
for (String child : children) {
byte[] data = zk.getData("/servers/" + child, false, null);
a.add(new String(data));
}
System.out.println(a);
}
private void getconnect() throws IOException {
zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
public void process(WatchedEvent watchedEvent) {
try {
watch();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
当服务端传入参数worker1时,可以认为集群中我的worker1节点上线,在客户端会有时刻监听着,会监听到列表中worker1的增加:
servers
clients