ZooKeeper入门(一)应用场景与安装搭建

一、ZooKeeper的应用场景
ZooKeeper的几个常用特性

1、节点唯一性,同一路径下节点名字是唯一的,且创建过程是原子性的。

2、临时节点,与手动删除时才消除的持久节点不同,临时节点是当创建它的会话断开则被删除。

3、watch机制,客户端可以对某一个节点的创建、修改、删除等事件进行注册watch,一旦该节点的事件发生则ZooKeeper会通知watch的客户端。

Zookeeper的应用场景以及如何实现
1、配置中心和注册中心

这俩放一起说,都是用了创建节点和节点watch。配置中心就是在ZooKeeper上创建一个节点比如/config,然后把配置项作为子节点写到/config节点下,使用配置的服务在启动的时候都来获取这个/config节点下的子节点也就是配置项,并且watch该节点的修改事件,这样当配置发生变化的时候,服务能够被通知然后重新获取配置项。

而注册中心相比配置中心多了一个健康检查的功能,先创建一个父节点比如/services/serviceName,然后服务提供者启动的时候在serviceName下边创建临时节点,比如使用ip:port这样的命名,这样服务消费者可以按照服务名来ZooKeeper获取该服务对应的服务地址列表了,且当服务提供者下线时、与ZooKeeper的连接断开,ip:port临时节点被删除(新的服务提供者上线则同理),watch父节点/services/serviceName的服务消费者收到通知,及时的获知最新的服务列表。

ZooKeeper作为注册中心来说的功能有些偏弱,实际生产上使用要在此基础上做比较多的二次开发。比如一般来说除了服务提供者下线服务不可达这种情况之外,比如服务线程池满、服务处于一个不可用状态,但这种情况下zk客户端与ZooKeeper的连接并未断开,服务消费者仍然认为服务是可用的,这样就没有达到及时屏蔽级联故障的目的。

2、分布式选主和分布式锁

这俩也很类似,用了节点唯一性和节点watch。

分布式锁就是使用锁的服务在与ZooKeeper建立连接的时候都watch某个父节点的变更事件,使用锁的时候去该父节点下创建一个代表锁的临时子节点比如/lock/locked,因为节点的唯一性,这时只有一个服务可以创建成功,则该服务执行所谓临界区业务逻辑,执行完以后删除该子节点,或者该服务此时崩溃、与ZooKeeper断开连接临时子节点也会删除。watch该子节点事件的其他服务会收到通知就可以重新通过尝试创建/lock/locked子节点的方式来重新竞争锁了。

服务实例之间选主的场景,服务实例启动的时候尝试去ZooKeeper上创建一个临时节点比如/master,节点唯一性保证只有一个服务实例会创建成功,创建成功说明自己是主服务,没创建成功说明已经有其他实例当选了master,此时获取到master实例并向/master注册watch,当master实例挂掉时、其与ZooKeeper的连接断开,其他watch该节点的实例收到ZooKeeper的通知,重新尝试创建/master临时节点来当选master。

这里的分布式选主是使用ZooKeeper集群的能力对另一个业务集群中的1个实例进行选主,本质上是这些实例来ZooKeeper上争抢创建一个临时节点来“抢主”。而ZooKeeper作为分布式集群内部的选主则是使用的ZAB协议进行的投票选举。注意不要混淆。

3、分布式唯一ID生成

用来在多个数据库之间生成主键ID,跨库的话用数据库自己的递增主键就不行了,如果让客户端自己用UUID生成倒是可以、但是UUID比较长浪费空间且无规律不是顺序的、对索引不友好。这时候可以用ZooKeeper来生成递增的唯一主键。利用ZooKeeper的顺序节点,比如在/seqName下创建顺序子节点,创建成功后返回节点即可得到顺序的主键了。

其他应用场景见官网介绍:ZooKeeper: Because Coordinating Distributed Systems is a Zoo (apache.org) ,真的是许多开源产品都用到了ZooKeeper的。

二、ZooKeeper安装与搭建
单机版:

超级简单,tar -xvf apache-zookeeper-3.6.3-bin.tar.gz解压缩,配置文件用给的sample弄一份:cp zoo_sample.cfg zoo.cfg,然后启动:

./zkServer.sh start

用./zkCli.sh测试一下:

创建节点、子节点、修改节点值、列出子节点、删除节点等。

[zk: localhost:2181(CONNECTED) 0] create /test testData
Created /test
[zk: localhost:2181(CONNECTED) 1] get /test
testData
[zk: localhost:2181(CONNECTED) 2] set /test testData2
[zk: localhost:2181(CONNECTED) 3] get /test
testData2
[zk: localhost:2181(CONNECTED) 4] ls /test
[]
[zk: localhost:2181(CONNECTED) 5] create /test/chd1 data1
Created /test/chd1
[zk: localhost:2181(CONNECTED) 6] ls /test 
[chd1]
[zk: localhost:2181(CONNECTED) 7] delete /test
Node not empty: /test
[zk: localhost:2181(CONNECTED) 8] delete /test/chd1
[zk: localhost:2181(CONNECTED) 10] delete /test
[zk: localhost:2181(CONNECTED) 11] ls /test
Node does not exist: /test

接下来看一下zoo.cfg配置文件:

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/tmp/zookeeper
# the port at which the clients will connect
clientPort=2181
# 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

## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true
集群搭建

这里在一个虚机上测试搭建3个节点组成的ZooKeeper集群,1主2从。

创建3个配置文件先,zoo1.cfg、zoo2.cfg、zoo3.cfg,其中zoo1.cfg内容如下:

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/zooData/zoo1
clientPort=2181
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

三个节点开放给客户端的端口分别是2181、2182、2183 (ZooKeeper启动以后不需要做对外开放ip的配置,直接通过服务器的外网IP进行telnent 2181端口就是通的,有比较大的安全隐患,后续生产环境需要配置防火墙或者为ZooKeeper配置安全校验机制acl)

创建三个myid文件:如下所示,路径与cfg文件里指明的保持一致,内容的话就是serverID,比如/usr/zooData/zoo1/myid里边的内容就是“1”。

[root@VM_0_11_centos usr]# pwd
/usr
[root@VM_0_11_centos usr]# tree zooData/
zooData/
|-- zoo1
|   `-- myid
|-- zoo2
|   `-- myid
`-- zoo3
    `-- myid

3 directories, 3 files

然后指定对应的配置文件启动这3个进程就可以了:

./zkServer.sh start ../conf/zoo1.cfg
./zkServer.sh start ../conf/zoo2.cfg
./zkServer.sh start ../conf/zoo3.cfg

启动好之后,分别看一下节点状态:

[root@VM_0_11_centos bin]# ./zkServer.sh status ../conf/zoo1.cfg 
ZooKeeper JMX enabled by default
Using config: ../conf/zoo1.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
[root@VM_0_11_centos bin]# ./zkServer.sh status ../conf/zoo2.cfg 
ZooKeeper JMX enabled by default
Using config: ../conf/zoo2.cfg
Client port found: 2182. Client address: localhost. Client SSL: false.
Mode: leader
[root@VM_0_11_centos bin]# ./zkServer.sh status ../conf/zoo3.cfg 
ZooKeeper JMX enabled by default
Using config: ../conf/zoo3.cfg
Client port found: 2183. Client address: localhost. Client SSL: false.
Mode: follower

可见server.2当选了leader,server.1和server.3作为follower,这符合我们的预期的结果。

测试一下:

./zkCli.sh -server localhost:2181
[zk: localhost:2181(CONNECTED) 7] set /test2 d2
[zk: localhost:2182(CONNECTED) 11] get /test2
d2

leader和follower都可以处理读请求,写请求的话follower会转发给leader处理。leader处理写请求,然后进行写log复制、同步等待超过半数节点处理成功之后才会返回给客户端成功,这也是ZooKeeper的特点。满足CP特性。

posted on 2022-02-09 15:19  肥兔子爱豆畜子  阅读(144)  评论(0编辑  收藏  举报

导航