目录
- 1 zookeeper介绍
- 2 zookeeper的文件系统结构
- 3 zookeeper客户端操作(了解)
- zookeeper的集群角色
- zookeeper的过半原则:
- 集群启动时zookeeper投票
- 4 zookeeper数据模型
- 5 : zookeeper节点类型与属性(理解)
- 7 zookeeper特性!
- 8 watch监听机制(理解)
- ==9 : zookeeper典型应用!==
- 10 hadoop的高可用
1 zookeeper介绍
zookeeper就是动物管理员的意思,因为ta管理的服务都是大数据的相关组件,而大数据相关组件中很多服务都是利用动物作为吉祥物或者图标的,所以zookeeper起了这样的名字
zookeeper是分布式协调服务的开源框架,本质上是一个分布式的小文件存储系统
作用:解决分布式集群中应用系统的一致性问题
大数据服务集群工作的难点是什么?(多人协同工作的难点是什么?)
- 信息同步
- 工作的顺序
- 工作权限
- 投票选举
大数据集群的难点:
如何保证全局数据的一致性
例如: NameNode 发送一条指令给所有的DataNode,我怎样保证所有的服务都收到这个指令呢? 我怎样保证所有人收到多个指令的顺序一致呢?
zookeeper可以帮助大数据服务完成什么工作呢?
帮助集群进行全局数据一致性的保持
帮助集群进行投票选举
2 zookeeper的文件系统结构
- zookeeper的文件系统是树状结构的
- zookeeper中所有的文件路径必须从根目录写起,没有相对路径
- zookeeper中的每一个节点都是一个znode,znode中既可以存储数据也可以创建子节点
可以理解为我们的znode既可以作为文件,又可以 作为目录.- 每个节点存储数据的大小最大为1M,但是在开发中我们根本用不了这么大空间
3 zookeeper客户端操作(了解)
前提条件: 已搭建好了zookeeper服务
① 修改配置文件(node1,node2,node3都要修改)
vim /etc/profile
# 在开启问文件的末尾书写如下内容:
# ZOOKEEPER_HOME
export ZOOKEEPER_HOME=/export/server/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin
# 使用source进行配置文件的激活
source /etc/profile
② 开启zookeeper的服务端(必须三台都启动)
开启服务:zkServer.sh start
查询服务状态:zkServer.sh status
关闭服务:zkServer.sh stop
[root@node1 ~]# zkServer.sh start
JMX enabled by default
Using config: /export/server/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@node1 ~]# zkServer.sh status
JMX enabled by default
Using config: /export/server/zookeeper/bin/../conf/zoo.cfg
Mode: leader
[root@node1 ~]# zkServer.sh stop
JMX enabled by default
Using config: /export/server/zookeeper/bin/../conf/zoo.cfg
Stopping zookeeper ... STOPPED
[root@node1 ~]# zkServer.sh status
JMX enabled by default
Using config: /export/server/zookeeper/bin/../conf/zoo.cfg
Error contacting service. It is probably not running.
主角色leader状态:
[root@node1 ~]# zkServer.sh status
JMX enabled by default
Using config: /export/server/zookeeper/bin/../conf/zoo.cfg
Mode: follower
98088 QuorumPeerMain 就是zookeeper进程
[root@node1 ~]# jps
87744 RunJar
87891 RunJar
92409 NodeManager
98088 QuorumPeerMain
91853 DataNode
91708 NameNode
92268 ResourceManager
98268 Jps
③ 开启客户端
开启本地客户端:zkCli.sh
[root@node1 ~]# zkCli.sh
Connecting to localhost:2181
远程链接其他服务客户端:zkCli.sh -server 服务器ip
[root@node1 ~]# zkCli.sh -server node2
Connecting to node2
zookeeper的集群角色
主角色: leader 管理者,负责管理所有的follower,是集群中唯一负责事务型请求的角色
从角色: follower 追随者 , 负责数据的非事务型请求,以及事务型请求的转发(发送给leader), 以及投票
辅助角色: observer 观察者, 和从角色负责的工作相同只是没有投票权和被投票权事务型请求: 写入操作,数据的增删改,
非事务型请求: 读取操作,数据的查询
- 向leader发送事务型请求,leader直接发送写入指令,如果写入成功的服务过半则证明写入成功,否则失败
- 如果向follower或者observer发送事务型请求会转发给leader进行事务型请求处理
- observer 和 follower 和leader 都可以响应非事务型请求
zookeeper的过半原则:
- 事务型请求成功过半则成功,失败过半则失败
- 集群投票如果其中一个服务获取票数过半则成功当选
- 集群服务中启动服务数量过半则集群可用,宕机服务数量过半则服务崩溃
zookeeper集群服务的数量一般都是单数,因为需要投票
集群启动时zookeeper投票
背景: 以有五台服务组成的zk集群为例, 启动node1-node5 五台服务,查看投票和当选结果
- node1启动,node1将票投给自己 node1: 1票
- node2启动,node2将票投给自己 node2: 1票 node1: 1票
- 改票环节, node2 比node1的id值大, 则 node1 将票转投给node2 node2 : 2票 node 1: 0票
- node3启动, node3将票投给自己 node3: 1票 node2 : 2票 node 1: 0票
- 改票环节,node3 比node1node2id值大,则node1 node2 将票投给 node3 : 3票, node2: 0票 node1: 0票
- node4启动,此时node3已经票数过半当选了,所以node4直接称为follower
- node5启动,此时node3已经票数过半当选了,所以node5直接称为follower
id值在哪里看呢:cat /export/server/zookeeper/zkdatas/myid
myid值越大越容易当选
[root@node3 ~]# cat /export/server/zookeeper/zkdatas/myid
3
4 zookeeper数据模型
zk服务的全部终端指令:
终端指令并不重要,主要是帮助大家验证zookeeper服务特性
[zk: node1(CONNECTED) 0] help
ZooKeeper -server host:port cmd args
stat path [watch]
set path data [version] # 修改节点数据值
ls path [watch] # 查询节点信息
delquota [-n|-b] path
ls2 path [watch]
setAcl path acl
setquota -n|-b val path
history
redo cmdno
printwatches on|off
delete path [version] # 删除节点
sync path
listquota path
rmr path
get path [watch] # 获取节点详细数据
create [-s] [-e] path data acl # 创建节点
addauth scheme auth
quit
getAcl path
close
connect host:port
每个znode都包含了一系列的属性,通过命令get /节点名,可以获得节点的属性
对于zk来说,每次的变化都会产生一个唯一的事务id,zxid(ZooKeeper Transaction Id)。通过zxid,可以确定更新操作的先后顺序。例如,如果zxid1小于zxid2,说明zxid1操作先于zxid2发生,zxid对于整个zk都是唯一的,即使操作的是不同的znode。
cZxid :Znode创建的事务id。
ctime :Znode创建时的时间戳.
mZxid :Znode被修改的事务id,即每次对当前znode的修改都会更新mZxid。
mtime :Znode最新一次更新发生时的时间戳.
pZxid :Znode的子节点列表变更的事务ID,添加子节点或删除子节点就会影响子节点列表
cversion :子节点进行变更的版本号。添加子节点或删除子节点就会影响子节点版本号
dataVersion:数据版本号,每次对节点进行set操作,dataVersion的值都会增加1(即使设置的是相同的数据),可有效避免了数据更新时出现的先后顺序问题。
aclVersion : 权限变化列表版本 access control list Version
ephemeralOwner : 字面翻译临时节点拥有者,持久节点值为0,非持久节点不为0(会话ID)
dataLength : Znode数据长度
numChildren: 当前Znode子节点数量(不包括子子节点)
5 : zookeeper节点类型与属性(理解)
节点按照持续时间分为两种:
永久节点: 保存成功后持续存在于zookeeper文件系统中
临时节点: 绑定创建节点的客户端,如果客户端断开连接,则节点销毁
节点按照序列化方式可以分为两种:
序列化节点: 在定义节点时,系统会在节点名称后自动添加一个不断自增的序列化编号
非序列化节点: 在定义节点时不会添加编号
所以自由组合后,节点一共有四种
永久序列化节点: create -s 节点名称 节点值
永久非序列化节点: create 节点名称 节点值
临时序列化节点: create -s -e 节点名称 节点值
临时非序列化节点: create -e 节点名称 节点值
临时节点和永久节点
[zk: node1(CONNECTED) 2] get /itcase_tmp
456
cZxid = 0xa00000013
ctime = Thur May 12 20:04:40 CST 2022
mZxid = 0xa00000013
mtime = Thur May 12 20:04:40 CST 2022
pZxid = 0xa00000013
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x1880e0846930003
dataLength = 3
numChildren = 0
[zk: node1(CONNECTED) 3] get /itcase
123
cZxid = 0xa00000012
ctime = Thur May 12 20:04:14 CST 2022
mZxid = 0xa00000012
mtime = Thur May 12 20:04:14 CST 2022
pZxid = 0xa00000012
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: node1(CONNECTED) 4]
ephemeralOwner = 0x1880e0846930003
临时节点会话地址ephemeralOwner = 0x0
永久节点会话地址
关闭node1中的连接,发现sessionid就是上边的会话地址
[zk: localhost:2181(CONNECTED) 21] close
2022-05-12 21:11:29,880 [myid:] - INFO [main:ZooKeeper@684] - Session: 0x1880e0846930003 closed
[zk: localhost:2181(CLOSED) 22] 2022-05-12 21:11:29,880 [myid:] - INFO [main-EventThread:ClientCnxn$EventThread@512] - EventThread shut down
此时临时节点itcast_tmp被销毁已关闭
结论: 每个临时节点都绑定了一个会话地址,如果临时节点绑定的会话(session)关闭或者销毁,则该节点也会随之被删除, 而永久节点的数据将会一致保留,与会话无关
每创建一个会话,会话地址都是重新随机分配的基本不可能重复.
序列化节点与非序列化节点
序列化节点创建时,可以创建多个同名节点,但是创建完成后,系统会自动在末尾添加编号
编号特点: 先创建的编号小, 后创建的编号大,小到大
[zk: localhost:2181(CONNECTED) 0] create -s /java 123
Created /java0000000003
[zk: localhost:2181(CONNECTED) 1] create -s /java 123
Created /java0000000004
[zk: localhost:2181(CONNECTED) 2] create -s /java 123
Created /java0000000005
[zk: localhost:2181(CONNECTED) 3] create -s /java 123
Created /java0000000006
[zk: localhost:2181(CONNECTED) 4] ls /
[java0000000004, java0000000005, java0000000003, zookeeper, itcase, java0000000006]
非序列化节点创建时不能创建同名节点
[zk: localhost:2181(CONNECTED) 5] create /python 111
Created /python
[zk: localhost:2181(CONNECTED) 6] ls /
[java0000000004, java0000000005, python, java0000000003, zookeeper, itcase, java0000000006]
[zk: localhost:2181(CONNECTED) 7] create /python 123
Node already exists: /python
[zk: localhost:2181(CONNECTED) 8]
7 zookeeper特性!
记住全局数据一致性即可
全局数据一致性是分布式协调服务的基础
为什么能够保证zookeeper中全局数据一致呢? 因为所有的数据,在zookeeper集群中的每一个服务中都保存了一份完整的数据.
可靠性: 因为集群中只有leader发号施令其他人都干活不说话
顺序性: 在zookeeper中所有的消息都是有序的
原子性: 更新数据时会返回成功回调,如果过半则成功,如果不过半则失败,失败后已经执行的数据进行回滚
实时性: 数据的成功或失败会立即返回结果
注意: 回滚就是恢复到指令执行之前的状态
8 watch监听机制(理解)
服务端: 运行在服务器后台,提供数据或连接服务的软件,就是服务端
客户端: 用户使用与服务端连接的工具就是客户端
举例:服务端: hdfs集群服务 客户端: hadoop fs -
服务端 hive服务 (metastore hiveserver2) 客户端: hive beeline什么叫做监听机制?
zookeeper客户端在服务端节点上创建一个监听,当服务端的节点发生变化时将会触发这个监听,将节点变化信息,发送给客户端,这种机制就是监听机制
zookeeper是客户端监听服务端
设置监听
get /itcast watch
使用另外一个客户端修改/itcast节点
set /itcast 444
zookeeper 是典型的发布订阅机制
客户端订阅数据
如果数据改变服务端发布通知
客户端接受到通知后查询数据或执行其他任务
在zookeeper中是客户端监听服务端
zookeeper监听的特点:
- 先监听后触发: 客户端需要先设置监听,服务端才可以触发监听
- 一次性触发: 触发监听后,客户端需要重新监听才能再次获取通知
- 异步监听: 设置监听后,客户端可以进行其他终端操作,如果监听被触发将会立即获得通知
- 通知内容: 使用了java中的event类,通知中可以获取节点位置,通知类型等数据
异步: 可以同时执行
同步: 一个一个排队执行
9 : zookeeper典型应用!
1.发布订阅机制
服务端可以将数据发布在zookeeper上,其他客户端或者服务可以订阅(监听)该数据节点,如果数据有更新,则会触发监听,客户端或服务会收到通知,收到通知后可以在zookeeper上获取最新数据
应用场景: 全局配置文件的统一管理
使用的技术: 监听机制
2. 集群选举功能(主备切换)
一般是用于主备结构的选举
启动服务时选举:
两台服务启动时其实是没有主备之分的
- 两台服务同时在zookeeper中注册相同名称的临时非序列化节点,如果注册成功了,就是主服务
- 如果注册不成功,自动变成备用节点,在主服务节点上设置监听
主服务崩溃时选举:
- 主服务宕机或失联后在zookeeper中创建的临时节点会自动销毁
- 给备用服务发送通知
- 备用服务在zookeeper中同样注册临时非序列化节点,此时备用服务变为主服务
- 原主服务重启后注册节点失败,设置监听后自动变为备用服务
应用场景: hdfs的主备切换, yarn的主备切换等
应用的技术: 监听, 临时节点, 节点唯一性
3.分布式锁
如果在分布式服务中多台服务器同时修改同一个数据可能造成数据混乱,此时就涉及到了资源竞争(资源抢夺)
方案一:
多个服务同时注册同名节点:
第一个服务抢到节点后操作数据,其余服务均不可操作,对于该节点注册监听
第一个服务执行完成后注销节点,其余节点继续抢注,依次类推.
方案二:
多个服务同时注册同名序列化节点:
按照注册的序列化节点编号从小到大依次执行任务,每个任务执行完成后才能执行下一个任务
应用场景 : 解决分布式集群中的资源竞争问题
应用的技术: 监听, 临时节点, 节点唯一性, 序列化节点
10 hadoop的高可用
高可用: 服务器出现单点故障问题后依然可以正常运行
单点故障: 在集群中,一台服务器出现宕机将会导致整个集群崩溃的现象叫做单点故障
eg: hdfs集群的单点故障发生在NameNode上, yarn集群的单点故障发生在ResourceManager
系统鲁棒性: 系统抵御异常的能力
如何解决集群服务中的单点故障问题??
使用主备集群架构,设置一主一备两个主服务,如果一个崩溃或宕机,则另一个立即替代
主备架构中,备用机需要满足哪些特性?
- 服务的功能和特性必须完全一致
- 主机和备用机要做到实时数据同步
- 主机崩溃或宕机要第一时间知道
备用机需要做到数据实时同步,所以在高可用集群中,就不需要类似SecondaryNameNode这种辅助元数据合并的角色了
zkfc的主要职责?
- 监控NameNode的健康状态
- 设置NameNode在zookeeper中的临时节点
- 如果创建节点时znode已经存在,则设置监听
- 保持和修改NameNode的状态(standby Active)
为什么要使用journal集群进行数据同步?可以使用单机服务作为备份服务么?
不可以使用单机服务进行数据同步,因为如果使用单机服务则这个服务将成为集群新的单点故障
集群服务中有冗余存储,不会因为个别服务崩溃而造成数据丢失
journalNode就是一个分布式文件存储系统,与hdfs不同的是他的重点不在于吞吐量的多少,而是在于安全且响应效率高.
journalnode中数据存储也是过半成功机制, 且如果文件有更新,会触发standby的监听,从而读取数据更新镜像journalnode备份的是所有的操作记录,也就是edits 不会备份fsimage
高可用Hadoop集群的集群规划
node4 . node5… 以后扩展的机器中只要有DataNode 和NodeManager即可,提供内存,cpu和磁盘存储资源
什么是脑裂现象,为什么要避免脑裂?
在集群中出现一个以上的主服务就是脑裂现象
在很多文献中没有主服务也属于脑裂
例如一个hdfs集群中, 没有NameNode 或者有两个NameNode都属于脑裂
此时集群数据将会混乱
高可用集群正常工作时的状态
HDFS高可用模式下的主备切换
yarn的高可用怎么处理呢?
- 启动两个ResourceManager服务
- 两个ResourceManager 抢注zookeeper节点,抢占成功则为主服务,失败则为备用服务,并注册监听
- yarn集群中需要持久化存储的数据非常少,只有ApplicationMaster的状态信息需要存储, 这个状态信息的数据量极小,所以我们可以使用zookeeper进行数据同步
- 主备切换时备用机收到zookeeper通知后自动注册节点,成为主机
注意: 不要忘记zookeeper也是分布式小文件系统
yarn的高可用其实不收关注,官方也是2.4.x版本以后才引入了yarn的高可用
- 因为yarn宕机后并不会丢失数据,只不过计算任务要从新执行,企业损失更小,且影响不大.
扩展: 在hadoop 2.x版本中高可用是一主一备的,而到了hadoop 3.x版本后支持一主多备
备用机和主机的性能都必须非常好,且备用机在备用期间其实是没有发挥自己的性能的,但是这个部分性能也必须存在,否则主备切换时无法胜任工作.
一主多备将会让企业的投资增大,成本不划算,在企业开发中基本都是一主一备,除非数据极其重要,或者企业及其有钱
举例:
一主一备 主备同时宕机的概率是多少?
主机宕机概率 0.3% 备用机宕机概率 0.3% 同时宕机概率 是 0.003*0.003 = 0.000009
一主二备 主备同时宕机的概率是多少?
主机宕机概率 0.3% 备用机宕机概率 0.3% 同时宕机概率 是 0.000009 * 0.003 …
成本提高了三分之一 但是安全性并没有提高多少 , 投资和回报不成正比