分布式系统的基石之ZooKeeper——基本原理+场景应用+集群搭建(最强万字入门指南)

利用ZooKeeper的Watch机制,可以很容易实现集群间的高效通信和控制子系统。

集群通信与控制子系统

  • ZooKeeper里规划一个用于存放控制命令和应答的·路径(如/Commands);

  • 集群中的所有节点在启动后都监听此路径(/Commands);

  • 命令行程序(CLI)发给集群节点的命令及参数被包装成一个ZNode节点(如上图中的command1),写入/Commands路径下,同时在command1上监听事件。

  • 集群中的所有节点都通过/Commands上的Watch事件收到此命令,然后开始执行command1命令对应的逻辑;

  • 在某个节点执行完成后就在command1路径下新建一个ZNode节点(如node1result)作为应答。

  • 由于CLI之前在command1上监听,所以很快就被通知此命令已经有节点执行完成,CLI就可以实时输出结果,在所有节点的应答都返回后(或者等待超时),命令行结束。

6、分布式锁

使用ZooKeeper实现分布式锁的原理是利用时序节点和Watch机制:

(1)一个ZNode节点代表一把锁,如果锁对应的ZNode节点不存在,那么先创建ZNode节点。需要使用分布式锁功能先申请一个业务路径,如/lock/app1(不同服务和不同业务隔离),如果不区分锁的业务路径,也需要区分锁的前缀。

(2)抢占锁的所有客户端,使用锁的ZNode节点的子节点列表来表示;如果某个客户端需要占用锁,则在/lock/app1下创建一个临时有序的子节点。

(3)如何判断客户端是否占有锁?客户端创建子节点后,需要判断自己创建的子节点是否为当前子节点列表中序号最小的子节点。如果是,则认为加锁成功;如果不是,则监听前一个ZNode子节点的变更消息,等待前一个节点释放锁。

(4)一旦队列中后面的节点获得前一个子节点的变更通知,则开始进行判断,判断自己是否为当前子节点列表中序号最小的子节点,如果是,则认为加锁成功;如果不是,则持续监听,一直到获得锁。

(5)获取锁后,开始处理业务流程。在完成业务流程后,删除对应的子节点,完成释放锁的工作,以便后面的节点监听到节点的变更通知,获得分布式锁

ZooKeeper实现的分布式锁是公平的,且一般也会是可重入的。流程上非常类似AQS的实现,也是CLH的变体,只不过释放锁后节点通知不是本地,而是利用ZooKeeper的Watch机制远程通知。

四、ZooKeeper下载与安装


为了后续的源码学习,体验到最新的功能,这里下载最新版本的ZooKeeper(至今最新3.7.0),实际生产中可以安装历史版本。

(安装ZK前,请先安装JDK)

1、下载与安装

https://zookeeper.apache.org/

复制下载链接,到Centos中下载安装。

cd /usr/local/

mkdir zookeeper

cd zookeeper

下载

wget https://dlcdn.apache.org/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz

解压在当前目录

tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz

下载的zk安装,解压之后就可以用了:

zk-解压

修改解压之后的目录名称(也可以不修改)

mv apache-zookeeper-3.7.0-bin apache-zookeeper-3.7.0

cd apache-zookeeper-3.7.0

data/zoo用于存储zk数据

mkdir -p data/zoo

修改zoo_sample.cfg 为zoo.cfg,因为bin/zkServer.sh默认用的是zoo.cfg

mv conf/zoo_sample.cfg conf/zoo.cfg

修改zoo.cfg 中的dataDir为/usr/local/zookeeper/apache-zookeeper-3.7.0/data/zoo

不能用/tmp 存储zk数据,因为机器会定时清理/tmp目录下的数据

vim conf/zoo.cfg

zoo.cfg

启动,默认使用的conf/zoo.cfg启动,单机版。

bin/zkServer.sh start

bin/zkServer.sh start

直接运行bin/zkServer.sh,可以看到该命令的使用说明,常用的有startstatusrestartstop,还可以在启动时指定配置文件,如:

指定配置文件启动,配置文件路径必须放在后面

bin/zkServer.sh start conf/zoo.cfg

2、配置说明

ZooKeeper的启动配置文件zoo.cfg的配置内容说明:

The number of milliseconds of each tick

通信心跳时间,Leader和Follower或者Zookeeper服务器与客户端心跳时间,单位毫秒

tickTime=2000

The number of ticks that the initial

synchronization phase can take

Leader和Follower初始连接时能容忍的最多心跳数(tickTime的数量)

initLimit=10

The number of ticks that can pass between

sending a request and getting an acknowledgement

Leader和Follower之间通信时间如果超过syncLimit * tickTime,

Leader认为Follwer死掉,从服务器列表中删除Follwer。

syncLimit=5

the directory where the snapshot is stored.

do not use /tmp for storage, /tmp here is just

example sakes.

保存zk数据的目录,默认是/tmp,一般要修改为其他路径,因为Linux系统会定期请求/tmp下的数据

dataDir=/usr/local/zookeeper/apache-zookeeper-3.7.0/data/zoo

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

最大客户端连接数,默认60

#maxClientCnxns=60

The number of snapshots to retain in dataDir

dataDir中保留的快照数量

#autopurge.snapRetainCount=3

Purge task interval in hours

Set to “0” to disable auto purge feature

自动清除任务运行时间间隔,单位为小时,

若设置为 0 则禁用自动清除功能

#autopurge.purgeInterval=1

zk 指标监控提供者,官方推荐用prometheus普罗米修斯

Metrics Providers

https://prometheus.io Metrics Exporter

#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider

#metricsProvider.httpPort=7000

#metricsProvider.exportJvmInfo=true

zoo.cfg配置内容最后面是ZooKeeper指标数据监控配置,官方推荐用prometheus,如果用生产中用influxdb存储zk指标数据,本人推荐用Telegraf

五、ZooKeeper集群搭建


ZooKeeper集群中只要有半数以上节点存活,就能正常对外提供服务,所以Zookeeper集群一般运行奇数个服务端。由于学习用的Linux只有一台,只能搭建一个伪集群,不过理论上都是一样的。

1、伪集群

搭建ZooKeeper集群至少需要同时运行三个zk服务实例,如果其中一个挂了,依然可以正常对外提供服务。

(1)准备myid文件

为三个ZK实例创建数据存储目录。

在/usr/local/zookeeper/apache-zookeeper-3.7.0/data目录下

创建zoo-1、zoo-2、zoo-3

mkdir data/zoo-1 && mkdir data/zoo-2 && mkdir data/zoo-1

为三个目录分别创建myid文件,其内容只有一个数字编号,分别为1、2、3。myid文件中的编号唯一标识服务节点,用于Leader投票选举。

(2)配置zoo-.cfg文件

复制修改三份zoo.cfg,分别为zoo-1.cfgzoo-2.cfgzoo-3.cfg

zoo-1.cfg

没有显示的配置项和zoo.cfg一致

dataDir=/usr/local/zookeeper/apache-zookeeper-3.7.0/data/zoo-1

clientPort=2191

server.1 = 127.0.0.1:2888:3888

server.2 = 127.0.0.1:2889:3889

server.3 = 127.0.0.1:2890:3890

zoo-2.cfg

没有显示的配置项和zoo.cfg一致

dataDir=/usr/local/zookeeper/apache-zookeeper-3.7.0/data/zoo-2

clientPort=2192

server.1 = 127.0.0.1:2888:3888

server.2 = 127.0.0.1:2889:3889

server.3 = 127.0.0.1:2890:3890

zoo-3.cfg

没有显示的配置项和zoo.cfg一致

dataDir=/usr/local/zookeeper/apache-zookeeper-3.7.0/data/zoo-3

clientPort=2193

server.1 = 127.0.0.1:2888:3888

server.2 = 127.0.0.1:2889:3889

server.3 = 127.0.0.1:2890:3890

由于三个伪实例在一台机器上运行,所以clientPort不一样,实际生产中三个zk实例会运行在不同机器上,clientPort建议一致(2181)。

每个配置中都有相同的三行配置,表示这是一个集群关系配置:

server.A=B:C:D

  • A是一个数字,就是每个zk实例的myid文件中的编号。

  • B是ip地址,每个zk实例所在的机器ip。

  • C是集群中 LeaderFollower通信的端口,如LeaderFollower发送同步写指令,Follower将写请求转发给Leader。(通信端口)

  • D是集群中用于投票选举Leader的端口。(选举端口)

实际生产中,不同的zk实例运行在不同机器上,所以通信端口和选举端口各需要一个即可。

2、集群启动第一次Leader选举

依次执行如下命令,启动集群:

在/usr/local/zookeeper/apache-zookeeper-3.7.0目录下

bin/zkServer.sh start conf/zoo-1.cfg

bin/zkServer.sh start conf/zoo-2.cfg

bin/zkServer.sh start conf/zoo-3.cfg

为了看清楚三个zk实例启动时的Leader选举过程,特意在每次start之后穿插status

  • 启动zoo-1时,发起一次投票,zoo-1给自己投一票,此时服务实例不够半数以上,无法对外提供服务。status显示Error contacting service

  • 启动zoo-2时,再发起一次投票,status显示zoo-2leader,zoo-1显示follower,说明zoo-2给自己投了一票,zoo-1也给zoo-2投了一票,服务实例数超过半数,leader选举完成,此时可以对外提供服务。

  • 启动zoo-3时,status显示zoo-3follower。说明后来者zoo-3把选票投给了已经当上了leaderzoo-2

调整启动顺序,zoo-2zoo-1zoo-3

leader依然是zoo-2。

zoo-3放在前两次启动,leader就是zoo-3,最后启动实例都是Follower(演示省略),可得出结论:

  • myid小的投票给myid大的实例。

  • 已经完成leader选举后,后来者会直接把选票投给现任leader,自己甘为Follower

(leader投票选举的更多细节还需要后续看了源码才知道。)

3、模拟服务实例宕机leader重选

Follower实例宕机,只要集群实例个数在半数以上,依然可以对外提供服务,leader的地位也不会动摇,只有当身为leader的实例宕机了,此时就需要重新投票选leader

此时leaderzoo-2,将其stop,再次查看zoo-1zoo-3的状态,zoo-3变成了leader

(更多leader重选细节还需后续看了源码才知道。)

4、编写集群批量启动脚本

集群中每个实例手动一个个执行启动命令,确实比较麻烦,特编写一个批量启动脚本,如果多实例运行在不同机器上,可改成ssh的方式:

#!/bin/bash

case $1 in

“start”){

for i in zoo-1.cfg zoo-2.cfg zoo-3.cfg

do

echo ---------- zookeeper $i 启动 ------------

/usr/local/zookeeper/apache-zookeeper-3.7.0/bin/zkServer.sh start /usr/local/zookeeper/apache-zookeeper-3.7.0/conf/$i

done

};;

“stop”){

for i in zoo-1.cfg zoo-2.cfg zoo-3.cfg

do

echo ---------- zookeeper $i 停止 ------------

/usr/local/zookeeper/apache-zookeeper-3.7.0/bin/zkServer.sh stop /usr/local/zookeeper/apache-zookeeper-3.7.0/conf/$i

done

};;

“restart”){

for i in zoo-1.cfg zoo-2.cfg zoo-3.cfg

do

echo ---------- zookeeper $i 重启 ------------

/usr/local/zookeeper/apache-zookeeper-3.7.0/bin/zkServer.sh restart /usr/local/zookeeper/apache-zookeeper-3.7.0/conf/$i

done

};;

“status”){

for i in zoo-1.cfg zoo-2.cfg zoo-3.cfg

do

echo ---------- zookeeper $i 状态 ------------

/usr/local/zookeeper/apache-zookeeper-3.7.0/bin/zkServer.sh status /usr/local/zookeeper/apache-zookeeper-3.7.0/conf/$i

done

};;

esac

六、要点回顾


ZooKeeper集群搭建好了,就该用客户端连接上集群进行操作了,后续篇章会对客户端操作做详细讲解。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)

image

image

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)

[外链图片转存中…(img-hQv33IH1-1713538465092)]

[外链图片转存中…(img-bZMa29Fb-1713538465092)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值