它是一个分布式协调服务的开源框架,主要用来解决分布式集群中应用系统一致性的问题,例如怎样避免同时操作同一数据造成脏读的问题
它的本质是是一个分布式的小文件存储系统,提供基于类似于文件系统的目录树方式的数据存储,并且可以对树上的节点进行管理并维护和监控你存储的数据的状态变化,通过监控这些数据的变化达到基于数据的集群管理
(统一命名服务,分布式配制管理,分布式消息队列,分布式锁,分布式协调服务)
zookeeper节点
(1)全局数据一致,无论client连接到哪一个服务器,展示的数据都是一样的
对于事物操作(写入,修改,删除)统一交给leader来管理,对于非事物的操作(读)因为不涉及目录树的修改,不需要保证
(2) 可靠性 如果消息被一个服务器接收,那么将被所有服务器接收
(3)顺序性 有序和偏序 消息的执行顺序根据发布的时间来进行有序或者偏序的执行
(4)数据更新原子性 数据的更新要么成功,要么失败
(5) 实时性 zookeeper保证客户端在一个时间间隔范围内获得更新信息,或者服务器失效的信息
(1)数据的发布与订阅
发布与订阅模型,即所谓的配置中心,发布者将数据发布到zk的节点上,供订阅者动态的获取数据,实现配置信息的集中式管理与动态更新。
应用在启动的时候会主动的获取一次配置信息,并在节点上注册一个watcher,这样后面每次配置有更新的时候,都会实时的通知到订阅的客户端,从来达到获取最新配置信息的目的。
例如 在分布式搜索服务中,索引的元信息就可以存在zk的一些指定结点,还有分布式项目中的一些配置文件。properties
(2)命名服务
在分布式系统中,通过使用命名服务,客户端可以通过指定的用户名来获取资源或服务的地址,提供者的信息,被命名的对象可以使服务器,提供的服务地址,远程对象等等,这些都可以称为名字,其中比较常见的就是分布式框架中的服务地址列表,通过调用zk提供的创建节点的API,创建一个全局唯一的path,这个path就可以成为一个名字
其中dubbo框架就是运用zookeeper作为其命名服务,无论是提供者还是消费者,zookeeper都会创建代理对象,这样当去调用其他服务时,从注册中心中找到这个服务的全局唯一path就可以调用了。
(3) 分布式锁
依靠zookeeper的全局数据一致性,锁服务分为两类,一种是保持独占,另一个是控制时序。
保持独占就是把zk上的一个节点看成一把锁,所有试图获取这个锁的客户端最终只有一个可以成功,
控制时序同样是利用上面的创建节点,所有试图获取这个锁的客户端都会被安排执行,只是这个锁的节点已经存在,客户端在他下面创建一个有序的节点,zk的父节点维持了一份sequence,用来保证创建的时序性,从而保证了去哪聚的时序性
(4) 给其他集群进行选举
要求各个服务器启动之前去zk集群指定的节点创建指定的znode(短暂无序的),这样只会有一个创建成功,这样就选举出了leader,剩下的为follower,同时设置该节点的监听,如果leader挂掉,断开与zk集群的连接,会话消失,节点消失,监控触发,监控通知给设置监听的follower,接收到监听的follower,去zk指定结点抢注znode,成功的为leader 。
zk的监听机制:
监听是客户端向服务端注册watcher,服务端事件发生触发watcher,客户端回调watcher得到触发事件的情况
shell命令行设置监听:
设置监听
改变节点数据使监听触发
WATCHER::
WatchedEvent state:SyncConnected type:NodeDataChanged path:/itheima
zk中的监听分为两类:
用户自定义的监听事件:先注册再监听 一次性监听
系统自带的连接状态事件:none null 不需要注册 满足直接触发 客户端如果有需要就处理,如果没有需求直接忽略
实现永久监听:
只能通过JavcAPI,永久监听是我们根据需求强制加上的。
只要能在上一次监听回调的方法前再次设置同节点同类型的监听,一次达到前后两次监听的首尾连接
zookeeper 默认的算法是 FastLeaderElection,采用投票数大于半数则胜出的逻辑。
服务器 ID
比如有三台服务器,编号分别是 1,2,3。
编号越大在选择算法中的权重越大。
选举状态
LOOKING,竞选状态。
FOLLOWING,随从状态,同步 leader 状态,参与投票。
OBSERVING,观察状态,同步 leader 状态,不参与投票。
LEADING,领导者状态。
数据 ID
服务器中存放的最新数据 version。
值越大说明数据越新,在选举算法中数据越新权重越大。
逻辑时钟
也叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票
这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,
根据不同的值做出不同的判断。
对于全新选举(默认zk集群数2n+1)
当有一台服务器参与选举时,服务器会将选票投给自己,因为此时只有一台并且ID最大
第二台服务器参与选举时,由于他的ID最大,所以1和2将选票投给2,此时第二台服务器有两票
第三台服务器参与选举时,如果这个集群仅有三台服务器,那么由于第二台服务器得票数已经过半,此时第三台服务器没有选举权也没法参与投票,此时2为leader,1和3为follower。
对于运行正常的 zookeeper 集群,中途有机器 down 掉,需要重新选举时,
选举过程就需要加入数据 ID、服务器 ID 和逻辑时钟。
数据 ID:数据新的 version 就大,数据每次更新都会更新 version。
服务器 ID:就是我们配置的 myid 中的值,每个机器一个。
逻辑时钟:这个值从 0 开始递增,每次选举对应一个值。 如果在同一次选举中,这个值是一致的。
这样选举的标准就变成:
1、逻辑时钟小的选举结果被忽略,重新投票;
2、统一逻辑时钟后,数据 id 大的胜出;
3、数据 id 相同的情况下,服务器 id 大的胜出;
根据这个规则选出 leader。
1 zookeeper的节点兼具文件和目录两种特点,既可以像文件一样存储信息,维护着数据,元信息,ACL,时间戳等数据结构,又可以像目录一样,作为路径的一部分,并且具有子节点znode,用户对znode具有增删改查的操作(权限允许)
2 znode具有原子性操作,读会读取与节点相关的所有数据,写操作也会替换掉节点的所有数据,每一个节点都拥有自己的访问控制列表ACL ,这个列表规定了用户的权限,即规定了特殊用户对目标节点的可执行的操作
3 znode的存储数据的大小有限制,它主要是用来管理和调度数据,它存储的数据通常是以kb为大小单位。ZooKeeper 的服务器和客户端都被设计为严格检查并限制每个 Znode 的数据大小至多 1M,当
时常规使用中应该远小于此值。
4znode通过路径引用,他的路径是绝对的,开头必须以”/”开头
每个znode有三部分组成:
1 stat: 状态信息,描述了节点的版本,权限等信息
2 data :与znode相关联的数据
3 children: 该节点下的子节点
节点的类型
PERSISTENT:永久节点
EPHEMERAL:临时节点
PERSISTENT_SEQUENTIAL:永久节点、序列化
EPHEMERAL_SEQUENTIAL:临时节点、序列化
当客户端与服务端进行连接时即创建了一个会话(session),当连接中断,超时或者其他原因断开时,会话结束。
临时节点会随着session的结束而自动删除,它不允许有子节点
序列化是指在该节点的名字后面追加一个不断增加的序列号,序列号对于这个节点的父节点来说是唯一确定的,这样可以记录每个子节点创建的先后顺序。
节点的属性(通过get命令获得)
dataVersion :数据的版本号,每次对节点进行set操作都会增加1(即使是设置相同的数据),可以有效避免数据更新后出现的先后顺序问题
cversion :子节点的版本号,当其子节点有变化时,它的值会加1
aclVersion:ACL版本号
cZxid: 节点创建的事物ID
mZxid: 节点被修改的事务 id,即每次对 节点的修改都会更新 mZxid。
对于 zk 来说,每次的变化都会产生一个唯一的事务 id,zxid(ZooKeeperTransaction Id)。通过 zxid,可以确定更新操作的先后顺序。
ctime:节点创建时的时间戳.
mtime:节点最新一次更新发生时的时间戳
ephemeralOwner:如果该节点为临时节点, ephemeralOwner 值表示与该节点绑定的 session id. 如果不是, ephemeralOwner 值为 0
dataVersion 数据的版本号,每次对节点进行set操作都会
安装前需确认
1 jdk是否安装
2 防火墙
3 时间是否同步
4 主机名与IP映射是否配置
确认之后进行zookeeper的安装
1 上传解压安装包
2 修改配置文件(/etc/profile)
export ZOOKEEPER_HOME=zookeeper的路径(可以通过pwd查看)
export PATH= PATH: P A T H : ZOOKEEPER_HOME/bin
配置完之后切记执行source /etc/profile 让其生效
3 修改Zookeeper配置文件zoo_sample.cfg
添加内容:
dataDir=(zookeeper的数据存放位置)
server.1=主机名:2888:3888 ## (心跳端口、选举端口)
4 创建myid文件
并为其赋值 echo 1 > myid
5 根据需求将安装包和配置文件发送其他的服务器上,并更改myid的值
6 启动:可以创建脚本启动也可以手动逐个启动