ZooKeeper 是一个分布式服务框架,它主要是用来解决分布式应用中经常遇到的
一些数据管理问题,如:命名服务、状态同步、配置中心、集群管理等。
命名服务:
命名服务是分布式系统中比较常见的一类场景。命名服务是分布式系统最基本的
公共服务之一。在分布式系统中,被命名的实体通常可以是集群中的机器、提供
的服务地址或远程对象等——这些我们都可以统称它们为名字(Name),其中较
为常见的就是一些分布式服务框架(如 RPC、RMI)中的服务地址列表,通过使
用命名服务,客户端应用能够根据指定名字来获取资源的实体、服务地址和提供
者的信息等。
状态同步:
每个节点除了存储数据内容和 node 节点状态信息之外,还存储了已经注册的
APP 的状态信息,当有些节点或 APP 不可用,就将当前状态同步给其他服务。
配置中心:
现在我们大多数应用都是采用的是分布式开发的应用,搭建到不同的服务器上,
我们的配置文件,同一个应用程序的配置文件一样,还有就是多个程序存在相同
的配置,当我们配置文件中有个配置属性需要改变,我们需要改变每个程序的配
置属性,这样会很麻烦的去修改配置,那么可用使用 ZooKeeper 来实现配置中心,
ZooKeeper 采用的是推拉相结合的方式: 客户端向服务端注册自己需要关注的
节点,一旦该节点的数据发生变更,那么服务端就会向相应的客户端发送
Watcher 事件通知,客户端接收到这个消息通知后,需要主动到服务端获取最新
的数据。
集群管理:
所谓集群管理,包括集群监控与集群控制两大块,前者侧重对集群运行时状态的收集,后者则是对集群进行操作与控制,在日常开发和运维过程中,我们经常会
有类似于如下的需求:
希望知道当前集群中究竟有多少机器在工作。
对集群中每台机器的运行时状态进行数据收集。
对集群中机器进行上下线操作。
ZooKeeper 具有以下两大特性。
客户端如果对 ZooKeeper 的一个数据节点注册 Watcher 监听,那么当该数据节点
的内容或是其子节点列表发生变更时,ZooKeeper 服务器就会向订阅的客户端发
送变更通知。
对在 ZooKeeper 上创建的临时节点,一旦客户端与服务器之间的会话失效,那么
该临时节点也就被自动清除。
Watcher(事件监听器),是 Zookeeper 中的一个很重要的特性。Zookeeper
允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,
ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 Zookeeper
实现分布式协调服务的重要特性。
0 生产者启动
1 生产者注册至 zookeeper
2 消费者启动并订阅频道
3 zookeeper 通知消费者事件
4 消费者调用生产者
5 监控中心负责统计和监控服务状态
ZooKeeper 单机安装:
配置 java 环境:
## 官方依赖介绍
https://zookeeper.apache.org/doc/r3.4.14/zookeeperAdmin.html#sc_requiredSoftware
安装jdk
[root@mq1 ~]# apt install openjdk-8-jdk -y
下载网址
https://archive.apache.org/dist/zookeeper/
下载
[root@mq1 ~]# cd /usr/local/src/
[root@mq1 src]# wget https://archive.apache.org/dist/zookeeper/zookeeper-3.6.0/apache-zookeeper-3.6.0.tar.gz
解压
[root@mq1 src]# tar xf apache-zookeeper-3.6.0.tar.gz
做成软链接
[root@mq1 ~]# ln -s /usr/local/src/apache-zookeeper-3.6.0 /usr/local/zookeeper
修改文件
[root@mq1 ~]# cd /usr/local/zookeeper
[root@mq1 zookeeper]# cp conf/zoo_sample.cfg conf/zoo.cfg
创建数据目录
[root@mq1 zookeeper]# mkdir /data/zookeeper -p
查看配置
[root@mq1 zookeeper]# grep ^[a-Z] conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zookeeper
clientPort=2181
启动
[root@mq1 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh start
查看端口2181
[root@mq1 zookeeper]# ss -tanl
查看进程
[root@mq1 zookeeper]# ps -ef | grep zookeeper
查看状态
[root@mq1 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh status
报错
[root@mq1 zookeeper]# tail -f logs/zookeeper-root-server-mq1.exmplr.local.out
Error: Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain
解决方法:
因为zk是java写的,所以启动zk就是执行java文件,看了zk目录都是源文件,并不是编译后的包,显然是下载的tar包有问题,重新下载了带bin的包
[root@mq1 src]# wget https://archive.apache.org/dist/zookeeper/zookeeper-3.6.0/apache-zookeeper-3.6.0-bin.tar.gz
zookeeper 集群
ZooKeeper 集群用于解决单点和单机性能及数据高可用等问题。
Zookeeper 集群部署:
Zookeeper 的集群部署过程。
zookeeper 集群特性:整个集群中只要有超过集群数量一半的 zookeeper 工作只
正常的,那么整个集群对外就是可用的,假如有 2 台服务器做了一个 zookeeper
集群,只要有任何一台故障或宕机,那么这个 zookeeper 集群就不可用了,因为
剩下的一台没有超过集群一半的数量,但是假如有三台 zookeeper 组成一个集群,
那么损坏一台就还剩两台,大于 3 台的一半,所以损坏一台还是可以正常运行的,
但是再损坏一台就只剩一台集群就不可用了。那么要是 4 台组成一个 zookeeper
集群,损坏一台集群肯定是正常的,那么损坏两台就还剩两台,那么 2 台不大于
集群数量的一半,所以 3 台的 zookeeper 集群和 4 台的 zookeeper 集群损坏两台
的结果都是集群不可用,以此类推 5 台和 6 台以及 7 台和 8 台都是同理,所以这
也就是为什么集群一般都是奇数的原因。
配置 ZooKeeper 集群:
各 zookeeper 服务器都配置 java 环境并部署 zookeeper 集群
服务器环境:
Zk-node1:172.31.2.41
Zk-node2:172.31.2.42
Zk-node3:172.31.2.43
配置如下(其他机器配置都一样)
[root@mq1 zookeeper]# grep -v "^#" /usr/local/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/usr/local/zookeeper/data
clientPort=2181
maxClientCnxns=128
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
server.1=172.31.2.41:2888:3888
server.2=172.31.2.42:2888:3888
server.3=172.31.2.43:2888:3888
创建目录
[root@mq1 zookeeper]# mkdir -p /usr/local/zookeeper/data
[root@mq2 zookeeper]# mkdir -p /usr/local/zookeeper/data
[root@mq2 zookeeper]# mkdir -p /usr/local/zookeeper/data
所有机器都不一样
[root@mq1 zookeeper]# echo "1" > /usr/local/zookeeper/data/myid
[root@mq2 zookeeper]# echo "2" > /usr/local/zookeeper/data/myid
[root@mq3 zookeeper]# echo "3" > /usr/local/zookeeper/data/myid
各服务器启动 zookeeper:
各 zookeeper 服务器尽快启动 zookeeper 服务。
[root@mq1 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh restart
[root@mq2 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh restart
[root@mq3 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh restart
验证 zookeeper 集群状态:
[root@mq1 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh status
Mode: follower
[root@mq2 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh status
Mode: leader
[root@mq3 zookeeper]# /usr/local/zookeeper/bin/zkServer.sh status
Mode: follower
节点角色状态:
LOOKING:寻找 Leader 状态,处于该状态需要进入选举流程
LEADING:领导者状态,处于该状态的节点说明是角色已经是 Leader
FOLLOWING:跟随者状态,表示 Leader 已经选举出来,当前节点角色是 follower
OBSERVER:观察者状态,表明当前节点角色是 observer
选举 ID:
ZXID(zookeeper transaction id):每个改变 Zookeeper 状态的操作都会形成一个对应的 zxid。
myid:服务器的唯一标识(SID),通过配置 myid 文件指定,集群中唯一。
leader 选举过程
当集群中的 zookeeper 节点启动以后,会根据配置文件中指定的 zookeeper 节点
地址进行 leader 选择操作,过程如下:
1. 每个 zookeeper 都会发出投票,由于是第一次选举 leader,因此每个节点都
会把自己当做 leader 角色进行选举,每个 zookeeper 的投票中都会包含自己
的 myid 和 zxid,此时 zookeeper 1 的投票为 myid 为 1,初始 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 选举。