从零开始的高并发(六)--- Zookeeper的Master选举及官网小览

前言

前情概要

距离上一篇的更新也是好一段日子了,期间也是有小伙伴催更但是由于一些杂事一直没处理好,接下来会恢复周更java

有小伙伴的反馈中说到标题都是经典应用,太过笼统因此无法经过标题得知对应内容的问题,在此也是进行了改进node

第四篇:Zookeeper的经典应用场景---标题修改成---Zookeeper的分布式队列
第五篇:Zookeeper的经典应用场景2---标题修改成---Zookeeper的配置中心应用
复制代码

以往连接

从零开始的高并发(一)--- Zookeeper的基础概念算法

从零开始的高并发(二)--- Zookeeper实现分布式锁编程

从零开始的高并发(三)--- Zookeeper集群的搭建和leader选举缓存

从零开始的高并发(四)--- Zookeeper的分布式队列session

从零开始的高并发(五)--- Zookeeper的配置中心应用架构

内容一:简单谈谈Zookeeper的Master选举

1.什么是Master选举

在分布式架构中常常采用的结构就是一主多从,主节点祈使句就是负责协调管理集群用的。咱们能够借用这个场景去展开。并发

2.zookeeper如何去实现master选举

为何咱们要采用临时节点,觉得考虑到master节点可能负载较高,挂掉了,这时咱们要保证其余下面的servers服务都可以获得通知,框架

其实咱们也能够经过最小节点方式来实现,就谁排在前面,谁就有权利去得到master运维

3.代码实现

① 须要使用到的变量

首先咱们须要有一个master节点,而后cluster表明的是集群的名字,name是指服务名,address是指服务的地址。masterPath是指master的znode目录,value是用来记录上面的name加address的,ZkClient不用多说了,从第二篇开始用这货用到如今了

private String cluster, name, address;

private final String masterPath, value;

private String master;

private ZkClient client; 
复制代码

② 构造器

public Server(String cluster, String name, String address) {
	super();
	this.cluster = cluster;
	this.name = name;
	this.address = address;
	masterPath = "/" + this.cluster + "/master";
	value = "name:" + this.name + " address:" + this.address;
	client = new ZkClient("localhost:2181");
	client.setZkSerializer(new MyZkSerializer());

	String serversPath = "/" + this.cluster + "/servers";
	client.createPersistent(serversPath, true);

	String serverPath = serversPath + "/" + name;
	client.createEphemeral(serverPath, value);

	new Thread(new Runnable() {
		@Override
		public void run() {
			electionMaster(client);
		}
	}).start();

}
复制代码

进来时你要先告诉我,你是属于哪一个集群的啊,你的名字,还有你的对应地址是什么,而后咱们的masterPath就定义在这个集群的master目录下,这种方式让咱们方便记录多个不一样的集群。

serversPath是指集群中全部服务信息存放的znode根目录路径,serverPath是一个具体的服务,是刚刚的根目录+这个服务的名字,这个服务咱们是要存放于临时节点(createEphemeral()方法)上的,刚刚的根目录咱们是建立了持久节点(createPersistent()方法),为何咱们如今要使用临时节点了呢,由于咱们刚刚也提到了,master节点是能够挂掉的,并且咱们以后也会进行master节点挂掉的模拟,value是用来记录name和address的,在以后的执行结果中会打印出来

最后经过一个线程去执行这个master的选举,咱们在master的选举中要不停地监听咱们的master,在master被抢到了之后,我须要对这个线程进行阻塞操做,但是若是这时候主线程阻塞了,整个程序就不跑了,因此咱们必须经过一个子线程去帮咱们去抢master,此时就算我抢不到master,也能保证整个程序能够继续往下执行。

③ 选举的方法实现

public void electionMaster(ZkClient client) {
    try {
        //尝试去获取master
	client.createEphemeral(masterPath, value);
	
	//若是成功,记录master节点信息
	//在这里咱们记录master信息并做为缓存,方便得知这个集群的master是谁
	//这样就能够再也不使用zookeeper去查master了
	master = client.readData(masterPath);
	
	System.out.println(value + "建立节点成功,成为Master");
    } catch (ZkNodeExistsException e) {
    
        //没有抢到master的状况下,咱们把如今master的信息读到本身的服务里面
    	master = client.readData(masterPath);
    	System.out.println("Master为:" + master);
    }

	// 为阻塞本身等待而用
	CountDownLatch cdl = new CountDownLatch(1);

	// 注册watcher
	IZkDataListener listener = new IZkDataListener() {

		@Override
		public void handleDataDeleted(String dataPath) throws Exception {
			System.out.println("-----监听到节点被删除");
			cdl.countDown();
		}

		@Override
		public void handleDataChange(String dataPath, Object data) throws Exception {

		}
	};

	client.subscribeDataChanges(masterPath, listener);

	// 让本身阻塞
	if (client.exists(masterPath)) {
		try {
			cdl.await();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
	}
	// 醒来后,取消watcher
	client.unsubscribeDataChanges(masterPath, listener);
	// 递归调本身(下一次选举)
	electionMaster(client);
}

	public void close() {
		client.close();
	}

}
复制代码

咱们监听节点的删除事件,一旦master节点被释放掉了,咱们会当即唤醒本身的线程去参与争抢。在最后还进行了一个if (client.exists(masterPath))的判断,肯定是已经有节点成为了master了,咱们就会经过await方法让本身阻塞,若是不存在master,那就从新调用自身争抢master的方法

最后的close()方法是为了模拟机器挂掉而使用的,与代码自己的逻辑无关

④ 场景测试

咱们使用线程来代替进程,ScheduledThreadPoolExecutor是一个定时任务,5秒后我会关闭s1,10秒后关闭s2以此类推。

public static void main(String[] args) {
	// 测试时,依次开启多个Server实例java进程,而后中止获取的master的节点,看谁抢到Master
	Server s1 = new MasterElectionDemo().new Server("cluster1", "server1", "192.168.1.11:8991");
	Server s2 = new MasterElectionDemo().new Server("cluster1", "server2", "192.168.1.11:8992");
	Server s3 = new MasterElectionDemo().new Server("cluster1", "server3", "192.168.1.11:8993");
	Server s4 = new MasterElectionDemo().new Server("cluster1", "server4", "192.168.1.11:8994");
	
	ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
	scheduled.schedule(()->{
		System.out.println("关闭s1");
		s1.close();
	}, 5, TimeUnit.SECONDS);
	scheduled.schedule(()->{
		System.out.println("关闭s2");
		s2.close();
	}, 10, TimeUnit.SECONDS);
	scheduled.schedule(()->{
		System.out.println("关闭s3");
		s3.close();
	}, 15, TimeUnit.SECONDS);

	try {
		Thread.currentThread().join();
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
}
复制代码

⑤ 结果分析

由于咱们s1是第一个被建立的,因此它成为master的可能性固然是最大的

此时咱们5秒后关闭s1,这时监听到master节点没了,你们都被唤醒去抢master,而后s4抢到了,成为了master

此时咱们再删除s2和s3,就会发现和上面不同了,由于s4是master,因此我删除s2,或者s3都不要紧,都不像删除s1的时候会再触发master的选举,假设咱们下次不是s4抢到,而是s3抢到了master,那咱们在关闭s3的时候,就会像s1关闭时那样从新触发选举了,不过此时就仅仅还剩s4了而已

内容二:zookeeper的官网

1.为何要普及一下官网

在本身仍是0基础的时候,如何来经过官网去学习,虽然如今网上关于各大框架的知识确实已经不少了,但是咱们仍是有必要去浏览这些开源框架的官网,由于不管网上的说法再良莠不齐众说纷纭,但官网是表明着绝对权威的

并且官网所提到的知识通常也是基础的应用,不会说涉及不少复杂的业务场景,从官网上去了解一个新的框架是最好的,也不会存在带有误导性的demo和总结,在大体了解以后,想看看具体的业务中使用,则可使用百度,去看看别人写的一些应用,就没有问题。

若是官网都会出错,那就只能本身看源码了,过程则会很是痛苦(摊手)

2.如何去大体地浏览官网

基本会按照以前写的章节的内容去大体说明,就是之前章节提到的内容在官网中哪里能够找到

这是zookeeper官网的目录结构,整个zookeeper的骨架都会列出来

① 欢迎页

这里其实就是介绍了每一个栏目分别都存在了什么东西,上面的图其实也大体翻译了这些内容

② 咱们最关心的Programmer's Guide

Developing Distributed Applications that use ZooKeeper
    Introduction---这个模块的简介
    The ZooKeeper Data Model---zookeeper的数据模型
    ZNodes---znode的介绍
        Watches---监听机制的介绍
        Data Access---以前谈到额ACL
        Ephemeral Nodes---临时节点的介绍
        Sequence Nodes -- Unique Naming---顺序节点的介绍及命名惟一规则
        
        这俩是3.5.3的新加入的节点类型,咱们使用的版本并未涉及
        Container Nodes
        TTL Nodes
    
    Time in ZooKeeper---zookeeper的时间定义
    ZooKeeper Stat Structure---节点的元数据,zxid那些
    ZooKeeper Sessions---session相关
    ZooKeeper Watches---watch想关及watch怎样用
        Semantics of Watches---watch的意义
        Remove Watches---移除
        What ZooKeeper Guarantees about Watches---watch的机制
        Things to Remember about Watches---使用注意的事项
        
    如下也不一一翻译了,就是各个方面相关的知识呗
    ZooKeeper access control using ACLs
        ACL Permissions
        Builtin ACL Schemes
        ZooKeeper C client API
    Pluggable ZooKeeper authentication
    Consistency Guarantees---特性
    Bindings---客户端使用方面的
        Java Binding
            Client Configuration Parameters
        C Binding
            Installation
            Building Your Own C Client
    Building Blocks: A Guide to ZooKeeper Operations
        Handling Errors
        Connecting to ZooKeeper
        Read Operations
        Write Operations
        Handling Watches
        Miscelleaneous ZooKeeper Operations
    Program Structure, with Simple Example
    Gotchas: Common Problems and Troubleshooting
复制代码

③ java example

ZooKeeper Java Example
    A Simple Watch Client
        Requirements
        Program Design
    The Executor Class
    The DataMonitor Class
    Complete Source Listings
复制代码

在program design中会介绍这个程序所要达成的目的

④ Barrier and Queue Tutorial和Recipes

这里提到了栅栏和队列的实现,不过在以前的文章中实现的方式和官网的不一样

Recipes上面的是一些更为高级的使用,双栅栏,权重队列,共享锁,对leader选举的补充等等

⑤ Admin & Ops

这里涉及到一些运维和管理员的使用文档,好比怎么去搭建集群等,在这里只贴部分,在以前的文章也有提到

dataLogDir也是经过log4j来进行管理的

JMX:zookeeper默认实现了JMX接口,内容也包括了以前咱们提到的jconsole

Observers Guide:观察者,其实它的职责就是服务集群,能够用来分担读请求的负载,还可让leader选举的时候更加快速,在集群数较多的时候,进行leader选举是一个很是耗时的过程,好比我只让几个节点来参与leader选举,其他的只是做为观察者,不参与投票而仅同步数据。

⑥ contributor

开票就提到了咱们说过的原子广播协议

以后的Miscellaneous模块就是一些杂七杂八的文档,维基百科之类的

wiki中有关于zab的介绍,包括paxos算法的介绍也有

⑦ 支持的客户端

⑧ 一些有用的工具

keptCollections

curator

curator的一种比较优雅的链式编程

curator自身实现了leader选举和分布式锁等功能,leader选举中Curator提供了LeaderSelector监听器实现Leader选举功能,同一时刻,只有一个Listener会进入takeLeadership()方法,说明它是当前的Leader。不过若是不清楚这个机制的话代码走起来讲真的其实有点懵。而分布式锁呢curator是经过一个InterProcessMutexDemo类来实现的,这里就不展开了。

finally

到这篇为止zookeeper的东西就差很少了,也算是填了一个坑吧,代码从二到六也算是敲的很多,并且基本都是完整地贴出来了,有兴趣想跑一下验证的话直接ctrl+c/v便可。以后应该是按部就班,RPC再到dubbo的一个路线

下一篇:从零开始的高并发(七)--- RPC的介绍,协议及框架

相关文章
相关标签/搜索