淘先锋技术网

首页 1 2 3 4 5 6 7

1. Zookeeper入门

1.1 概述

Zookeeper就是一个协调者,它存储和管理着集群数据(是一个文件系统,此数据是各个节点的状态),并且当某个节点下线后,它负责通知客户端,告知集群状况(通知机制)。
所以我总结,Zookeeper = 文件系统 + 通知机制的框架。

1.2特点

①全局数据一致(各个节点的数据是一致的)。
②数据更新时,全部的节点更新成功才叫成功。
③去中心化集群,集群中只要有半数以上节点存活,Zookeeper集群就能正常服务。

1.3 数据结构

Zookeeper的数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称作一个ZNode。每一个ZNode默认能够存储1MB的数据,每个节点都可以通过其路径唯一标识。
好了,这里概念可能抽象,我来解释一下,每一个节点它是文件也是一个值,也就说它有文件的属性也有值的属性。

在这里插入图片描述

1.4 应用场景

其实Zookeeper的应用场景很多,我们在Hadoop入门里面就有一张框架图,Zookeeper它的位置大家记得的话,它是直接竖着的,所以说很多框架都会和Zookeeper交互。我就来说一下常用的场景:
①去中心化集群、协调出临时主机(当主机挂掉时再协调新的主机)(HA)
②提供主从结耦服务(Hbase,主机挂掉,短时间内从机不受影响)

2. Zookeeper的安装

本地安装部署

①拷贝Zookeeper安装包到Linux系统下
②解压到/opt/module目录下

[atguigu@hadoop102 software]$ tar -zxvf zookeeper-3.5.7.tar.gz -C /opt/module/

③修改环境变量

[atguigu@hadoop102 ~]$ vim /etc/profile.d/my_env.sh 
#JAVA_HOME
export JAVA_HOME=/opt/module/jdk1.8.0_212
export PATH=$PATH:$JAVA_HOME/bin

#HADOOP_HOME
export HADOOP_HOME=/opt/module/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin
#ZOOKEEPER_HOME
export ZOOKEEPER_HOME=/opt/module/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin

④将/opt/module/zookeeper/conf这个路径下的zoo_sample.cfg,拷贝一份为zoo.cfg;(我在进行这部操作之前将Zookeeper解压的名字改成了Zookeeper)

[atguigu@hadoop102 conf]$ cp zoo_sample.cfg zoo.cfg

修改zoo.cfg文件

[atguigu@hadoop102 zookeeper]$ vim zoo.cfg

修改内容如下:

dataDir=/opt/module/zookeeper/zkData

大家在这里注意到了,我们没有ZkData这个文件夹,所以需要创建一个ZkData文件夹

[atguigu@hadoop102 zookeeper]$ mkdir zkData

这个时候就可以启动Zookeeper了

[atguigu@hadoop102 ~]$ zkServer.sh start

查看一下启动状态

[atguigu@hadoop102 ~]$ jps
4352 NodeManager
4753 JobHistoryServer
75173 Jps
3388 DataNode
1773 QuorumPeerMain
3183 NameNode

启动客户端

[atguigu@hadoop102 ~]$ zkCli.sh

退出客户端

[zk: localhost:2181(CONNECTED) 0] quit

3.Zookeeper操作

3.1 分布式安装部署

1.集群规划
在hadoop102、hadoop103、hadoop104上面部署Zookeeper。
2. 配置服务器编号
我们之前创建了一个ZkData文件夹没有使用,现在我们需要在这个文件夹下面创建一个myid的文件

[atguigu@hadoop102 zkData]$ touch myid

编辑一下myid文件

[atguigu@hadoop102 zkData]$ vi myid
2

同步一下文件到hadoop103和hadoop104上面

[atguigu@hadoop102 zkData]$ xsync myid

分别将hadoop103和hadoop104上面的内容改为3和4。
3.配置zoo.cfg文件
打开zoo.cfg文件

[atguigu@hadoop102 conf]$ vim zoo.cfg

增加如下配置

dataDir=/opt/module/zookeeper/zkData
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

同步zoo.cfg文件
4.配置群起Zookeeper
我们在/opt/module/zookeeper/bin目录下创建一个脚本zk.sh

[atguigu@hadoop102 bin]$ mkdir zk.sh

添加如下内容

#!/bin/bash

if (($#==0))
then
   exit 1;
fi
for i in hadoop102 hadoop103 hadoop104
do
   echo "=====================  Starting zk in $i  ======================="
   ssh $i "zkServer.sh $1" 2> /dev/null
done

修改其具有执行权限

[atguigu@hadoop102 bin]$ chmod  +x zk.sh

3.2 客户端命令行操作

命令基本语法功能描述
help显示所有操作命令
ls path使用 ls 命令来查看当前znode的子节点 -w 监听子节点变化 -s 附加次级信息
create普通创建 -s 含有序列 -e 临时(重启或者超时消失)
get path获得节点的值 -w 监听节点内容变化 -s 附加次级信息
set设置节点的具体值
stat查看节点状态
delete删除节点
deleteall递归删除节点

启动客户端

[atguigu@hadoop102 ~]$ zkCli.sh

1.显示所有操作命令

2.显示当前znode中所包含的内容

[zk: localhost:2181(CONNECTED) 1] ls /
[abc0000000001, sanguo, zookeeper]

3.查看当前节点详细数据

[zk: localhost:2181(CONNECTED) 2] ls -s /
[abc0000000001, sanguo, zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x300000003
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 3

4.分别创建2个普通节点

[zk: localhost:2181(CONNECTED) 3] create /sanguo "jinlian"
Created /sanguo
[zk: localhost:2181(CONNECTED) 4] create /sanguo/shuguo "liubei"
Created /sanguo/shuguo

获取节点的值

[zk: localhost:2181(CONNECTED) 5] get /sanguo

5.创建短暂节点,退出客户端后就看不见了

[zk: localhost:2181(CONNECTED) 7] create -e /sanguo/wuguo "zhouyu"
Created /sanguo/wuguo
[zk: localhost:2181(CONNECTED) 3] ls /sanguo 
[wuguo, shuguo]

退出重启后在查看

[zk: localhost:2181(CONNECTED) 12] quit
[atguigu@hadoop104 zookeeper-3.5.7]$ bin/zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /sanguo
[shuguo]

6.创建带序号的节点

[zk: localhost:2181(CONNECTED) 2] create -s /sanguo/weiguo/xiaoqiao "jinlian"
Created /sanguo/weiguo/xiaoqiao0000000000
[zk: localhost:2181(CONNECTED) 3] create -s /sanguo/weiguo/daqiao "jinlian"
Created /sanguo/weiguo/daqiao0000000001
[zk: localhost:2181(CONNECTED) 4] create -s /sanguo/weiguo/diaocan "jinlian"
Created /sanguo/weiguo/diaocan0000000002

7.修改节点数据值

8节点的值变化监听
在104主机上注册监听/sanguo节点数据的变化

在103主机上修改/sanguo节点的数据

观察104主机上收到数据变化的监听

WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/sanguo

9.删除节点

[zk: localhost:2181(CONNECTED) 4] delete /sanguo/jin

10.递归删除节点

[zk: localhost:2181(CONNECTED) 15] rmr /sanguo/shuguo

11.查看节点状态

[zk: localhost:2181(CONNECTED) 17] stat /sanguo

3.3 API 操作

3.3.1 idea中maven环境搭建

1.创建maven工程
2。添加pom文件,将依赖添加进去

<dependencies>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
       </dependency>
       <dependency>
           <groupId>org.apache.logging.log4j</groupId>
           <artifactId>log4j-core</artifactId>
           <version>2.8.2</version>
       </dependency>
       <!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
       <dependency>
           <groupId>org.apache.zookeeper</groupId>
           <artifactId>zookeeper</artifactId>
           <version>3.5.7</version>
       </dependency>
   </dependencies>

在main目录下的resource目录下创建log4j.properties文件

log4j.rootLogger=INFO, stdout  
log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n  
log4j.appender.logfile=org.apache.log4j.FileAppender  
log4j.appender.logfile.File=target/spring.log  
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout  
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n  

3.3.2 创建Zookeeper客户端

接下来我们进行常规的API操作(增删查改)

public class ZookeeperClient {
   private ZooKeeper zooKeeper;
   @Before
   public  void before() throws InterruptedException, IOException {
       //创建对象
       zooKeeper = new ZooKeeper(
               "hadoop102:2181,hadoop103:2181,hadoop104:2181",
               2000,
               new Watcher() {
                   public void process(WatchedEvent watchedEvent) {
                       System.out.println("默认的回调函数");
                   }
               }
       );

   }
   @After
   public void after() throws InterruptedException {
       //关闭
       zooKeeper.close();
   }
   //增加一个节点
   @Test
   public void create() throws KeeperException, InterruptedException {
       //做事情
       zooKeeper.create("/abc",
               "ceshi".getBytes(),
               ZooDefs.Ids.OPEN_ACL_UNSAFE,
               CreateMode.PERSISTENT_SEQUENTIAL);
   }
   //修改节点的值
   @Test
   public void set() throws KeeperException, InterruptedException {
       zooKeeper.setData("/abc0000000001",
               "ceshiwanle".getBytes(),
               0);
   }
   //查看节点的值
   @Test
   public void get() throws KeeperException, InterruptedException, IOException {
       Stat stat = new Stat();
       byte[] data = zooKeeper.getData("/abc0000000001",
               true,
               stat);
       System.out.write(data);
       System.out.println();
   }
   //删除节点的值
   @Test
   public void delete() throws KeeperException, InterruptedException {
       zooKeeper.delete("/abc0000000001",1);
   }
}

4. Zookeeper 原理

4.1 节点类型

节点类型按照节点存储是否永久可以分为
持久化目录节点、临时目录节点
按照是否有序可以分为
有序节点、无序节点
二者组合为4种节点为
持久化有序节点、持久化无序节点、临时有序节点、临时无序节点

4.2 Stat结构体

结构名称说明
cZxid事务ID
mZxid最后事务更新的ID
pZxid最后事务更新的子节点
cversion子节点变化号,子节点修改次数
dataVersion数据变化次数
aclVersion访问控制列表的变化
dataLength数据长度
numChildren子节点数

4.3 监听器原理(ZAP)

(1)首先有一个主线程
(2)在主线程里面创建Zookeeper客户端,这时会创建两个线程(SendThread、EventThread),一个负责发送数据的变化(SendThread),一个负责监听数据的改变(EventThread)。
(3)通过EventThread线程将注册的监听事件发送给Zookeeper。
(4)在Zookeeper的监听器列表中将注册的监听事件添加到列表中。
(5)Zookeeper监听到数据有数据或节点路径变化,就会将这个消息发送给EventThread线程。
(6)EventThread线程内部调用了process方法。

4.4 选举机制

(1)半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper适合安装奇数台服务器。
(2)Zookeeper虽然是去中心化集群,没有指定的Master和Slave。但是,Zookeeper工作时,会通过投票机制,选举出leader,其他的节点则是follower。
(3)投票机制是根据服务器的zxid和myid的大小来判断的。zxid越大代表数据越新,这也符合Zookeeper集群中数据一致性。
简单的来看一下下图:

在这里插入图片描述

(1)服务器1启动,发起一次选举。服务器1投自己一票。此时服务器1票数一票,不够半数以上(3票),选举无法完成,服务器1状态保持为LOOKING;
(2)服务器2启动,再发起一次选举。服务器1和2分别投自己一票并交换选票信息:此时服务器1发现服务器2的ID比自己目前投票推举的(服务器1)大,更改选票为推举服务器2。此时服务器1票数0票,服务器2票数2票,没有半数以上结果,选举无法完成,服务器1,2状态保持LOOKING
(3)服务器3启动,发起一次选举。此时服务器1和2都会更改选票为服务器3。此次投票结果:服务器1为0票,服务器2为0票,服务器3为3票。此时服务器3的票数已经超过半数,服务器3当选Leader。服务器1,2更改状态为FOLLOWING,服务器3更改状态为LEADING;
(4)服务器4启动,发起一次选举。此时服务器1,2,3已经不是LOOKING状态,不会更改选票信息。交换选票信息结果:服务器3为3票,服务器4为1票。此时服务器4服从多数,更改选票信息为服务器3,并更改状态为FOLLOWING;
(5)服务器5启动,同4一样当小弟。

4.5 写数据流程

在这里插入图片描述

leader接收到写数据的请求,把这个请求通知给follow节点,follow节点投票表示同意,将同意信息返回给leader,leader在向各个follow节点提交信息,这个时候,各个节点开始写。

5.总结

Zookeeper给我的感觉整体来说就是个好人,嘘寒问暖,帮助他人,哈哈哈哈,暖男🙂