简介
Zookeeper 是一个分布式协调服务框架,可用于服务发现,分布式领导选举,配置管理等。Zookeeper 提供了一个类似于 Linux 文件系统的树形结构(存放了少量信息的内存文件系统,不适合存储大量文件或大文件),同时提供了对每个分布式节点的监控与通知机制。
优点:
- 可靠性: 2n+1
- 可扩展性:需要增加机器时,少许修改即可,且不用冷启动(停机)
- 同步: 服务器进程之间的像话排斥和协作。
- 原子性:数据转移完全成功或完全失败,但没有事物是部分的?
- 序列化: 根据特定规则对数据进行编码。
特性
- 顺序一致性:保证客户端操作是按照顺序生效的
- 原子性:更新成功或者失败,没有部分结果
- 内容一致性:单个系统映像,无论连接到哪个服务器,客户端都将看到相同的内容
- 可靠性:数据的变更不会丢失,除非被客户端覆盖修改
- 及时性:保证系统端当前读取到的数据是最新的
应用场景:
(1)分布式协调:这个其实是zk很经典的一个用法,简单来说,就好比,你A系统发送个请求到mq,然后B消息消费之后处理了。那A系统如何知道B系统的处理结果?用zk就可以实现分布式系统之间的协调工作。A系统发送请求之后可以在zk上对某个节点的值注册个监听器,一旦B系统处理完了就修改zk那个节点的值,A立马就可以收到通知,完美解决。
(2)分布式锁:对某一个数据连续发出两个修改操作,两台机器同时收到了请求,但是只能一台机器先执行另外一个机器再执行。那么此时就可以使用zk分布式锁,一个机器接收到了请求之后先获取zk上的一把分布式锁,就是可以去创建一个znode,接着执行操作;然后另外一个机器也尝试去创建那个znode,结果发现自己创建不了,因为被别人创建了。。。。那只能等着,等第一个机器执行完了自己再执行。
(3)元数据/配置信息管理:zk可以用作很多系统的配置信息的管理,比如kafka、storm等等很多分布式系统都会选用zk来做一些元数据、配置信息的管理,包括dubbo注册中心不也支持zk么
(4)HA高可用性:这个应该是很常见的,比如hadoop、hdfs、yarn等很多大数据系统,都选择基于zk来开发HA高可用机制,就是一个重要进程一般会做主备两个,主进程挂了立马通过zk感知到切换到备用进程
架构
Zookeeper 的设计采用的是观察者的设计模式,zookeeper 主要是负责存储和管理所必需的数据,然后接受观察者注册,一旦数据发送变化,Zookeeper 就将负责通知已经在 Zookeeper 上注册的观察者。从而实现集群的 master/slave 管理模式。
Zookeeper 适用于主从构架(客户端-服务端架构)的高可用集群,每个节点分别承担了不同的集群角色。
-
Leader
一个 Zookeeper 集群同一时间内只能有一个实际工作的 Leader, 它会发起并维护各 Follwer 及 Observer 间的心跳。
Zookeeper 的写请求会被发送到 Leader 节点,然后 Leader 将数据变更的内容同步到集群的其它节点(Follower,Observer)。
Leader 节点在接收到数据变更请求后,首先将变更数据写入本地磁盘,以作恢复之用,当所有写请求持久化磁盘以后,才会将变更应用到内存中。 -
Follower
跟随 Leader 指令的服务器节点
一个 Zookeeper 集群可能同时存在多个 Follower,它会响应 Leader 的心跳. -
Observer
不参与选举的服务器节点。
文件系统的树结构
ZooKeeper 节点称为 znode, 每个 znode 由一个名称标识, 并用路径 (/)序列分隔。首先有一个由 “/” 分隔的 znode。 在根目录下,有两个逻辑命命名空间 config 和 workers。
config:命名空间用于集中式配置管理,每个znode 最多可存储 1MB 的数据
worker:命名空间用于命名
Znode 的类型
持久节点:
- 即使在创建该特定 znode 的客户端断开连接后,持久节点仍然存在
- 默认情况下,所有 znode 都是持久化的。
临时节点:
- 客户端活跃时,临时及诶单就是有效的。 当客户端与 ZooKeeper 集合断开连接时,临时节点会自动删除
- 只有临时节点不允许有子节点
- 临时节点在 leader 选举中起着重要作用
顺序节点:
- 顺序节点可以是持久的或临时的。
- 当一个新的 znode 被创建为一个顺序节点时,zookeeper 通过将 10 位的序列号附加到原始名称来设置 znode 的路径,
- 顺序节点在锁定和同步中起重要作用
如何保证数据的一致性
在集群中,当 follower 或 observer 收到客户端的事务请求,会将该事务转发给 leader。当 leader 处理事务请求时,也会向整个集群的 follower 节点对象发送广播提议,当 follower 收到消息后作出相应响应并向 leader 发送消息,表示事务被成功处理。然后再向收到请求的 follower 进行通知,告之其进行事务提交,并最终会返回客户端一个事务被成功处理的状态。如果还有 follower 没及时进行事务同步操作,那么也最终会从 leader 去进行状态的同步。保证数据与 leader 一致性。
leader 如何判断事务处理成功:超过总数的一半的 (n/2 +1)的数量才表明操作成功。
zk 写入流程
数据写入最终一致性zab算法。leader负责处理写事务请求,follower负责向leader转发写请求,响应leader发出的提议。
搭建
单机模式
解压安装包
tar -zxf zookeeper-3.4.10.tar.gz -C /opt/moduels
修改配置文件
修改文件名 conf/zoo_sample.cfg -> /conf/zoo.cfg
mv conf/zoo_sample.cfg /conf/zoo.cfg
制定本地存储数据的路径:zoo.cfg
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/opt/modules/zookeeper-3.4.5/data/zkData (myid文件的路径)
启动服务端
bin/zkServer.sh start
查看状态
bin/zkServer.sh status
启动客户端
bin/zkCli.sh
分布式模式
解压安装包
tar -zxf zookeeper-3.4.10.tar.gz -C /opt/app
修改配置文件
修改文件名 conf/zoo-simple.cfg /conf/zoo.cfg
cp conf/zoo-simple.cfg /conf/zoo.cfg
制定本地存储数据的路径 zoo.cfg
dataDir=/opt/app/zookeeper-3.4.5/data/zkData (myid文件的路径)
添加服务端
server.1=192.168.47.135:2888:3888 编号1
server.2=192.168.47.133:2888:3888 编号2
server.3=192.168.47.132:2888:3888 编号3
修改 /data/zkData, 如果没有,就创建该目录
vi myid
写入本机及其编号: 1
分发文件到其他主机上
scp -r zookeeper-3.4.10/ 192.168.47.133:/opt/app/
scp -r zookeeper-3.4.10/ 192.168.47.132:/opt/app/
修改每个机器上的myid: 2,3,...
分别启动服务端
bin/zkServer.sh start
分别查看状态
bin/zkServer.sh status
可能出现的问题
-
配置 myid 的问题。
其路径就是我们配置的路径。dataDir=/opt/app/zookeeper-3.4.5/data/zkData
如果配置错误,在查看状态时,会有提示 conf配置错误。 -
需要删除 zoo_sample.cfg
两个 zoo *** 不可能共存,否则在查看状态时也会提示server的问题
It is probably not running -
有时在 bin/zkServer.sh status 会发生 java.net.ConnectException: Connection refused 的问题
可以分别启动所有的节点,并通过 jps 来查看进程是否开启,最后再用 bin/zkServer.sh status。
我在第一个节点上始终都会发生这种情况,但是都启动完成后,再次看第一个节点却发现正常了。
如果无法 stop ,可以使用 kill 来杀掉该进程,再次 start 即可。