一:Zookeeper:
ZooKeeper最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题,所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。
关于"ZooKeeper"这个项目的名字,其实也有一段趣闻,在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的Pig项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家RaghuRamakrishnan(拉古-拉玛克里希南)开玩笑的说:“在这样下去,我们这儿就变成动物园了!”,此话一出,大家纷纷表示就叫动物园管理员吧。因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而ZooKeeper正好要用来进行分布式环境的协调,于是ZooKeeper的名字也就由此诞生了
二:ZooKeeper的使用场景
ZooKeeper是一个分布式服务框架,它主要使用来解决分布式应用中经常遇到的一些数据管理问题,如:命名服务、状态同步、配置中心、集群管理等。
2.1:命名服务:
命名服务是分布式系统中比较常见的一类场景。命名服务是分布式系统最基本的公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供的服务地址或远程对象等----这些我们都可以统称为名字(Name),其中较为常见的就是一些分布式服务框架(如RPC、RMI)中的服务地址列表,通过使用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供者的信息等。
2.1.1:状态同步:
每个节点除了存储数据内容和node节点和状态信息之外,还存储了已经注册的APP的状态信息,当有些节点或APP不可用,就将当前状态同步给其他服务。
2.1.2:配置中心:
现在我们大多数应用都是采用的是分布式开发的应用,搭建到不同的服务器上,我们的配置文件,同一个应用程序的配置文件一样,还有就是多个程序存在相同的配置,当我们配置文件中有个配置属性需要改变,我们需要改变每个程序的配置属性,这样会很麻烦的去修改配置,那么可以使用ZooKeeper来实现配置中心,ZooKeeper采用的是推拉相结合的方式:客户端向服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送Watcher时间通知,客户端接收到的消息通知后,需要主动到服务端获取最新的数据。
2.1.3:集群管理:
所谓的集群管理,包括集群监控与集群控制两大块,前者侧重对集群运行时状态的收集,后者则是对集群进行操作与控制,在日常开发和运维工作中,我们经常会有类似于如下的要求
希望知道当前集群中究竟有多少机器工作
对集群中每台机器的运行时状态进行数据收集
对集群中机器进行上下线操作
ZooKeeper具有一下两大特性。
客户端如果对ZooKeeper的一个数据节点注册Watcher监听,那么当该数据节点的内容或是其子节点列表发生变更时,ZooKeeper服务器就会向订阅的客户端发送变更通知。
对在ZooKeeper上创建的临时节点,一旦客户端与服务器之间的会话失效,那么该临时节点也就被自动清除。
Watcher(事件监听器),是ZooKeeper中的一个很重要的特性。ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是ZooKeeper实现分布式协调服务的重要特性
0 生产者启动
1 生产者注册到zookeeper
2 消费者启动并订阅频道
3 zookeeper通知消费者事件
4 消费者调用生产者
5 监控中心负责统计和监控服务状态
2.2:ZooKeeper单机安装:
单机版的ZooKeeper安装
2.2.1:配置java环境
https://zookeeper.apache.org/doc/r3.4.14/zookeeperAdmin.html#sc_requiredSoftware #官方依赖介绍
# yum install openjdk-8-jdk
# java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
2.2.2:部署ZooKeeper:
https://archive.apache.org/dist/zookeeper/ #官网下载地址
# tar xvf zookeeper-3.4.14.tar.gz
# ln -sv /usr/local/src/zookeeper-3.4.14 /usr/local/zookeeper
# cd /usr/local/zookeeper/conf/
# cp zoo_sample.cfg zoo.cfg
# grep ^[a-Z] zoo.cfg #当前配置
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181
2.2.3:启动ZooKeeper:
/usr/local/bin/zkServer.sh start
2.2.4:验证ZooKeeper进程:
2.2.3:验证ZooKeeper状态:
# /usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: standalone
2.3:ZooKeeper集群介绍:
ZooKeeper集群用于解决单点和单机性能及数据高可用等问题。
读写数据:http://www.sohu.com/a/253808097_465221
2.3.1:集群结构:
2.3.2:集群角色
角色 主要工作描述
1.事务请求的唯一调度和处理者, 保证集群事务处理的顺序性
领导者 2. 集群内部各服务器的调度者
跟随着(Follower) 1.处理客户端非事务请求,转发事 务请求给Leader服务器
2. 参与事务请求Proposal
学习者 3. 参与leader选举的投票
观察者(Observer) Follower和Observer唯一的区别在于Observer机器不参与Leader的选举过程, 也不参与写操作的"过半写成功"策略,因此Observer机器可以在不影响写性能的 情况下提升集群的读性能
客户端(client) 请求发起方
2.4:ZooKeeper集群部署:
ZooKeeper的集群部署过程。
zookeeper集群特性:整个集群中只要有超过集群数量一半的zookeeper工作节点是正常的,那么整个集群对外就是可用的,假如有2台服务器做了一个zookeeper集群,只要有任何一台故障或宕机,那么这个zookeeper集群就不可用了,因为剩下的一台没有超过集群一半的数量,但是假如有三台zookeeper组成一个集群,那么损坏一台还剩两台,大于3台的一半,所以损坏一台还是可以正常运行的,但是再损坏一台就只剩一台集群就不可用了。那么要是4台组成一个zookeeper集群,损坏一个集群肯定是正常的,那么损坏两台就还剩两台,那么2台不大于集群数量的一半,所以3台的zookeeper集群和4台zookeeper集群损坏两台的结果都是集群不可用,以此类推5台和6台以及7台和8台都是同理,所以这也就是为什么集群一般都是奇数的原因。
2.4.1:配置ZooKeeper集群:
各zookeeper服务器都配置java环境并部署zookeeper集群
服务器环境:
Zk-node1: 172.16.10.22
Zk-node2: 172.16.10.23
Zk-node3: 172.16.10.24
2.4.1.1:zk节点1部署过程:
官方文档:https://zookeeper.apache.org/doc/r3.4.14/zookeeperAdmin.html
# yum install -y openjdk-8-jdk
[root@mq-server1 conf]# java -verison #验证java版本
Unrecognized option: -verison
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
# pwd
/usr/local/src
# tar xf zookeeper-3.4.14.tar.gz
# ln -sv /usr/local/src/zookeeper-3.4.14 /usr/local/zookeeper #解决并对 zookeeper做软连接
# cd /usr/local/zookeeper/conf/
# cp zoo_sample.cfg zoo.cfg #基于模板配置文件生成配置文件
mkdir /data/zookeeper/data #创建数据目录
[root@mq-server1 conf]# grep -v "^#" zoo.cfg
tickTime=2000 #服务器与服务器之间的单次心跳监测时间间隔,单位为毫秒
initLimit=10 #集群中leader服务器与follow服务器初始链接心跳次数,及多少个2000毫秒
syncLimit=5 #leader与follower之间连接完成之后,后期监测发送和应答的心跳次数,如果该follower再设置的时间内(5*2000)不能与leader进行通信,那么此follower将被视为不可用。
dataDir=/data/zookeeper/data #自定以的zookeeper保存数据的目录
clientPort=2181 #客户端连接Zookeeper服务器的端口,Zookeeper会监听这个端口,接受客户端的访问请求
server.1=172.16.10.22:2888:3888 #server.服务器编号=服务器IP:LF数据同步端口:LF选举端口
server.2=172.16.10.23:2888:3888
server.3=172.16.10.24:2888:3888
maxClientCnxns=60 #单个客户端IP可以和zookeeper保持的连接数
autopurge.snapRetainCount=3 #3.4.0中的新增功能;启用后,ZooKeeper自动清除功能会将autopurge.snapRetainCount最新快照和相应的事务日志分别保留再dataDir和dataLogDir中,并删除其余部分,默认值为3.最小值为3.
autopurge.purgeInterval=1 #3.4.0 及之后版本,ZK提供了自动清理日志和快照文件的功能,这个参数指定了清理频率,单位是小时,需要配置一个1或更大的整数,默认为0,表示不开启自动清理功能。
# echo '1' > /data/zookeeper/data/myid #自己集群的id
scp zoo.cfg 172.16.10.22:/usr/local/zookeeper/conf/zoo.cfg #将配置文件分发至其他服务器
scp zoo.cfg 172.16.10.23:/usr/local/zookeeper/conf/zoo.cfg #将配置文件分发至其他服务器
2.4.1.2:zk节点2部署过程:
# yum install -y openjdk-8-jdk
[root@mq-server1 conf]# java -verison #验证java版本
Unrecognized option: -verison
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
# pwd
/usr/local/src
# tar xf zookeeper-3.4.14.tar.gz
# ln -sv /usr/local/src/zookeeper-3.4.14 /usr/local/zookeeper #解决并对 zookeeper做软连接
# cd /usr/local/zookeeper/conf/
# cp zoo_sample.cfg zoo.cfg #基于模板配置文件生成配置文件
[root@mq-server1 conf]# grep -v "^#" zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
clientPort=2181
server.1=172.16.10.22:2888:3888
server.2=172.16.10.23:2888:3888
server.3=172.16.10.24:2888:3888
# echo '2' > /data/zookeeper/data/myid #自己集群的id
2.4.1.3:zk节点3部署过程:
# yum install -y openjdk-8-jdk
[root@mq-server1 conf]# java -verison #验证java版本
Unrecognized option: -verison
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
# pwd
/usr/local/src
# tar xf zookeeper-3.4.14.tar.gz
# ln -sv /usr/local/src/zookeeper-3.4.14 /usr/local/zookeeper #解决并对 zookeeper做软连接
# cd /usr/local/zookeeper/conf/
# cp zoo_sample.cfg zoo.cfg #基于模板配置文件生成配置文件
[root@mq-server1 conf]# grep -v "^#" zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper/data
clientPort=2181
server.1=172.16.10.22:2888:3888
server.2=172.16.10.23:2888:3888
server.3=172.16.10.24:2888:3888
# echo '3' > /data/zookeeper/data/myid #自己集群的id
2.4.2:各服务器启动zookeeper:
各zookeeper服务器尽快启动zookeeper服务。
2.4.2.1:zk节点1启动zookeeper:
/usr/local/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
2.4.2.2:zk节点2启动zookeeper
/usr/local/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
2.4.2.3:zk节点2启动zookeeper
/usr/local/zookeeper/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
2.4.3:验证zookeeper集群状态
验证各zookeeper节点服务运行状态
2.4.3.1:zk节点1验证zookeeper
# /usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower
2.4.3.2:zk节点2验证zookeeper
# /usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: leader
2.4.3.2:zk节点3验证zookeeper:
# /usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower
2.4.4:zookeeper集群选举过程
2.4.4.1:节点角色状态:
LOOKING: 寻找Leader状态,处于该状态需要进入选举过程
LEADING: 领导者状态,处于该状态的节点说明角色已经是Leader
FOLLOWING: 跟随着状态,表示Leader已经选举出来,当前节点角色是follower
OBSERVER: 观察者状态,表明当前节点角色是observer
2.4.4.2::选举ID:
ZXID(zookeeper transaction id):每个改变Zookeeper状态的操作都会形成一个对应的zxid。
myid:服务器的唯一标识(SID),通过myid文件指定,集群中唯一。
2.4.4.3:leader选举过程:
当集群中的zookeeper节点启动以后,会根据配置文件中指定的zookeeper节点地址进行leader选择操作,过程如下:
1. 每个zookeeper都会发出投票,由于是每一个选举leader,因此每个节点都会把自己当做leader角色进行选举,每个zookeeper的投票中都会包含自己的myid和zxid,此时zookeeper1的投票为myid1,初始zxid有一个初始值,后期会随着数据更新而自动变化,zookeeper2的投票为myid为2,初始zxid为初始生成的值。
2. 每个节点接受并检查对方的投票信息,比如投票时间、是否状态为LOOKING状态的投票。
3. 对比投票,优先检查xvid,如果xvid不一样则xvid大的为leader,如果xvid相同则继续对比myid,myid大的一方为leader
成为Leader的必要条件:Leader要具有最高的zxid;当集群的规模是n时,集群中大多数的机器(至少n/2+1)得到响应并follow选出的Leader。
心跳机制: Leader与Follower利用PING来感知对方的是否存活,当Leader无法响应PING时,将重新发起Leader选举。
2.4.4.4: 投票日志:
ZooKeeper1的投票日志:
2020-06-01 09:21:48,244 [myid:1] - INFO
[ListenerThread:QuorumCnxManager$Listener@736] - My election bind port:
/172.31.4.101:3888
2020-06-01 09:21:48,247 [myid:1] - INFO
[QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:QuorumPeer@910] - LOOKING
2020-06-01 09:21:48,247 [myid:1] - INFO
[QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:FastLeaderElection@813] - New
election. My id = 1, proposed zxid=0x50000000f
2020-06-01 09:21:48,250 [myid:1] - INFO
[WorkerReceiver[myid=1]:FastLeaderElection@595] - Notification: 1 (message format
version), 1 (n.leader), 0x50000000f (n.zxid), 0x1 (n.round), LOOKING (n.state), 1
(n.sid), 0x7 (n.peerEpoch) LOOKING (my state)
2020-06-01 09:21:50,291 [myid:1] - INFO
[QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:2181:QuorumPeer@980] - FOLLOWING
ZooKeeper2的投票日志:
2020-06-01 09:21:50,082 [myid:2] - INFO
[WorkerReceiver[myid=2]:FastLeaderElection@595] - Notification: 1 (message format
version), 1 (n.leader), 0x50000000f (n.zxid), 0x1 (n.round), LOOKING (n.state), 1
(n.sid), 0x7 (n.peerEpoch) LOOKING (my state)
2020-06-01 09:21:50,083 [myid:2] - INFO
[WorkerReceiver[myid=2]:FastLeaderElection@595] - Notification: 1 (message format
version), 2 (n.leader), 0x50000000f (n.zxid), 0x1 (n.round), LOOKING (n.state), 1
(n.sid), 0x8 (n.peerEpoch) LOOKING (my state)
2020-06-01 09:21:50,284 [myid:2] - INFO
[QuorumPeer[myid=2]/0:0:0:0:0:0:0:0:2181:QuorumPeer@992] - LEADING
ZooKeeper3 的投票日志:
2020-06-01 09:21:53,607 [myid:3] - INFO
[QuorumPeer[myid=3]/0:0:0:0:0:0:0:0:2181:QuorumPeer@910] – LOOKING
2020-06-01 09:21:53,615 [myid:3] - INFO
[WorkerReceiver[myid=3]:FastLeaderElection@595] - Notification: 1 (message format
version), 2 (n.leader), 0x50000000f (n.zxid), 0x1 (n.round), FOLLOWING (n.state), 1
(n.sid), 0x9 (n.peerEpoch) LOOKING (my state)
2020-06-01 09:21:53,616 [myid:3] - INFO
[QuorumPeer[myid=3]/0:0:0:0:0:0:0:0:2181:QuorumPeer@980] - FOLLOWING
2.5:zookeeper数据增删改查:
2.5.1:查看当前zk运行状态:
/usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Mode: follower
2.5.2:命令行写入数据:
可连接至zookeeper集群中得任意一台zookeeper节点进行一下操作。
# /usr/local/zookeeper/bin/zkCli.sh -server 172.18.0.101:2181
[zk: 172.18.0.101:2181(CONNECTED) 3] create /test "hello" #写入数据
Created /test
[zk: 172.18.0.101:2181(CONNECTED) 4] get /test
config: /usr/local/zookeeper/bin/…/conf/zoo.cfg
Mode: follower
### 2.5.2:命令行写入数据:
可连接至zookeeper集群中得任意一台zookeeper节点进行一下操作。
```bash
# /usr/local/zookeeper/bin/zkCli.sh -server 172.18.0.101:2181
[zk: 172.18.0.101:2181(CONNECTED) 3] create /test "hello" #写入数据
Created /test
[zk: 172.18.0.101:2181(CONNECTED) 4] get /test