原文地址:

http://www.cnblogs.com/nevermorewang/p/5611807.html

选主原理介绍:zookeeper的节点有两种类型,持久节点跟临时节点。临时节点有个特性,就是如果注册这个节点的机器失去连接(通常是宕机),那么这个节点会被zookeeper删除。选主过程就是利用这个特性,在服务器启动的时候,去zookeeper特定的一个目录下注册一个临时节点(这个节点作为master,谁注册了这个节点谁就是master),注册的时候,如果发现该节点已经存在,则说明已经有别的服务器注册了(也就是有别的服务器已经抢主成功),那么当前服务器只能放弃抢主,作为从机存在。同时,抢主失败的当前服务器需要订阅该临时节点的删除事件,以便该节点删除时(也就是注册该节点的服务器宕机了或者网络断了之类的)进行再次抢主操作。从机具体需要去哪里注册服务器列表的临时节点,节点保存什么信息,根据具体的业务不同自行约定。选主的过程,其实就是简单的争抢在zookeeper注册临时节点的操作,谁注册了约定的临时节点,谁就是master。

主要有两个类,WorkServer为主服务类,RunningData用于记录运行数据。因为是简单的demo,我们只做抢master节点的编码,对于从节点应该去哪里注册服务列表信息,不作编码。

  采用zkClient实现,代码如下:

  WorkServer类

package com.zookeeper.master;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkInterruptedException;
import org.I0Itec.zkclient.exception.ZkNoNodeException;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.apache.zookeeper.CreateMode; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; /**
* Created by nevermore on 16/6/22.
*/
public class WorkServer { //客户端状态
private volatile boolean running = false; private ZkClient zkClient; //zk主节点路径
public static final String MASTER_PATH = "/master"; //监听(用于监听主节点删除事件)
private IZkDataListener dataListener; //服务器基本信息
private RunningData serverData;
//主节点基本信息
private RunningData masterData; //调度器
private ScheduledExecutorService delayExector = Executors.newScheduledThreadPool(1);
//延迟时间5s
private int delayTime = 5; public WorkServer(RunningData runningData){
this.serverData = runningData;
this.dataListener = new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception { } @Override
public void handleDataDeleted(String s) throws Exception {
//takeMaster(); if(masterData != null && masterData.getName().equals(serverData.getName())){
//若之前master为本机,则立即抢主,否则延迟5秒抢主(防止小故障引起的抢主可能导致的网络数据风暴)
takeMaster();
}else{
delayExector.schedule(new Runnable() {
@Override
public void run() {
takeMaster();
}
},delayTime, TimeUnit.SECONDS);
} }
};
} //启动
public void start() throws Exception{
if(running){
throw new Exception("server has startup....");
}
running = true;
zkClient.subscribeDataChanges(MASTER_PATH,dataListener);
takeMaster();
} //停止
public void stop() throws Exception{
if(!running){
throw new Exception("server has stopped.....");
}
running = false;
delayExector.shutdown();
zkClient.unsubscribeDataChanges(MASTER_PATH,dataListener);
releaseMaster();
} //抢注主节点
private void takeMaster(){
if(!running) return ; try {
zkClient.create(MASTER_PATH, serverData, CreateMode.EPHEMERAL);
masterData = serverData;
System.out.println(serverData.getName()+" is master"); delayExector.schedule(new Runnable() {//测试抢主用,每5s释放一次主节点
@Override
public void run() {
if(checkMaster()){
releaseMaster();
}
}
},5,TimeUnit.SECONDS); }catch (ZkNodeExistsException e){//节点已存在
RunningData runningData = zkClient.readData(MASTER_PATH,true);
if(runningData == null){//读取主节点时,主节点被释放
takeMaster();
}else{
masterData = runningData;
}
} catch (Exception e) {
// ignore;
} }
//释放主节点
private void releaseMaster(){
if(checkMaster()){
zkClient.delete(MASTER_PATH);
}
}
//检验自己是否是主节点
private boolean checkMaster(){
try {
RunningData runningData = zkClient.readData(MASTER_PATH);
masterData = runningData;
if (masterData.getName().equals(serverData.getName())) {
return true;
}
return false; }catch (ZkNoNodeException e){//节点不存在
return false;
}catch (ZkInterruptedException e){//网络中断
return checkMaster();
}catch (Exception e){//其它
return false;
}
} public void setZkClient(ZkClient zkClient) {
this.zkClient = zkClient;
} public ZkClient getZkClient() {
return zkClient;
}
}

RunningData类:

package com.zookeeper.master;

import java.io.Serializable;

/**
* Created by nevermore on 16/6/22.
*/
public class RunningData implements Serializable { private static final long serialVersionUID = 4260577459043203630L; //服务器id
private long cid;
//服务器名称
private String name; public long getCid() {
return cid;
} public void setCid(long cid) {
this.cid = cid;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}

说明:在实际生产环境中,可能会由于插拔网线等导致网络短时的不稳定,也就是网络抖动。由于正式生产环境中可能server在zk上注册的信息是比较多的,而且server的数量也是比较多的,那么每一次切换主机,每台server要同步的数据量(比如要获取谁是master,当前有哪些salve等信息,具体视业务不同而定)也是比较大的。那么我们希望,这种短时间的网络抖动最好不要影响我们的系统稳定,也就是最好选出来的master还是原来的机器,那么就可以避免发现master更换后,各个salve因为要同步数据等导致的zk数据网络风暴。所以在WorkServer中,54-63行,我们抢主的时候,如果之前主机是本机,则立即抢主,否则延迟5s抢主。这样就给原来主机预留出一定时间让其在新一轮选主中占据优势,从而利于环境稳定。

测试代码:

package com.zookeeper.master;

import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer; import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; /**
* Created by nevermore on 16/6/23.
*/
public class LeaderSelectorZkClient { //启动的服务个数
private static final int CLIENT_QTY = 10;
//zookeeper服务器的地址
private static final String ZOOKEEPER_SERVER = "localhost:2181"; public static void main(String[] args) throws Exception{
//保存所有zkClient的列表
List<ZkClient> clients = new ArrayList<ZkClient>();
//保存所有服务的列表
List<WorkServer> workServers = new ArrayList<WorkServer>(); try{
for ( int i = 0; i < CLIENT_QTY; ++i ){
//创建zkClient
ZkClient client = new ZkClient(ZOOKEEPER_SERVER, 5000, 5000, new SerializableSerializer());
clients.add(client);
//创建serverData
RunningData runningData = new RunningData();
runningData.setCid(Long.valueOf(i));
runningData.setName("Client #" + i);
//创建服务
WorkServer workServer = new WorkServer(runningData);
workServer.setZkClient(client); workServers.add(workServer);
workServer.start();
} System.out.println("敲回车键退出!\n");
new BufferedReader(new InputStreamReader(System.in)).readLine();
}finally{
System.out.println("Shutting down..."); for ( WorkServer workServer : workServers ){
try {
workServer.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
for ( ZkClient client : clients ){
try {
client.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}

zookeeper master 选举的更多相关文章

  1. zookeeper典型应用场景之一:master选举

    对于zookeeper这种东西,仅仅知道怎么安装是远远不够的,至少要对其几个典型的应用场景进行了解,才能比较全面的知道zk究竟能干啥,怎么玩儿,以后的日子里才能知道这货如何能为我所用.于是,有了如下的 ...

  2. 使用zookeeper实现分布式master选举(c 接口版本)

    zookeeper,已经被很多人所熟知,主要应用场景有(数据订阅/发布 ,负载均衡, 命名服务, 分布式协调/通知,集群管理,Master选举,分布式锁,分布式队列). C接口的描述  主要参考 Ha ...

  3. ZooKeeper场景实践:(6)集群监控和Master选举

    1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...

  4. Zookeeper实现master选举

    使用场景         有一个向外提供的服务,服务必须7*24小时提供服务,不能有单点故障.所以采用集群的方式,采用master.slave的结构.一台主机多台备机.主机向外提供服务,备机负责监听主 ...

  5. Zookeeper系列五:Master选举、ZK高级特性:基本模型

    一.Master选举 1. master选举原理: 有多个master,每次只能有一个master负责主要的工作,其他的master作为备份,同时对负责工作的master进行监听,一旦负责工作的mas ...

  6. zookeeper【4】master选举

    考虑7*24小时向外提供服务的系统,不能有单点故障,于是我们使用集群,采用的是Master+Slave.集群中有一台主机和多台备机,由主机向外提 供服务,备机监听主机状态,一旦主机宕机,备机必需迅速接 ...

  7. ZooKeeper 典型应用场景-Master选举

    master选举 1.使用场景及结构 现在很多时候我们的服务需要7*24小时工作,假如一台机器挂了,我们希望能有其它机器顶替它继续工作.此类问题现在多采用master-salve模式,也就是常说的主从 ...

  8. 模拟使用zookeeper实现master选举

    1.模拟选举机器类 package com.karat.cn.zookeeperAchieveLock.zkclient; import java.io.Serializable; /** * 选举的 ...

  9. Zookeeper实现Master选举(哨兵机制)

    master选举使用场景及结构 现在很多时候我们的服务需要7*24小时工作,假如一台机器挂了,我们希望能有其它机器顶替它继续工作.此类问题现在多采用master-salve模式,也就是常说的主从模式, ...

随机推荐

  1. windowbuilder安装

    windowbuilder,也就是原来的SWT Designer.Google收购了Instantiations,把它的工具也重新免费发布了.用过swt designer的人都知它是非常好用的swin ...

  2. jquery特效(1)—点击展示与隐藏全文

    下班了~~~我把今天整理的一个jquery小特效发一下,个人觉得比较简单,嗖嗖的就写出来了~~~ 下面先来看最终的动态效果: 一.来看一下主体框架程序: <!DOCTYPE html> & ...

  3. Java锁机制-重入锁

    锁的种类: 读写锁   悲观锁  乐观锁 CSA无锁  自旋锁  AQS 非公平锁 公平锁 互斥锁 排它锁  分布式锁(redis实现 和 zk实现) 轻量级锁(lock),重量级锁(synchron ...

  4. Android图片加载神器之Fresco-加载图片基础[详细图解Fresco的使用](秒杀imageloader)

    Fresco简单的使用—SimpleDraweeView 百学须先立志—学前须知: 在我们平时加载图片(不管是下载还是加载本地图片…..)的时候,我们经常会遇到这样一个需求,那就是当图片正在加载时应该 ...

  5. hdu-5673 Robot(默次金数)

    题目链接: Robot Time Limit: 12000/6000 MS (Java/Others)  Memory Limit: 65536/65536 K (Java/Others) 问题描述 ...

  6. CNN中下一层Feature map大小计算

    符号表示: $W$:表示当前层Feature map的大小. $K$:表示kernel的大小. $S$:表示Stride的大小. 具体来讲: 整体说来,和下一层Feature map大小最为密切的就是 ...

  7. Swift类型转换

    关于「类型转换」(Type Casting),<The Swift Programming Language>描述如下: Type casting is a way to check th ...

  8. Android开发者的四大工具

    1. Basic4Android Basic4Android是Android平台上一个简单而又强大的可视化快速应用开发工具,它可被用来开发和测试数据库通信,甚至可以被用来开发2D的即时游戏! 主要特性 ...

  9. MSD3393/MSD3463 屏参及REG对照表

    概述:TIMMING组成 MOD: BANK:0x1032 VOP: SC_BK10 注意BANK对应: VOP: SC_BK10 例如:MS_U16 m_wPanelHTotal;   Sub VO ...

  10. twincat3新建cpp提示"在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "stdafx.h"

    自己之前在windows下面写过一些c++的函数,想在倍福工控机上直接使用,发现添加了.cpp和.h文件后无法完成编译,会提示 在查找预编译头时遇到意外的文件结尾.是否忘记了向源中添加“#includ ...