转载请说明出处:https://blog.csdn.net/LiaoHongHB/article/details/84951540
该篇博客需要有上一篇基础:https://blog.csdn.net/LiaoHongHB/article/details/84950486
代码下载地址:https://download.csdn.net/download/liaohonghb/10843687
架构图:
左边是ZooKeeper集群,右边是3台工作服务器。工作服务器启动时,会去ZooKeeper的Servers节点下创建临时节点,并把基本信息写入临时节点。这个过程叫服务注册,系统中的其他服务可以通过获取Servers节点的子节点列表,来了解当前系统哪些服务器可用,这该过程叫做服务发现。接着这些服务器会尝试创建Master临时节点,谁创建成功谁就是Master,其他的两台就作为Slave。所有的Work Server必需关注Master节点的删除事件。通过监听Master节点的删除事件,来了解Master服务器是否宕机(创建临时节点的服务器一旦宕机,它所创建的临时节点即会自动删除)。一旦Master服务器宕机,必需开始新一轮的Master选举。
1、新建zookeeper-master工程,并新建master-client1和master-client2子模块:
2、master-client1:
application.yml:
server:
port: 5004
registry:
servers: 192.168.202.128:2181,192.168.202.129:2181,192.168.202.130:2181
masterservice:
public interface MasterService {
void master();
}
masterserviceimpl:
@Service
public class MasterServiceImpl implements MasterService, Watcher {
private static Logger logger = LoggerFactory.getLogger(MasterServiceImpl.class);
private static CountDownLatch latch = new CountDownLatch(1);
private ZooKeeper zk;
private static final int SESSION_TIMEOUT = 15000;
private ExecutorService executorService = Executors.newFixedThreadPool(3);
private String masterData = null;
public MasterServiceImpl() {
}
public MasterServiceImpl(String zkServers) {
try {
zk = new ZooKeeper(zkServers, SESSION_TIMEOUT, this);
latch.await();
logger.debug("connected to zookeeper");
} catch (Exception ex) {
logger.error("create zookeeper client failure", ex);
}
}
@Override
public void master() {
masterData = "127.0.0.1:5001";
logger.info("开始监听........");
Task task = new Task();
executorService.execute(task);
}
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected)
latch.countDown();
}
private class Task implements Runnable {
@Override
public void run() {
try {
zk.exists("/master", new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getType() == Event.EventType.NodeDeleted) {
logger.info("exists中监听到..." + watchedEvent.getPath() + "...删除了");
try {
zk.create("/master", masterData.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
logger.info("{}成功创建master节点", masterData);
logger.info("删除节点/registry/slave/address-0000000013");
zk.delete("/registry/slave/address-0000000013", 0);
} catch (ZkNodeExistsException e) {
logger.info("master节点已经被创建");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
} finally {
}
}
}
});
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// private class ZkDataListener implements IZkDataListener {
//
// @Override
// public void handleDataChange(String s, Object o) throws Exception {
// }
//
// @Override
// public void handleDataDeleted(String s) throws Exception {
// //重新选举master
// logger.info("重新选举master");
// try {
// zk.create("/master", masterData.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
// logger.info("{}成功创建master节点", masterData);
// zk.delete("/registry/slave/address-0000000007", 0);
// } catch (ZkNodeExistsException e) {
// logger.info("master节点已经被创建");
// } finally {
// }
// }
// }
}
masterconfig:
@Configuration
@ConfigurationProperties(prefix = "registry")
public class MasterConfig {
private String servers;
@Bean
public MasterService masterService() {
return new MasterServiceImpl(servers);
}
public void setServers(String servers) {
this.servers = servers;
}
}
weblistener:
@Component
public class WebListener implements ServletContextListener {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
public MasterService masterService;
@Override
public void contextInitialized(ServletContextEvent sce) {
masterService.master();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
master-client2和master-client1一致,只是在masterserviceimpl中masterData参数以及对应的删除节点修改即可。
3、运行结果:将master节点删除
原来的master节点删除之后,client1和client2都监听了该事件,由于client1先创建master节点,于是client2在创建master节点时就会抛出异常(KeeperErrorCode = NodeExists for /master) ;并且client1创建完master节点之后要将原来的slave下的client1节点信息删除。