原理就是利用ZK同级节点的惟一性.服务器
Curator框架下的一些分布式锁工具
InterProcessMutex:分布式可重入排它锁 网络
InterProcessSemaphoreMutex:分布式排它锁 session
InterProcessReadWriteLock:分布式读写锁框架
使用 Zookeeper 实现 leader 选举分布式
Leader Latch ide
参与选举的全部节点,会建立一个顺序节点,其中最小的 节点会设置为 master 节点, 没抢到 Leader 的节点都监听前一个节点的删除事件,在前一个节点删除后进行从新抢主,当 master 节点手动调用 close()方法或者 master 节点挂了以后,后续的子节点会抢占 master。 其中 spark 使用的就是这种方法 工具
LeaderSelector ui
LeaderSelector 和 Leader Latch 最的差异在于,leader 能够释放领导权之后,还能够继续参与竞争this
public class LeaderSelectorClient extends LeaderSelectorListenerAdapter implements Closeable { private String name; //表示当前的进程 private LeaderSelector leaderSelector; //leader选举的API private CountDownLatch countDownLatch=new CountDownLatch(1); public LeaderSelectorClient(){ } public LeaderSelectorClient(String name) { this.name = name; } public LeaderSelector getLeaderSelector() { return leaderSelector; } public void setLeaderSelector(LeaderSelector leaderSelector) { this.leaderSelector = leaderSelector; } public void start(){ leaderSelector.start(); //开始竞争leader } @Override public void takeLeadership(CuratorFramework client) throws Exception { //若是进入当前的方法,意味着当前的进程得到了锁。得到锁之后,这个方法会被回调 //这个方法执行结束以后,表示释放leader权限 System.out.println(name+"->如今是leader了"); // countDownLatch.await(); //阻塞当前的进程防止leader丢失 } @Override public void close() throws IOException { leaderSelector.close(); } private static String CONNECTION_STR="x.x.x.x:2181; public static void main(String[] args) throws IOException { CuratorFramework curatorFramework = CuratorFrameworkFactory.builder(). connectString(CONNECTION_STR).sessionTimeoutMs(50000000). retryPolicy(new ExponentialBackoffRetry(1000, 3)).build(); curatorFramework.start(); LeaderSelectorClient leaderSelectorClient=new LeaderSelectorClient("ClientA"); LeaderSelector leaderSelector=new LeaderSelector(curatorFramework,"/leader",leaderSelectorClient); leaderSelectorClient.setLeaderSelector(leaderSelector); leaderSelectorClient.start(); //开始选举 System.in.read(); } }
ZAB 协议包含两种基本模式,spa
1. 崩溃恢复[master节点选择]
2. 原子广播[数据恢复,数据同步]
当整个集群在启动时,或者当 leader 节点出现网络中断、 崩溃等状况时,ZAB 协议就会进入恢复模式并选举产生新 的 Leader,当 leader 服务器选举出来后,而且集群中有过 半的机器和该 leader 节点完成数据同步后(同步指的是数 据同步,用来保证集群中过半的机器可以和 leader 服务器 的数据状态保持一致),ZAB 协议就会退出恢复模式。
当集群中已经有过半的 Follower 节点完成了和 Leader 状 态同步之后,那么整个集群就进入了消息广播模式。这个时候,在 Leader 节点正常工做时,启动一台新的服务器加入到集群,那这个服务器会直接进入数据恢复模式,和 leader 节点进行数据同步。同步完成后便可正常对外提供非事务请求的处理。
须要注意的是:leader 节点能够处理事务请求和非事务请 求,follower 节点只能处理非事务请求,若是 follower 节 点接收到非事务请求,会把这个请求转发给 Leader 服务器
ZK数据同步流程过程其实是一个 简化版本的二阶段(2pc)提交过程
1. leader 接收到消息请求后,将消息赋予一个全局惟一的 64 位自增 id,叫:zxid,经过 zxid 的大小比较既能够实现因果有序这个特征 2. leader 为每一个 follower 准备了一个 FIFO 队列(经过 TCP 协议来实现,以实现了全局有序这一个特色)将带有 zxid 的消息做为一个提案(proposal)分发给全部的 follower 3. 当 follower 接收到 proposal,先把 proposal 写到磁盘, 写入成功之后再向 leader 回复一个 ack 4. 当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会 在本地执行该消息 5. 当 follower 收到消息的 commit 命令之后,会提交该消息
为了保证事务的顺序一致性,zookeeper 采用了递增的事 务 id 号(zxid)来标识事务。
全部的提议(proposal)都 在被提出的时候加上了 zxid。实现中 zxid 是一个 64 位的 数字,它高 32 位是 epoch(ZAB 协议经过 epoch 编号来 区分 Leader 周期变化的策略)用来标识 leader 关系是否改变,每次一个 leader 被选出来,它都会有一个新的 epoch=(原来的 epoch+1),标识当前属于那个 leader 的 统治时期。低 32 位用于递增计数。
epoch:能够理解为当前集群所处的年代或者周期,每一个leader 就像皇帝,都有本身的年号,因此每次改朝换代,leader 变动以后,都会在前一个年代的基础上加1。这样就算旧的 leader 崩溃恢复以后,也没有人听他的了,由于 follower 只遵从当前年代的 leader 的命令。