ZooKeeper 笔记

1、分布式系统常见问题

部分失败:发生网络错误时候,发送者不知道接受者是否已经收到信息,接收者可能收到、可能没有、可能进程已死。发送者需要重新连接接收者,再次发送以确认。


2、ZooKeeper 用于正确处理部分失败‘,其特点是

(1)、ZooKeeper 核心是一个精简的文件系统,提供排序、通知等操作。

(2)、 富有表现力,可实现分布式队列、分布式锁、领导者选举等数据结构和协议。

(3)、具有高可用性,只要集群一半以上机器可以,则整体可能,可帮助系统避免出现单点故障。

(4)、采用松耦合方式,参与者不需要彼此了解,消息是异步的。

(5)、是一个资源库,提供了一个通用协调模式实现和方法的开源共享存储库。


3、ZooKeeper 的连接

当一个ZooKeeper 实例创建时候,会启动一个线程连接到ZooKeeper服务,由于对构造函数的调用是立即返回的,所以在使用新建ZooKeeper对象之前,一定要等到其与ZooKeeper服务之间的连接建立成功。可以使用以下两种方法。

(1)、使用CountDownLatch

public class ConnectionWatcher implements Watcher {

    protected static final int SESSION_TIMEOUT = 5000;

    protected ZooKeeper zk;
    protected CountDownLatch connectedSignal = new CountDownLatch(1);

    public void connect(String clusters) throws IOException, InterruptedException {
        this.zk = new ZooKeeper(clusters, SESSION_TIMEOUT, this);
        this.connectedSignal.await();
    }

    @Override
    public void process(WatchedEvent event) {
        if (event.getState() == KeeperState.SyncConnected) {
            this.connectedSignal.countDown();
        }
    }

    public void close() throws InterruptedException {
        if (this.zk != null) {
            this.zk.close();
        }
    }

}


(2). 使用 volatile 变量

public class ConnectionWatcher implements Watcher {

    protected static final int SESSION_TIMEOUT = 5000;

    protected ZooKeeper zk;
    private volatile boolean isConnectd = false;

    public void connect(String clusters) throws IOException {
        this.zk = new ZooKeeper(clusters, SESSION_TIMEOUT, this);
       while(!this.isConnectd)
       {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {  }
       }
    }

    @Override
    public void process(WatchedEvent event) {
        if (event.getState() == KeeperState.SyncConnected) {
            this.isConnectd=true;
        }
    }

    public void close() throws InterruptedException {
        if (this.zk != null) {
            this.zk.close();
        }
    }

}

4、ZooKeeper数据模型

znode 能存储的数据限制在 1MB 以内

ZooKeeper 的数据访问有原子性:读写znode要么全部成功,要么全部失败,不会部分读写。

znode类型:PERSISTENT、EPHEMERAL、PERSISTENT_SEQUENTIAL、EPHEMERAL_SEQUENTIAL

ZooKeeper 的 Watcher : 在读操作exists, getDate, getChildren  时候可以设置观察,有NodeCreatedNodeDataChangedNodeDeletedNodeChildrenChanged事件。

znode 的 ACL:可以通过用户名密码、客户机主机名、客户端IP 等进行身份认证。

znode的删除:不能递归,必须先删子节点,再删父节点


5、Zab 协议

ZooKeeper 确保对znode树的每一个修改都会被复制到集合体中超过半数的机器上。如果少于半数的机器出现故障,则最少有一台机器会保存最新的状态,其余副本最终也会更新到这个状态。

Zab 协议阶段:

(1). 所有机器选出一台leader,其余作为follower,一旦半数follower 与leader 同步,则表明这个阶段已经完成。

(2). 所有写请求先写给leader,再由leader广播给follower,在半数follower 持久化修改后,leader 才持久化,然后客户端才收到响应。故而协议具有原子性。

(3). 若leader死掉,则其余follower选出另外一个leader,原先的leader在重启后作为follower。


6、ZooKeeper 的数据一致性

(1). 顺序一致性:若客户端将znode 值设先设为a, 再设为b, 则没有客户端可能再先看到b之后再看到a

(2). 原子性:要么全部成功要么全部失败,不会部分更新

(3). 单系统映像:无论客户端连接到哪台服务器,其与系统看见的视图是一样的。

(4). 容错性:一旦更新成功,其结果将持久存在,不被撤销

(5). 及时性:任何客户端所看到系统视图的滞后都是有限的,不会超过几十秒。


7、会话

客户端的会话空闲超过一定时间,可以通过客户端发送心跳保持会话不过期(心跳由ZooKeeper客户端自动发送,不要用户代码维护)。

客户端可以自动进行故障切换,切换到另外一台服务器。

TickTime 一般为2秒,会话超时可以设置在 2个 TickTime 到 20 个 TickTime 之间。

ZooKeeper 集合体中的服务器越多,会话超时应该设置越大,可以对应用程序进行设计,在超时之前重启。

将会话ID 和 密码保存在数据库中,可以将应用程序关闭,然后在重启之前凭借所保存的会话ID 和 密码 来回复会话环境。


8. 状态

ZooKeeper.States:CONNECTING, ASSOCIATING, CONNECTED, CLOSED, AUTH_FAILED;

Watcher.KeeperState:  Disconnected, SyncConnected, AuthFailed, Expired, 


9. 异常恢复

InterruptedException  并不意味着故障,而是意味着操作已经取消,不需要恢复。

KeeperException.ConnectionLossException  此异常可恢复,一般需要重试操作

KeeperException.SessionExpiredException  此异常不可恢复,需要重新连接


以下异常按照具体的业务逻辑处理:

KeeperException.NoNodeException 

KeeperException.NodeExistException 

KeeperException.BadVersionException 

KeeperException.NoChildrebForEphemeralsException 

KeeperException.NoNodeException 


10.分布式锁服务

有两个客户端差不多同时创建znode,分别为/leader/lock-1,  /leader/lock-2 , 那么创建/leader/lock-1 的客户端将持有锁,行使Super权限。

如果leader 进程死亡,则/leader/lock-1 被删除, 此时创建 /leader/lock-2 的客户端将观察到 Watcher 事件,持有锁,行使Super权限。


11、生产环境中注意环节

(1)  ZooKeeper 应该运行在专用机器上,如果有其他程序竞争资源,将导致ZooKeeper性能明显下降。

(2)  将 dataDir 和 dataLogDir 保存在不同的磁盘下。所有写操作都由leader完成。

(3)  参数含义:

tickTime = 2000                // 单位毫秒,其实是2秒

clientPort = 2181

dataDir =/disk1/zookeeper

dataLogDir=/disk2/zookeeper

initLimit=5                         //  所有follower 与 leader 连接、同步的时间。如果在initLimit内,半数follower未完成同步,则leader 放弃领导地位,进行另一次leader 选举。

syncLimit=2                       // 某个follower 与 leader 连接、同步的时间。如果在syncLimit内,该follower未完成同步,则该follower 自己重启。


原文地址:https://www.cnblogs.com/leeeee/p/7276322.html