ZooKeeper
特点:查可以发生在所有节点,写只能发生在Leader节点
zk有两种运行的状态:可用状态和不可用状态
zk旨在存储协调数据:状态信息,配置,位置信息
zk是一个目录树结构,其中有node可以存数据,官方上线是1MB,节点分为持久节点和临时节点
2888端口和3888端口,第一次启动没有leader的时候,通过3888建立连接,之后在3888中通信,投票,选出leader,选完以后,leader会开一个2888端口,其他节点和这个端口建立连接
3888:选主投票用的
2888:leader接受写请求,同步数据
节点信息中
cZxid(创建节点时的事务ID)低32位是事务递增序列的值,前32位表示leader的纪元,第几个leader
mZxid(最后修改节点时的事务ID)
pZxid(当前节点子节点中的cZxid最大值。)
ephemeralOwner:如果是持久节点(默认创建的就是持久节点,create -e 创建临时节点),则是0x0,如果是临时节点,显示当前会话的sessionid
session也是要消耗统一视图,事务id的
create -s 可以在多并发条件下创建多个相同的子节点,用后缀的序号来需区分。例如两个会话同时创建create -s /xxoo/ooxx 那么/xxoo下就会有 ooxx000000和ooxx000001
选主过程:通过Zxid和myid来选举,票数多的当选leader
watch
ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)
- connectString 表示zookeeper集群的地址(ip:port),用逗号隔开,末尾可以添加默认的起始路径
- sessionTimeout 表示客户端连接断开后节点在集群中存活的时间
- watcher 里面写回调方法。这个watch是session级别的,和path,node没有关系
该构造方法是异步的,可以使用CountDownLatch锁,在回调的SyncConnected情况中解锁,然后使用创建完的对象
create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
- acl:访问权限
- createMode:
持久节点:CreateMode.PERSISTENT
临时节点:CreateMode.EPHEMERAL
顺序节点:CreateMode.PERSISTENT_SEQUENTIAL、CreateMode.EPHEMERAL_SEQUENTIAL
该方法是同步的,还有另一个异步的方法可以写回调方法
另一种watch的注册只发生读类型的调用,get exist
getData(final String path, Watcher watcher, Stat stat)
- stat 是path上的源数据 Zxid version,也就是get回来数据的version,防止aba问题
- watcher 当path中的数据发生改变时发生的回调,不过该回调是一次性的,所以可以在回调结束的时候再去getData一下,设置一个回调,回调传this即可
getData(String path, boolean watch, Stat stat)
- watch 为false则不用回调,true代表用是new ZooKeeper中的watch
setData(final String path, byte data[], int version)
- version 从stat中getVersion()得到,方式aba问题
zookeeper 实现分布式锁
获得锁到释放锁的步骤
- 多个线程争抢锁
- 某个线程获得锁
- 获得锁的线程释放锁
可能引发的问题及解决方案
步骤2会引发的问题:获得锁的线程挂了,成了死锁
解决方案:使用临时节点
步骤3会引发的问题:释放锁以后别人不知道
解决方案:
- 线程主动轮询。弊端:延迟、服务器压力
- watch 解决延迟问题 弊端:释放锁后,多个线程来抢锁,通信压力
- sequence + watch 将抢锁的线程都排好队,后一个线程等前一个线程的锁。完美解决问题。
实操步骤
- 首先各个线程创建临时节点
- 第一次抢锁,看自己是否是第一个节点,如果是就获得锁,如果不是,等待自己前一个节点消失获得锁
- 当前面一个节点消失,要继续判断自己是否是第一个节点,如果是,获取锁,如果不判断自己是第一个节点,那么以下情况会发生错误:第5个节点挂了,第6个节点收到通知,但第6个节点不应该获得锁
Zookeeper介绍
zookeeper是一个分布式协调服务,遵循CP原则。他的节点中会有一个leader,多个follower和observer,所有节点都可以进行读操作,只有leader可以进行写操作,follower可以投票,observer不能投票。他有两种状态,可用和不可用,当leader宕机后,进入不可用状态,在follower中选举出zxid最大的节点作为leader,如果最大的zxid节点有多个,就选其中myid最大最为leader。他的适用场景有分布式锁,使用顺序临时节点 + watch极大地提高了他的性能。
Paxos和ZAB
Paxos是基于信道可靠的条件下的,采用的是过半通过的方式来解决分布式数据一致性的问题。ZAB就是使用了他的思想,其中主要有两个机制,选举和广播,选举发生在服务刚刚启动还没有leader,或者说leader挂了的条件下,根据zxid和myid来进行选举leader,提高了集群的可靠性。广播是类似于二阶段提交,保证了数据的一致性。
实操总结
Watcher接口是用来监听节点的一些事件的
命令操作
用xxx.cfg来启动一台zookeeper:zkServer.sh start xxx.cfg,可以输入zkServer.sh 错误的指令,来看提示
zkCli.sh -server ip:port