HADOOPHA场景下,即使Active节点发生故障,系统也不会自动触发从Active到Standby的故障转移。
需要进行手动的故障转移。...
HADOOPHA场景下,即使Active节点发生故障,系统也不会自动触发从Active到Standby的故障转移。
需要进行手动的故障转移。 手动故障转移显然不是我们所需要的解决方案。 为了实现自动故障转移,
需要引入两个新组件:ZooKeeper和ZKFailoverController(ZKFC)进程。
Apache ZooKeeper是一种高可用性服务,用于维护少量协调数据,通知客户端该数据的更改以及监视客户端
是否存在故障。自动故障转移的实现依赖于ZooKeeper来实现以下功能:
ZKFC是自动故障转移中的另一个新组件,是ZooKeeper的客户端,也监视和管理NameNode的状态。
每个运行NameNode的主机也运行了一个ZKFC进程,ZKFC负责:
1)健康监测:ZKFC使用一个健康检查命令定期地ping与之在相同主机的NameNode,只要该NameNode及时地回复
健康状态,ZKFC认为该节点是健康的。如果该节点崩溃,冻结或进入不健康状态,健康监测器标识该节点为非
健康的。
2)ZooKeeper会话管理:当本地NameNode是健康的,ZKFC保持一个在ZooKeeper中打开的会话。
如果本地NameNode处于active状态,ZKFC也保持一个特殊的znode锁,该锁使用了ZooKeeper对短暂节点的支持,
如果会话终止,锁节点将自动删除。
3)基于ZooKeeper的选举(word文档):如果本地NameNode是健康的,且ZKFC发现没有其它的节点当前持有znode锁,
它将为自己获取该锁。如果成功,则它已经赢得了选举,并通过RPC将它的本地NameNode的状态置为active。
必要时对先前的Active进行隔离(Fence),然后本地NameNode转换为活动状态。
注意:
1)DN同时向active和standby发送心跳和块报告
2)ACTIVE NN将操作记录写到自己的edit log ,同时将edit log写入JN集群。每个JN都会写。
3)STANDBY NN:?同时接收JN集群的日志(随机选个写入成功的JN节点读),重演edits log操作,使得自己的元数据和active nn节点保持一致。
4)在激活新的Active NN之前,会对旧的Active NN进行隔离操作防止脑裂。(kill掉)
a.下载zookeeper3.4.6.tar.gz 通过挂载盘上传
b.解压至【/home/crx/soft】
进入soft文件夹下解压
[crx@master soft]$ tar -zxvf zookeeper-3.4.6.tar.gz
c.创建软连接:ZOOKEEPER_HOME/bin:$PATH
[crx@master ~]$ source ~/.bash_profile
e.进入安装目录:/home/crx/soft/zookeeper-3.4.6/conf
复制一份 zoo_sample.cfg 为zoo.cfg
[crx@master conf]$ cp zoo_sample.cfg zoo.cfg
修改【{ZOOKEEPER_HOME}/conf/zoo.cfg】zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper
clientPort=2181
f.开启zookeeper Server
$>zkServer.sh start
$>jps
5914 QuorumPeerMain //QuorumPeerMain:zookeeper Server的守护进程
5931 Jps
g.客户端连接:
$>zkCli.sh -server 127.0.0.1:2181
5988 ZooKeeperMain //ZooKeeperMain:zookeeper client的守护进程
$>quit 退出客户端
h.关机Zookeeper Server
$>zkServer.sh stop
i.查看:zookeeper.out /home/crx/tmp/zookeeper
1.zookeeper集群模式:
a.[修改zoo.cfg文件]:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper
clientPort=2181
server.1=master:2888:3888
server.2=slave1:2888:3888
server.3=slave2:2888:3888
b.在/home/crx/tmp/zookeeper目录下,创建myid文件
scp -r zookeeper-3.4.6 crx@slave1:~/soft/
[crx@master soft]$ scp -r zookeeper-3.4.6 crx@slave2:~/soft/
分别创建zookeeper软链接 ln -s zookeeper-3.4.6 zookeeper
d.复制dataDir=/home/crx/tmp/zookeeper
$> scp -r ~/tmp/zookeeper/ crx@slave1:~/tmp/
$> scp -r ~/tmp/zookeeper/ crx@slave2:~/tmp/
e.复制环境变量
$> scp ~/.bash_profile crx@slave1:~/
$> scp ~/.bash_profile crx@slave2:~/
f.修改myid文件
slave1进入到zookeeper目录下创建myid 内容为2
slave2进入到zookeeper目录下创建myid 内容为3
分别三个节点启动【master slave1 slave2】zkServer.sh start
分别查看状态:
[crx@master conf]$ zkServer.sh status
[crx@slave1 conf]$ zkServer.sh status
[crx@slave2 conf]$ zkServer.sh status
启动集群查50070 , 测试kill -9 active所在的节点
【修改hdfs-site.xml】
dfs.ha.automatic-failover.enabled
true
【修改core-site.xml】
ha.zookeeper.quorum
master:2181,slave1:2181
将配置文件同步至所有节点:
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/hdfs-site.xml crx@slave1:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/hdfs-site.xml crx@slave2:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/core-site.xml crx@slave1:~/soft/hadoop/etc/hadoop/
[crx@master ~]$ scp -r ~/soft/hadoop/etc/hadoop/core-site.xml crx@slave2:~/soft/hadoop/etc/hadoop/
3.格式化zk
分别将所有节点的zkServer开启
[crx@master ~]$ zkServer.sh start
[crx@slave1 ~]$ zkServer.sh start
[crx@slave2 ~]$ zkServer.sh start
如果手动管理群集上的服务,则需要在运行NameNode的每台计算机上手动启动zkfc守护程序。
您可以通过运行以下命令来启动守护程序:
[hdfs] $ $ HADOOP_PREFIX / sbin / hadoop-daemon.sh --script $ HADOOP_PREFIX / bin / hdfs start zkfc
实例化hadoop和zookeeper的状态(让它们两个认识,一定要先开启zkServer)
[master]$>hdfs zkfc -formatZK
说明:将在Zookeeper的树状节点上注册一个Znode
4.确保zookeeper集群是开启状态:
$>jps
5458 QuorumPeerMain
5.start-dfs.sh
注意:nn1和nn2均要配置相同的无密登录;!!!!!!
6.测试:
将active的节点kill掉,查看另一个节点状态;
[crx@master hadoop]$ jps
16352 NameNode
16711 DFSZKFailoverController
16776 Jps
16203 JournalNode
16476 DataNode
12543 QuorumPeerMain
[crx@master hadoop]$ kill -9 16711
守护进程的说明:
5458 QuorumPeerMain 【zookeeper Server端】
7715 Jps 【java进程】
7626 DFSZKFailoverController 【ZKFC:设置自动故障转移】
7324 JournalNode 【QJM:日志节点进程】
7405 NameNode 【名称节点】
6015 DataNode 【数据节点】
以一个简单的例子来说明整个选举的过程.
假设有五台服务器组成的zookeeper集群,它们的id从1-5,同时它们都是最新启动的,也就是没有历史数据,
在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么.
集群服务器宕掉的情况, 半数以上服务器宕机代表zookeeper服务器宕机
例如我们集群服务器有3台, 其中有一台zkServer宕机,那么整个ZK还是可以服务的
如果2台服务器,1台宕机是就是不可用的
案例演示 分别启动zkServer.sh start(master slave1 slave2)
1.查看选举状态zkServer.sh status(分别三台节点查看)
2.jps查看leader的状态 kill掉leader所在的节点
3.再次查看 slave2应该是leader
4.再次启动slave1的zkServer.sh start 它只能当小弟了
搭建zookeeper伪分布模式,采用了多线程的方式来模拟分布式环境
a.创建zoo*.cfg配置文件【创建三个文件:分别为5,6,7】
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/crx/tmp/zookeeper/data*
clientPort=218*
server.5=master:2888:3888
server.6=master:2889:3889
server.7=master:2890:3890
注:在【/home/crx/tmp/zookeeper/data*】目录下创建对应的myid文件
b.开启server端:
$>zkServer.sh start zoo*.cfg
c.开启客户端连接zookeeper集群:
$>zkCli.sh -server master:2181,master:2182,master:2183
***集群模式下,首先开启Zookeeper集群
1.创建永久节点,不加s和加s的区别,序号
[zk: master:2181(CONNECTED) 1] create /aaa1 helloword
Created /aaa1
[zk: master:2181(CONNECTED) 2] ls /
[zookeeper, aaa1, hadoop-ha]
[zk: master:2181(CONNECTED) 3] create -s /aaa2 helloword2
Created /aaa20000000023
2.zookeeper当中不能往znode中去追加内容,只能覆盖
set /aaa20000000023 newwords
3.创建临时znode (临时节点不能有子节点)
create -e /path data
4.删除znode(删除znode时,不能有子znode,需要先删除子znode再删除父znode)
delete /path
5.rmr 删除所有znode,可以包含子路径
ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。
① 临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,
当然可以也可以手动删除。虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。
另外,ZooKeeper的临时节点不允许拥有子节点。
② 永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
顺序节点
当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。
这个计数对于此节点的父节点来说是唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。
当计数值大于232-1时,计数器将溢出。
观察
客户端可以在节点上设置watch,我们称之为监视器。
当节点状态发生改变时(Znode的增、删、改)将会触发watch所对应的操作。
当watch被触发时,ZooKeeper将会向客户端发送且仅发送一条通知,
因为watch只能被触发一次,这样可以减少网络流量。
监听/path下的变化
stat /path true
****运行项目报错 ****
1.将log4j.properties拷贝到项目下,路径不能放错
2.将hadoop jar包引入项目下
// zk.create("/ccc2", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// zk.create("/ccc2", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
// zk.create("/ccc3", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
// zk.create("/ccc4", “hellowordccc”.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
// Thread.sleep(10000L);
// zk.setData("/ccc1", "new ccc2 ".getBytes(), 1);
// List paths = zk.getChildren("/ccc1", null);
// for(String path : paths) {
// System.out.println(path);
// }
// zk.delete("/ccc1", -1);
// List paths = zk.getChildren("/ccc1", null);
// for(String path : paths) {
// zk.delete("/ccc1/"+path, -1);
// }
// zk.delete("/ccc1", -1);
实现观察者要么事先接口, 要么内部类
watcher(观察者 案例) zk客户端连接服务端触发一次事件(构造函数连接zk的服务端), 所以执行一次process