3.大数据学习之旅——Zookeeper

版权声明:版权归零零天所有 https://blog.csdn.net/qq_39188039/article/details/86219343

Zookeeper

Zookeeper是开源的分布式的协调服务框架,是Apache Hadoop的子件,适用
于绝大部分分布式集群的管理

分布式引发问题:

  1. 死锁:至少有一个线程占用了资源,但是不占用CPU
  2. 活锁:所有线程都没有把持资源,但是线程却是在不断地调度占用CPU
  3. 需要引入一个管理节点
  4. 为了防止入口的单点问题,需要引入管理节点的集群
  5. 需要在管理阶段中选举出一个主节点
  6. 需要确定一套选举算法
  7. 主节点和从节点之间要保证数据的一致
    Zookeeper的安装可以分为单机版和集群式

Zookeeper的单机版安装

Zookeeper可以安装在Linux下,也可以安装在Windows中,但是官网上声明
在Windows中Zookeeper不保证稳定性

  1. 关闭Linux的防火墙
    1. 临时关闭:service iptables stop
    2. 永久关闭:chkconfig iptables off
  2. 下载并且安装jdk,要求jdk是1.6以上的版本
  3. 下载Zookeeper的安装包
  4. 解压安装包:tar - xvf zookeeper-3.4.8.tar.gz
  5. 进入Zookeeper的安装目录中的conf目录:cd zookeeper-3.4.8/conf
  6. 将zoo_sample.cfg复制为zoo.cfg:cp zoo_sample.cfg zoo.cfg
  7. Zookeeper在启动的时候会自动加载zoo.cfg,从里面读取配置信息,需要
    修改zoo.cfg,将其中的dataDir进行修改:
    dataDir=/home/software/zookeeper-3.4.8/tmp
  8. 创建指定的数据存储目录:mkdir tmp
  9. 进入bin目录:cd bin
  10. 启动服务器端:sh zkServer.sh start
  11. 启动客户端:sh zkCli.sh
    注意:
    Zookeeper返回Started不代表启动成功,可以通过jps或者是sh zkServer.sh
    status来查看是否启动成功
    如果使用的是jps,查看是否有QuorumPeerMain
    如果使用的是sh zkServer.sh status, 查看是否有Mode:standalone
    当Zookeeper启动之后,在bin目录下会出现zookeeper.out文件 — 记录
    Zookeeper的启动过程的日志文件

Zookeeper的特点

  1. 本身是一个树状结构 — Znode树
  2. 每一个节点称之为znode节点
  3. 根节点是 / 3.
  4. Zookeeper的所有操作都必须以根节点为基准进行计算 /
  5. 每一个znode节点都必须存储数据
  6. 任意一个持久节点都可以有子节点
  7. 任意一个节点的路径都是唯一的
  8. Znode树是维系在内存中 — 目的是为了快速查询
  9. Zookeeper不适合存储海量数据。原因:1)维系在内存中,如果存储大
    量数据会耗费内存 2) 不是一个存储框架而是一个服务协调框架
  10. Zookeeper会为每一次事务(除了读取以外的所有操作都是事务)分配一
    个全局的事务id —Zxid

Zookeeper的命令

  1. create /node01 “hello zookeeper” 在根节点下创建子节点node01并且赋值
    为hello zookeeper
  2. set /node01 “hi” 将node01的数据更新为hi
  3. get /node01 获取node01的数据
  4. ls / 查看根节点下的所有的子节点
  5. delete /node02 删除子节点,要求这个节点中没有子节点
  6. rmr /node01 删除node01及其子节点
  7. quit 退出客户端
  8. create -e /node02 ‘’ 表示在根目录下创建临时节点/node02
  9. create -s /node03 ‘’ 表示在根目录下创建持久顺序节
    点/node03000000000X
  10. create -e -s /node04 ‘’ 表示在根目录下创建临时顺序节点/node04000000000X

Zookeeper的节点类型

  1. 持久节点
  2. 临时节点:在客户端退出之后就自动删除
  3. 持久顺序节点
  4. 临时顺序节点

Zookeeper的节点信息

  1. cZxid - 全局分配的创建的事务id — 创建这个节点是Zookeeper的第n个操
    作 — 定义好之后就不变了
  2. ctime - 创建时间
  3. mZxid - 修改的事务id — 记录自己本身修改
  4. mtime - 修改时间
  5. pZxid - 表示子节点的变化的事务id — 记录直接子节点的创建或者删除
  6. cversion - 记录子节点变化次数
  7. dataVersion - 数据版本 — 记录当前节点的数据的变化次数
  8. aclVersion - acl版本 — 记录当前节点的acl的变化次数
  9. ephemeralOwner - 如果当前节点不是临时节点,那么这个属性的值为0;
    如果是临时节点,那么这个属性的值记录的是当前临时节点的session id
  10. dataLength - 数据长度 - 实际上是字节个数
  11. numChildren - 子节点个数

Zookeeper的API操作

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;

public class ZookeeperDemo {
	ZooKeeper zk;

	@Before
	public void connect() throws IOException, InterruptedException {
		CountDownLatch cdl = new CountDownLatch(1);
		// connectString - 连接地址+端口号
		// sessionTimeout - 会话超时时间 - 表示连接超时时间,单位默认为毫秒
		// watcher - 监控者 - 监控连接状态
		// Zookeeper本身是一个非阻塞式连接
		zk = new ZooKeeper("117.50.90.232:2181", 5000, new Watcher() {

			// 监控连接状态
			public void process(WatchedEvent event) {

				if (event.getState() == KeeperState.SyncConnected) {
					System.out.println("连接成功~~~");
				}
				cdl.countDown();
			}
		});
		cdl.await();

	}

	// 创建节点
	@Test
	public void create() throws KeeperException, InterruptedException {
		// path - 节点路径
		// data - 数据
		// acl - acl策略
		// createMode - 节点类型
		// 返回值表示节点的实际路径
		String str = zk.create("/node08", "hello,1807".getBytes(), Ids.OPEN_ACL_UNSAFE,
				CreateMode.PERSISTENT_SEQUENTIAL);
		System.out.println(str);

	}

	// 删除节点
	@Test
	public void delete() throws InterruptedException, KeeperException {

		// path - 节点路径
		// version - 数据版本
		// 在删除节点的时候回比较指定的数据版本和节点的实际数据版本是否一致
		// 如果一致则删除,如果不一致则放弃该操作
		// zk.delete("/node04", 0);
		// -1表示强制执行
		zk.delete("/node04", -1);

	}
	
	// 更新数据
	@Test
	public void set() throws KeeperException, InterruptedException{
		// path - 节点路径
		//data - 数据
		// version - 数据版本
		// 返回节点信息
		Stat s = zk.setData("/node02", "hi,zk".getBytes(), -1);
		System.out.println(s);
	}
	
	// 获取节点的数据
	@Test
	public void get() throws KeeperException, InterruptedException, UnsupportedEncodingException {
		
		// path - 节点路径
		// watch - 监控
		// stat - 节点信息
		Stat s =  new Stat();
		byte[] data = zk.getData("/node01", null, s );
		System.out.println(new String(data, "utf-8"));
		
	}
	
	// 判断节点是否存在
	@Test
	public void exist() throws KeeperException, InterruptedException{
		
		// path - 节点路径
		// watch - 监控者
		// 返回的节点的信息
		Stat s = zk.exists("/node07", null);
		System.out.println(s);
	}
	
	// 获取子节点
	@Test
	public void getChidren() throws KeeperException, InterruptedException {
		
		// path - 节点路径
		// watch - 监控者
		// 返回子节点的路径
		List<String> nodes = zk.getChildren("/" ,null);
		for (String p : nodes) {
			System.out.println(p);
		}
	}

}

Zookeeper的集群安装

  1. 关闭防火墙
  2. 安装jdk
  3. 下载Zookeeper的安装包
  4. 解压Zookeeper的安装包
  5. 进入Zookeeper的安装目录中conf目录
  6. 将zoo_sample.cfg复制为zoo.cfg
  7. 编辑zoo.cfg,修改dataDir属性:
    dataDir=/home/software/zookeeper-3.4.8/tmp
    server.1=10.9.162.133:2888:3888 # 1是编号,要求每一个节点的编号是数
    字且不重复;
    server.2=10.9.152.65:2888:3888 #2888,3888是端口号,只要不和已经占用
    的端口号冲突即可
    server.3=10.9.130.83:2888:3888
  8. 创建存储数据的目录
  9. 进入数据存储目录
  10. 编辑文件myid, 将当前机器的编号写到myid中
  11. 将配置好的Zookeeper的安装目录拷到其他集群主机中:scp -r
    zookeeper-3.4.8 10.9.130.83:/home/software/
  12. 根据指定的编号修改对应的myid

在Zookeeper集群中,单独启动一台主机是不对外提供服务的
Zookeeper在使用过程中,会进行选举,选举出主节点-leader,其他的节点
就会成为从节点-follower

Zookeeper的选举

第一阶段:数据恢复阶段
会从数据目录(dataDir)中恢复数据

  1. 所有的节点都会推荐自己当leader并且发送自己的选举信息(最大事务
    id - pZxid,编号 - myid,逻辑时钟值)
  2. 选举原则:先比较最大事务id,谁的事务id大谁就胜出;如果最大事务id
    一样,则比较myid,谁的myid大谁就胜出
  3. 选举出的leader的胜出要满足过半性:即要比至少一半的节点大
  4. 如果在集群中新加入一个节点,节点的事务id比leader的事务id大,新的
    节点是否会成为leader? — 不会。只要选定了一个leader,那么后续节点
    的事务id和myid无论是多少,一律都是follower
  5. 如果leader宕机,集群中会自动选举一个新的leader
    第二阶段:选举阶段

如果超过一半的服务器宕机,那么此时Zookeeper不再对外提供服务 — 过
半性

01 02 03 => 02成为leader
01 03 02 => 03成为leader

节点的状态

  1. Looking - 选举状态
  2. follower - 追随者
  3. leader - 领导者
  4. observer - 观察者
    Zookeeper的投票是ZAB协议。ZAB是2PC协议的基础上来进行的延伸。
    2PC:将节点分为了协调者和参与者。当来一个请求的时候,协调者是将请
    求分发给每一个参与者,如果所有的参与者决定执行这个请求,那么协调者
    就真正提交操作,有参与者执行,参与者在执行完成之后返回Ack表示执行
    成功。如果协调者将请求分发给每一个参与者之后,有一个或者多个参与者
    不同意执行或者是没有返回消息,那么将这个操作回滚,不执行 — 一票否

    在Zookeeper中,接收一个请求之后,leader会将请求分发给每一个节点,由
    所有的节点投票确定是否执行这个请求 — 如果有超过一半的节点同意执行
    这个请求,那么这个时候leader才会决定执行这个操作

过半性:

  1. 选举leader的要满足过半性
  2. 请求操作也要满足过半性
  3. 过半集群才能对外提供服务 — 防止脑裂 — 脑裂:集群中产生2个及以
    上的leader — 一般将集群节点设置为奇数

观察者

执行操作,但是不参与选举和投票。

  1. 12个观察者宕机,依然对外提供服务
  2. 4个follower宕机,不对外提供服务
    21个节点 — 14个观察者,6个follower以及1个leader
    观察者不参与投票,所以就不影响集群的运行状态 — 适用于网络不稳定的
    情况
    在这里插入图片描述
    找到要设置为观察者的主机,编辑zoo.cfg,添加:peerType=observer,再在
    要设置的主机之后添加observer标记,例如:server.3=
    10.9.130.83:2888:3888:observer,然后重新启动这一个节点

上一篇 2.大数据学习之旅——红黑树

猜你喜欢

转载自blog.csdn.net/qq_39188039/article/details/86219343