zookeeper第二课-环境搭建和使用,用途分析

此次实验选用4台机器node1,node2,node3,node4
四台机器分别需要安装jdk,并设置JAVA_HOME的环境变量。

环境搭建

node01:
在zookeeper.apache.org下载zookeeper

wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.7/apache-zookeeper-3.5.7.tar.gz

解压

tar xf zookeeper.*.tar.gz
mkdir  /opt/bigdata/zookeeper
mv  zookeeper-3.4.7  /opt/bigdata

复制一份zookeeper配置并命名为zoo.cfg(因为zookeeper默认会使用这个名称)

cd zookeeper/conf
cp zoo.sem*.cfg   zoo.cfg

编辑zoo.cfg

vi zoo.cfg
# The number of milliseconds of each tick
tickTime=2000  #主从心跳间隔
# The number of ticks that the initial
# synchronization phase can take
initLimit=10 #初始同步阶段,主机可以容忍从机延迟的时间是  tickTime*initLimit
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5 #在主机向从机发送请求和获取从机确认的可以容忍的最大时间是 tickTime*syncLimit
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/var/bigdata/hadoop/zookeeper #数据存储路径
# the port at which the clients will connect
clientPort=2181 #客户端连接zookeeper的端口号
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60 #允许最大连接数
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

#写入zookeeper所有的实例的信息
#server.id id号越大,权重越大,在选主的时候,zookeeper是谦让制,会优先让给权重值最大的
server.1=dream01:2888:3888  # 2888是各从节点与主节点通信的端口,3888是当主节点挂掉时,幸存的从节点进行选举主节点的端口
server.2=dream02:2888:3888
server.3=dream03:2888:3888
server.4=dream04:2888:3888

每一台实例都要在存储数据的目录创建一个myid的文件,在里面写入自己对应的在配置文件里的权重id号:

mkdir -p /var/bigdata/hadoop/zookeeper
echo 1 >  /var/bigdata/hadoop/zookeeper/myid #此处node1写入1,node2的话就是写入2

拷贝node1的zookeeper文件分别分发到2,3,4节点:

cd /opt/bigdata
scp -r ./zookeeper/  dream02:`pwd`
scp -r ./zookeeper/  dream03:`pwd`
scp -r ./zookeeper/  dream04:`pwd`

然后,在node02~node04 分别创建 myid,并写入自己的权重id。
在node01,02,03,04分别进行配置zookeeper的环境变量:

vi /etc/profile

然后添加:

export ZOOKEEPER_HOME=/opt/bigdata/zookeeper
export PATH=$PATH:$ZOOKEEPER_HOME/bin

刷新环境变量:

. /etc/profile

至此,环境搭建就完成了。

使用zkServer.sh在四台进行启动zookeeper。
zookeeper默认是后台启动,这里为了实验方便,需要指定参数start-foreground 就可以阻塞前台启动了

zkServer.sh   start-foreground

这里抛出一个问题:如果四台都启动了zookeeper,那么会是谁是leader呢?
你可能会觉得根据我上述说的,谁的权重值最大谁就是leader。
那我们来试一下:

[root@dream03 ~]# zkServer.sh  status
JMX enabled by default
Using config: /opt/bigdata/zookeeper/bin/../conf/zoo.cfg
Mode: leader

我们发现,节点3成为了leader。
为什么呢? 是我说错了吗?
谁的权重值最大谁就是leader,这句话没有错。
但是要考虑一个前提,zookeeper是过半选举机制的,也就是一共4台,当有3台启动的时候就过半了,就已经可以推举出leader了,此时就是3。
而4再启动,也不会重新选主了。

zookeeper的初体验

随便连入一个zookeeper的实例:

[root@dream03 ~]# zkCli.sh 

看看有哪些操作:

[zk: localhost:2181(CONNECTED) 5] 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

create: 创建一个数据节点

[zk: localhost:2181(CONNECTED) 3] create /zk_test ""
Created /zk_test
[zk: localhost:2181(CONNECTED) 6] create /zk_test/haha "haha"
Created /zk_test/haha

set:设置某个path的值

[zk: localhost:2181(CONNECTED) 3] set /zk_test "zk_test_update"

ls: 查看当前指定路径节点的子节点列表

[zk: localhost:2181(CONNECTED) 7] ls /zk_test 
[haha]

get:查看当前节点的详细信息:

[zk: localhost:2181(CONNECTED) 8] get /zk_test/haha
"haha"
cZxid = 0x3d00000006 #创建事务id,这是一个64位的数,低32位存储全局事务操作递增id号(新增修改等操作都会递增该值),高32位记录纪元号,也就是当前是第几代leader
ctime = Sun Mar 01 00:09:52 CST 2020
mZxid = 0x3d00000006 #修改事务id,同上
mtime = Sun Mar 01 00:09:52 CST 2020
pZxid = 0x3d00000006 #当前节点下创建的最后一个子节点的创建事务id号
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0 #归属的sessionid,只有临时节点才会有值,值为创建该临时节点的那个客户端的sessionid
dataLength = 6
numChildren = 0

因为zookeeper的所有操作都会有顺序的转交到leader节点进行操作,而leader作为一个单节点,维护一个递增的事务id号是比较容易的。所以每个操作会给绑上一个全局的事务id号

session与临时节点

当我们一个客户端连接zookeeper后,可以看到leader的控制台打印:

2020-03-01 00:30:12,001 [myid:3] - INFO  [ProcessThread(sid:3 cport:-1)::PrepRequestProcessor@494] 
- Processed session termination for sessionid: 0x37091ab7bab0000

然后zookeeper中其实节点是分为两种的:永久节点和临时节点。
永久节点自然是不用说了,创建了就一直存在着。
临时节点是啥呢? 其实临时节点是与客户端的一次连接会话是挂钩的,伴随着客户端的离去,临时节点也会消失。

此时我们基于这个连接,进行创建一个临时节点:
create命令加上“-e”代表此时要创建的就是一个临时节点:

[zk: localhost:2181(CONNECTED) 1] create -e /zk_test/balala ""
Created /zk_test/balala

查看该节点:

[zk: localhost:2181(CONNECTED) 3] get /zk_test/balala 
""
cZxid = 0x3d00000009
ctime = Sun Mar 01 00:30:58 CST 2020
mZxid = 0x3d00000009
mtime = Sun Mar 01 00:30:58 CST 2020
pZxid = 0x3d00000009
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x37091ab7bab0001 #发现与当前创建该节点的sessionid一致
dataLength = 2
numChildren = 0

基于一致性视图,此时再打开另外一个客户端,发现依然可以获得这个临时节点:

[zk: localhost:2181(CONNECTED) 0] get /zk_test/balala
""
cZxid = 0x3d00000009
ctime = Sun Mar 01 00:30:58 CST 2020
mZxid = 0x3d00000009
mtime = Sun Mar 01 00:30:58 CST 2020
pZxid = 0x3d00000009
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x37091ab7bab0001
dataLength = 2
numChildren = 0

但此时创建该节点的客户端退出,观察leader,发现回收了sessionid:

2020-03-01 00:33:29,399 [myid:3] - INFO  [ProcessThread(sid:3 cport:-1)::PrepRequestProcessor@494] 
- Processed session termination for sessionid: 0x37091ab7bab0001

再在刚打开的客户端上尝试获取临时节点,发现已经没了:

[zk: localhost:2181(CONNECTED) 1] get /zk_test/balala
Node does not exist: /zk_test/balala

sessionid与一致性视图

每次客户端建立连接时,leader都会为其分配一个sessionid,并根据一致性视图的特点,会将sessionid广播给其他的节点。
session的创建与销毁(客户端的连接和退出)都算是一个事务操作,因此都会使得事务id递增。

可以验证一下,创建一个节点,然后查看它的cZxid :0x3d0000000c

[zk: localhost:2181(CONNECTED) 7] create /zk_test/ba ""
Created /zk_test/ba
[zk: localhost:2181(CONNECTED) 8] get /zk_test/ba      
""
cZxid = 0x3d0000000c
ctime = Sun Mar 01 00:50:02 CST 2020
mZxid = 0x3d0000000c
mtime = Sun Mar 01 00:50:02 CST 2020
pZxid = 0x3d0000000c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0

然后开启一个新的客户端连接,什么也不做。
然后再创建一个节点:

[zk: localhost:2181(CONNECTED) 9] create /zk_test/ba2 ""
Created /zk_test/ba2
[zk: localhost:2181(CONNECTED) 10] get /zk_test/ba2      
""
cZxid = 0x3d0000000e
ctime = Sun Mar 01 00:50:35 CST 2020
mZxid = 0x3d0000000e
mtime = Sun Mar 01 00:50:35 CST 2020
pZxid = 0x3d0000000e
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 2
numChildren = 0

发现cZxid = 0x3d0000000e,c直接到e了,中间少了一个d, d就是用来去创建新sessionid的创建了。

结合上述两点sessionid与一致性视图以及临时节点的关系,抛出一个问题:

如果当一个客户端连接的某个zookeeper的服务节点发生故障宕机了,
但这个客户端本地保存了此次请求时生成的sessionid,此时快速去基于这个sessionid去连接另外一个存活的节点(使用API连接zookeeper可以实现指定sessionid),
那这个session状态会丢失吗,或者说它创建的临时节点还存在吗?

其实是还存在的:
首先基于一致性视图,随着一个客户端连接的建立,一个sessionid在生成时,它的状态会广播到每一台现存的节点上,在此期间,其创建的临时节点也可以被所有节点查看到。
其次,临时节点其实不是对应session会话下线就立马删除的。
其实是会有一个失效时间的,当超过指定时间,若还没有sessionid对应的连接连入,这个临时节点才会被删除。
而这个session状态因为每一台节点都有保存,因此只要客户端可以以之前的sessionid随便连入任何一台,就可以完成续命
因此,只要保证能在失效之前成功续命,那么也依旧是在其他节点访问到临时节点的。

序列节点

序列节点并非是一种独立存在的节点,更像是一种规则。
因此永久节点和临时节点都可以是一个序列节点。
那啥是序列节点?
不得不先说一下, zookeeper毕竟是一个分布式下生存的服务,自然避免不了分布式下的命名问题,
也就是假如多个人在一个路径下想要创建节点的时候,是很有可能造成数据节点名称重复的。
不光是zookeeper,任何的分布式都面临这样的问题,解决方案也有很多。
这里zookeeper的序列节点就是分布式下它选取的命名解决方案。
leader内部维护一个递增序列数,因为所有的写操作都是有顺序的打入leader的,所以可以就此解决分布式的命名问题。
当然leader维护的这个递增序列数,其他的节点也都是会同步持有的,所以不必担心leader挂掉后重新选举会造成这个数值丢失的问题。

通过create 指定“-s”来设置序列节点:

[zk: localhost:2181(CONNECTED) 0] create -s /zk_test/abc ""
Created /zk_test/abc0000000008
[zk: localhost:2181(CONNECTED) 1] create -s /zk_test/abc ""
Created /zk_test/abc0000000009

zookeeper的应用

结合我们已经学到的zookeeper知识,想一想结合它的特点功能,我们能做哪些事?

1、统一的配置管理

zookeeper的节点存储大小是1M,不要把zookeeper当成存储数据库,但我们可以把配置的一些信息存储在zookeeper的某个节点上,当一方修改了,另一方立马可以查看到变动后的内容。

2、分组管理

zookeeper的类文件系统的路径存储,使得我们可以对不同数据放入不同path下面,实现分组管理。

3、分布式统一命名解决方案

通过zookeeper的序列节点,我们困扰的分布式命名就得到了解决。

4、分布式同步

简单来说:通过临时节点,相比较redis的主从复制下作为分布式锁的复杂度,zookeeper利于自身特点,使用临时节点更加可以以比较轻松的方式完成分布式锁的实现。
进阶一些:如果我们的锁依托于一个父目录,并且这个目录的临时节点都具备序列节点的特征,那么我们可以使得一个目录下存在多把锁,完成队列式事务的锁。

5、分布式协调高可用

使用zookeeper可以用来协调其他应用服务集群中的高可用以及选主问题,例如hdfs也是主从模型的,
其中namenode就是其内部的主机角色,就是借助的zookeeper来协调完成namenode的选主和高可用:
在其指定目录通过创建临时节点,多个namenode谁先创建也即是抢到了锁,谁就是主机;
通过自己实现的ZKFC作为客户端,通过zookeeper监听先前创建的节点,当故障发生时,对其进行故障转移,实现高可用。

重事说三

谨记:zookeeper的节点存储大小是1M,一定不要把zookeeper当成存储数据库使用

谨记:zookeeper的节点存储大小是1M,一定不要把zookeeper当成存储数据库使用

谨记:zookeeper的节点存储大小是1M,一定不要把zookeeper当成存储数据库使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值