ZooKeeper入门笔记

今天准备重新回到简书写文章,在这之前我的技术文章都放在github上,这次一律都搬过来,后面的文章技术的两边都发,其他类型的发简书,毕竟简书上写还有人看,稍微有些乐趣(本文原链接点我)。

初识

定义

ZooKeeper是一个开源的分布式协调服务,其设计目标是将原本复杂容易出错的分布式一致性服务封装,构成一个高效可靠简单易用的接口供用户使用。

特点
  • 顺序一致性:同一个客户端发起的事物请求会被顺序的在ZooKeeper中执行,每个客户端的事物请求,ZooKooper都会分配一个全局唯一的递增序号来区分事物的先后顺序
  • 原子性:所有的事物请求在整个集群中的所有机器上的应用情况是一致的。
  • 单一视图:无论客户端连接的是ZooKeeper的哪个节点机器,其看到的服务端数据模型都是一致的
  • 实时性:保证在一定时间段内,客户端最终一定能从服务端上读取到最新的数据状态
  • 数据模型简单:树形的结构,类型文件系统
  • 可构建集群:多台ZooKeeper节点组成集群,角色可分为Leader,Follower,Observer,Leader可读可写,Follower和Observer可读,Follower可被选举为Leader;集群的每台机器存储的数据是一致的
  • 高可靠性:一旦服务端成功地执行了一个事物并响应给客户端,那么其状态变更就会被一直保留下来,除非下一次再进行变更。数据也会被增量和全量地持久化到磁盘中
  • 高性能:全量数据位于内存中
  • 提供事件监听机制:客户端可以对节点注册监听事件,当事件发生时会通知客户端
  • 会话状态:客户端与服务端建立连接后保持一个会话状态,客户端可以创建临时节点,在会话失效后临时节点将被清理
背后的算法原理
  • ZAB协议:ZooKeeper保证数据一致性的核心算法,类似二阶提交的过程,每个事物由全局唯一的Leader来将该请求转换成一个提议,并将该提议分发给所有的Follower,超过半数的Follower进行正确反馈后,Leader才会再次向所有的Follower服务器发送确认提交,Follower服务器要么响应,要么丢弃,正常情况下Leader接收到超半数反馈,如果没有超半数反馈则ZooKeeper进入崩溃恢复状态,重新选举Leader,重新选举出来的Leader具有事物序号最大的特点,这也说明这台Leader的数据最齐全,当选举完成后,全局递增的事物序号会发生改变,该序号由64位数字表示,低32位是递增序号,高32位每次重新选举会增1,这样新选举出来的递增序号高于之前Leader的序号,所以就算之前的Leader恢复正常了再发送之前的事物序号,集群发现序号太小不会执行,这样就保证了强一致性

  • 如何选举Leader:目的是选举出唯一的一台服务器作为Leader,并让所有Follower知道谁被选举为Leader,且该Leader具有全局递增序号最大的特点(这样的数据才最新)
    假设有三台Follower进行选举:三台机器ID分别为1,2,3;3台机器的递增序号(ZID)都为0(初始选举),每台机器将[myID, ZID]投票给其他机器,每台机器接收到投票后,将投票处理,先检查ZID,以ZID较大的再作为选票,如果ZID相同就将myID大的服务器作为选票,将新选票再投出去;每次投票后机器就统计是否有超过半数的机器收到相同的投票,如果有就他是Leader了;这里第一轮投票大家各自将自己投出去,机器1收到[2,0],[3,0]后将投票变更为[3,0],机器2收到[1,0],[3,0]将投票变更为[3,0],机器3收到[1,0],[2,0]不做变更,第二轮投票后再统计3机器就超半数当选Leader;如果3台机器首轮的选票为[1,5],[2,4],[3,4],机器1收到[2,4][3,4]后选票不变,机器2收到[1,5][3,4]后将选票改为[1,5],机器3收到[1,5][2,4]后将选票改为[1,5],第二轮选出机器1,所以最后ZID最大的最有可能成为Leader。

ZooKeeper的应用

  • 数据发布/订阅,配置管理,如qconf
  • 命名服务,如RPC服务框架
  • 分布式协调/通知:如心跳检测,任务调度,Master选举,分布式锁等

实践一下

环境搭建
  • 下载稳定的releases包,并解压到工作目录中
  • 创建配置文件:conf 目录下 cp zoo_sample.cfg zoo.cfg,设置dataDir到一个存在的目录(由于机器太差就没有搭集群,集群的配置网上找找总是有的)
  • 启动服务端: bin/zkServer.sh start
  • 验证服务是否正常,用客户端连上去随便测试几个命令 bin/zkCli.sh -server 127.0.0.1:2181
  • JAVA客户端选择:原生的Api,ZkClient,Curator,这里我们选择Curator,它是一个Apache开源项目,相对原生的Api更简单易用
实现一个分布式锁

实现一个分布式锁,场景为ES build全量build索引时只能由单一进程来build,在进程build索引前先拿到锁才可以开始build,build完了得释放锁,在锁住的情况下如果程序挂了或者发布代码将进程kill了也得释放掉锁,否则后续的进程将再也无法拿到锁。之前实现过一个本地文件的版本,缺点在于无法应用到分布式场景下,且如果kill程序时暴力地使用了kill -9,进程退出无法清理锁文件将导致后续进程再也无法处理;利用ZooKeeper很好地解决了分布式和锁无法清理的问题,用ZooKeeper的临时节点,获取锁的时候试图创建节点,如果说节点已经存在则说明锁被别人拿着,如果创建成功则成功获取锁,程序结束删除节点,如果恰好进程异常终止甚至被无情的kill -9杀掉,那等一会在服务端无法和客户端取得重连的情况下,临时节点也会被清理掉,这样后续的进程又可以正常的运行了。代码如下,留了个接口,也可以自己实现别的锁逻辑。

接口

package BizLock;

public interface BizLock {

    public boolean getLock(String lockName) throws Exception;

    public void releaseLock(String lockName) throws Exception;

}

ZooKeeper实现的分布式锁

package BizLock;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;

public class ZkLock implements BizLock {

    /**
     * 这些变量可以写入配置中
     */
    private static final String nameSpace = "zkLock";
    private static final String zkUrl = "127.0.0.1:2181";

    private static ZkLock zkLock = null;
    private static CuratorFramework client = null;

    private ZkLock() {
        client = CuratorFrameworkFactory.newClient(zkUrl, new RetryNTimes(5, 5000));
        client.start();
        client.usingNamespace(nameSpace);
    }

    public static ZkLock getInstance() {
        if (zkLock == null) {
            zkLock = new ZkLock();
        }
        return zkLock;
    }

    public boolean getLock(String lockName) throws Exception{
        try {
            client.create().withMode(CreateMode.EPHEMERAL).forPath(getLockNode(lockName));
        } catch (KeeperException.NodeExistsException e) {
            return false;
        }
        return true;
    }

    public void releaseLock(String lockName) throws Exception{
        client.delete().forPath(lockName);
    }

    private String getLockNode(String loockName) {
        return "/"+loockName;
    }
}

参考:

《从Paxos到ZooKeeper》
http://zookeeper.apache.org/
http://curator.apache.org/

    原文作者:龟仙老人
    原文地址: https://www.jianshu.com/p/f630006b0993
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞