Zookeeper 学习-应用场景及对应开发+操作命令+监控指标

 

Zookeeper 学习-应用场景及对应开发+操作命令+监控指标

 

转:ZooKeeper 的应用场景

https://zhuanlan.zhihu.com/p/59669985

0 Overview

ZooKeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架。

ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.

ZooKeeper 解决了什么问题?

高性能使得 ZooKeeper 能够应用于对系统吞吐有明确要求的大型分布式系统

高可用可以解决分布式的单点问题

具有严格的顺序访问控制能力,主要是针对写操作的严格顺序性,使得客户端可以基于 ZooKeeper 来实现一些复杂的同步原语

1 一些基本概念

ZooKeepr 提供基于类似于文件系统的目录节点树方式的数据存储,这是一个共享的内存中的树型结构。有几个概念需要关注一下。

Session 会话 客户端启动会与服务端建立一个 TCP 长连接,通过这个连接可以发送请求并接受响应,以及接受服务端的 Watcher 事件通知

Znode 数据节点 /xxxx 就是一个 Znode,会保存自己的数据内容和属性信息,分为持久和临时节点,节点有 SEQUENTIAL 属性

Version 版本 Stat 数据结构包含 version, cversion, aversion

Watcher 事件监听器 客户端可以在 Znode 上注册 Watcher,服务端将事件通知已注册的客户端

 

2 典型应用场景和实现

 

利用 ZooKeeper 可以非常方便构建一系列分布式应用中都会涉及到的核心功能。

 

    数据发布/订阅负载均衡命名服务分布式协调/通知集群管理Master 选举分布式锁分布式队列

 

多个开源项目中都应用到了 ZooKeeper,例如 HBase, Spark, Flink, Storm, Kafka, Dubbo 等等。

2.1 数据发布/订阅

 

数据发布/订阅的一个常见的场景是配置中心,发布者把数据发布到 ZooKeeper 的一个或一系列的节点上,供订阅者进行数据订阅,达到动态获取数据的目的。

 

配置信息一般有几个特点:

 

    数据量小的KV数据内容在运行时会发生动态变化集群机器共享,配置一致

 

 

 

ZooKeeper 采用的是推拉结合的方式。

 

    推: 服务端会推给注册了监控节点的客户端 Wathcer 事件通知拉: 客户端获得通知后,然后主动到服务端拉取最新的数据

 

实现的思路可以如下。

 

mysql.driverClassName=com.mysql.jdbc.Driver

dbJDBCUrl=jdbc:mysql://127.0.0.1/runzhlliu

username=runzhliu

password=runzhliu

 

    把配置信息写到一个 Znode 上,例如 /Configuration客户端启动初始化阶段读取服务端节点的数据,并且注册一个数据变更的 Watcher配置变更只需要对 Znode 数据进行 set 操作,数据变更的通知会发送到客户端,客户端重新获取新数据,完成配置动态修改

 

2.2 负载均衡

 

负载均衡是一种手段,用来把对某种资源的访问分摊给不同的设备,从而减轻单点的压力。

 

实现的思路:

 

    首先建立 Servers 节点,并建立监听器监视 Servers 子节点的状态(用于在服务器增添时及时同步当前集群中服务器列表)在每个服务器启动时,在 Servers 节点下建立临时子节点 Worker Server,并在对应的字节点下存入服务器的相关信息,包括服务的地址,IP,端口等等可以自定义一个负载均衡算法,在每个请求过来时从 ZooKeeper 服务器中获取当前集群服务器列表,根据算法选出其中一个服务器来处理请求

 

 

 

2.3 命名服务

 

命名服务就是提供名称的服务。ZooKeeper 的命名服务有两个应用方面。

 

    提供类 JNDI 功能,可以把系统中各种服务的名称、地址以及目录信息存放在 ZooKeeper,需要的时候去 ZooKeeper 中读取制作分布式的***生成器

 

利用 ZooKeeper 顺序节点的特性,制作分布式的***生成器,或者叫 id 生成器。(分布式环境下使用作为数据库 id,另外一种是 UUID(缺点:没有规律)),ZooKeeper 可以生成有顺序的容易理解的同时支持分布式环境的编号。

 

在创建节点时,如果设置节点是有序的,则 ZooKeeper 会自动在你的节点名后面加上序号,上面说容易理解,是比如说这样,你要获得订单的 id,你可以在创建节点时指定节点名为 order_[日期]_xxxxxx,这样一看就大概知道是什么时候的订单。

 

/

└── /order

    ├── /order-date1-000000000000001

    ├── /order-date2-000000000000002

    ├── /order-date3-000000000000003

    ├── /order-date4-000000000000004

    └── /order-date5-000000000000005

 

2.4 分布式协调/通知

 

一种典型的分布式系统机器间的通信方式是心跳。心跳检测是指分布式环境中,不同机器之间需要检测彼此是否正常运行。传统的方法是通过主机之间相互 PING 来实现,又或者是建立长连接,通过 TCP 连接固有的心跳检测机制来实现上层机器的心跳检测。

 

如果使用 ZooKeeper,可以基于其临时节点的特性,不同机器在 ZooKeeper 的一个指定节点下创建临时子节点,不同机器之间可以根据这个临时节点来判断客户端机器是否存活。

 

好处就是检测系统和被检系统不需要直接相关联,而是通过 ZooKeeper 节点来关联,大大减少系统的耦合。

2.5 集群管理

 

集群管理主要指集群监控和集群控制两个方面。前者侧重于集群运行时的状态的收集,后者则是对集群进行操作与控制。开发和运维中,面对集群,经常有如下需求:

 

    希望知道集群中究竟有多少机器在工作对集群中的每台机器的运行时状态进行数据收集对集群中机器进行上下线的操作

 

分布式集群管理体系中有一种传统的基于 Agent 的方式,就是在集群每台机器部署 Agent 来收集机器的 CPU、内存等指标。但是如果需要深入到业务状态进行监控,比如一个分布式消息中间件中,希望监控每个消费者对消息的消费状态,或者一个分布式任务调度系统中,需要对每个机器删的任务执行情况进行监控。对于这些业务紧密耦合的监控需求,统一的 Agent 是不太合适的。

 

利用 ZooKeeper 实现集群管理监控组件的思路:

 

在管理机器上线/下线的场景中,为了实现自动化的线上运维,我们必须对机器的上/下线情况有一个全局的监控。通常在新增机器的时候,需要首先将指定的 Agent 部署到这些机器上去。Agent 部署启动之后,会首先向 ZooKeeper 的指定节点进行注册,具体的做法就是在机器列表节点下面创建一个临时子节点,例如 /machine/[Hostname](下文我们以“主机节点”代表这个节点),如下图所示。

 

 

 

当 Agent 在 ZooKeeper 上创建完这个临时子节点后,对 /machines 节点关注的监控中心就会接收到“子节点变更”事件,即上线通知,于是就可以对这个新加入的机器开启相应的后台管理逻辑。另一方面,监控中心同样可以获取到机器下线的通知,这样便实现了对机器上/下线的检测,同时能够很容易的获取到在线的机器列表,对于大规模的扩容和容量评估都有很大的帮助。

2.6 Master 选举

 

分布式系统中 Master 是用来协调集群中其他系统单元,具有对分布式系统状态更改的决定权。比如一些读写分离的应用场景,客户端写请求往往是 Master 来处理的。

 

利用常见关系型数据库中的主键特性来实现也是可以的,集群中所有机器都向数据库中插入一条相同主键 ID 的记录,数据库会帮助我们自动进行主键冲突检查,可以保证只有一台机器能够成功。

 

但是有一个问题,如果插入成功的和护短机器成为 Master 后挂了的话,如何通知集群重新选举 Master?

 

利用 ZooKeeper 创建节点 API 接口,提供了强一致性,能够很好保证在分布式高并发情况下节点的创建一定是全局唯一性。

 

集群机器都尝试创建节点,创建成功的客户端机器就会成为 Master,失败的客户端机器就在该节点上注册一个 Watcher 用于监控当前 Master 机器是否存活,一旦发现 Master 挂了,其余客户端就可以进行选举了。

2.7 分布式锁

 

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,一般需要通过一些互斥的手段来防止彼此之间的干扰,以保证一致性。

2.7.1 排他锁

 

如果事务 T1 对数据对象 O1 加上了排他锁,那么加锁期间,只允许事务 T1 对 O1 进行读取和更新操作。核心是保证当前有且仅有一个事务获得锁,并且锁释放后,所有正在等待获取锁的事务都能够被通知到。

 

通过 ZooKeeper 上的 Znode 可以表示一个锁,/x_lock/lock。

 

    获取锁 所有客户端都会通过调用 create() 接口尝试在 /x_lock 创建临时子节点 /x_lock/lock。最终只有一个客户端创建成功,那么该客户端就获取了锁。同时没有获取到锁的其他客户端,注册一个子节点变更的 Watcher 监听。释放锁 获取锁的客户端发生宕机或者正常完成业务逻辑后,就会把临时节点删除。临时子节点删除后,其他客户端又开始新的一轮获取锁的过程。

 

2.7.2 共享锁

 

如果事务 T1 对数据对象 O1 加上了共享锁,那么当前事务 T1 只能对 O1 进行读取操作,其他事务也只能对这个数据对象加共享锁,直到数据对象上的所有共享锁都被释放。

 

通过 ZooKeeper 上的 Znode 表示一个锁,/s_lock/[HOSTNAME]-请求类型-序号。

 

/

├── /host1-R-000000001

├── /host2-R-000000002

├── /host3-W-000000003

├── /host4-R-000000004

├── /host5-R-000000005

├── /host6-R-000000006

└── /host7-W-000000007

 

    获取锁 需要获得共享锁的客户端都会在 s_lock 这个节点下面创建一个临时顺序节点,如果当前是读请求,就创建类型为 R 的临时节点,如果是写请求,就创建类型为 W 的临时节点。判断读写顺序 共享锁下不同事务可以同时对同一个数据对象进行读取操作,而更新操作必须在当前没有任何事务进行读写操作的情况下进行。 2.1 创建完节点后,获取 s_lock 的所有子节点,并对该节点注册子节点变更的 Watcher 监听 2.2 然后确定自己的节点序号在所有的子节点中的顺序 2.3 对于读请求,如果没有比自己小的子节点,那么表名自己已经成功获取到了共享锁,同时开始执行读取逻辑,如果有比自己序号小的写请求,那么就需要进行等待 2.4 接收到 Watcher 通知后重复 2.1释放锁 获取锁的客户端发生宕机或者正常完成业务逻辑后,就会把临时节点删除。临时子节点删除后,其他客户端又开始新的一轮获取锁的过程。

 

2.7.3 羊群效应

 

在 2.7.2 介绍的共享锁中,在判断读写顺序的时候会出现一个问题,假如 host4 在移除自己的节点的时候,后面 host5-7 都需要接收 Watcher 事件通知,但是实际上,只有 host5 接收到事件就可以了。因此以上的实现方式会产生大量的 Watcher 通知。这样会对 ZooKeeper 服务器造成了巨大的性能影响和网络冲击,这就是羊群效应。

 

改进的一步在于,调用 getChildren 接口的时候获取到所有已经创建的子节点列表,但是这个时候不要注册任何的 Watcher。当无法获取共享锁的时候,调用 exist() 来对比自己小的那个节点注册 Wathcer。而对于读写请求,会有不同的定义:

 

    读请求: 在比自己序号小的最后一个写请求节点注册 Watcher。写请求: 向比自己序号小的最后一个节点注册 Watcher。

 

2.8 分布式队列

2.8.1 FIFO

 

使用 ZooKeeper 实现 FIFO 队列,入队操作就是在 queue_fifo 下创建自增序的子节点,并把数据(队列大小)放入节点内。出队操作就是先找到 queue_fifo 下序号最下的那个节点,取出数据,然后删除此节点。

 

/queue_fifo

|

├── /host1-000000001

├── /host2-000000002

├── /host3-000000003

└── /host4-000000004

 

创建完节点后,根据以下步骤确定执行顺序:

 

    通过 get_children() 接口获取 /queue_fifo 节点下所有子节点通过自己的节点序号在所有子节点中的顺序如果不是最小的子节点,那么进入等待,同时向比自己序号小的最后一个子节点注册 Watcher 监听接收到 Watcher 通知后重复 1

 

2.8.2 Barrier

 

Barrier就是栅栏或者屏障,适用于这样的业务场景:当有些操作需要并行执行,但后续操作又需要串行执行,此时必须等待所有并行执行的线程全部结束,才开始串行,于是就需要一个屏障,来控制所有线程同时开始,并等待所有线程全部结束。

 

 

 

利用 ZooKeeper 的实现,开始时 queue_barrier 节点是一个已经存在的默认节点,并且将其节点的数据内容赋值为一个数字 n 来代表 Barrier 值,比如 n=10 代表只有当 /queue_barrier 节点下的子节点个数达到10才会打开 Barrier。之后所有客户端都会在 queue_barrier 节点下创建一个临时节点,如 queue_barrier/host1。

 

如何控制所有线程同时开始? 所有的线程启动时在 ZooKeeper 节点 /queue_barrier 下插入顺序临时节点,然后检查 /queue/barrier 下所有 children 节点的数量是否为所有的线程数,如果不是,则等待,如果是,则开始执行。具体的步骤如下:

 

    getData() 获取 /queue_barrier 节点的数据内容getChildren() 获取 /queue_barrier 节点下的所有子节点,同时注册对子节点列表变更的 Watche 监听。统计子节点的个数如果子节点个数不足10,那么进入等待接收 Watcher 通知后,重复2

 

如何等待所有线程结束? 所有线程在执行完毕后,都检查 /queue/barrier 下所有 children 节点数量是否为0,若不为0,则继续等待。

 

用什么类型的节点? 根节点使用持久节点,子节点使用临时节点,根节点为什么要用持久节点?首先因为临时节点不能有子节点,所以根节点要用持久节点,并且在程序中要判断根节点是否存在。 子节点为什么要用临时节点?临时节点随着连接的断开而消失,在程序中,虽然会删除临时节点,但可能会出现程序在节点被删除之前就 crash了,如果是持久节点,节点不会被删除。

3 ZooKeeper 在大型分布式系统的应用

3.1 Hadoop

 

Hadoop 利用 ZooKeeper 实现了高可用的功能,包括 HDFS 的 NameNode 和 YARN 的 ResourceManager。此外 YARN 的运行状态是利用 ZooKeeper 来存储的。

3.1.1 ResourceManager HA

 

 

 

    多个 RM 在 /yarn-leader-election/pseudo-yarn-rm-cluster 竞争创建锁节点注册 Watcher,创建锁成功的 RM 为 Active 节点,创建锁不成功的 RM 监听此节点,并成为 Stanby 状态当 Active RM 挂了,通知 Standby RM,开始新一轮竞争

 

3.1.2 Fencing

 

Fencing 一般指解决脑裂这样的问题,YARN 引入了 Fencing 机制,利用的是 ZooKeeper 数据节点的 ACL 权限控制。

 

如果 RM1 假死,此时 RM2 成为 Active 状态,当 RM1 恢复之后,会试图去更新 ZooKeeper 里的数据,但此时会发现写上了 ACL 权限的节点无法修改,这样就可以避免了脑裂。

3.2 Spark

 

Spark 对 ZooKeeper 的使用主要在以下几个类中。

 

org.apache.spark.deploy.master.ZooKeeperPersistenceEngine

org.apache.spark.deploy.master.ZooKeeperLeaderElectionAgent

 

3.2.1 ZooKeeperPersistenceEngine

 

ZooKeeperPersistenceEngine 这个类主要是用于 Spark Master 高可用的持久化工作。其实很容易理解,作为一个分布式内存计算框架,每个环节都有「崩溃」的可能性,那么能不能减少诸如宕机、网络问题带来的影响呢?那么就是将运行中的各个环节,或者说有助于恢复这个集群状态的信息持久化下来。

 

Spark 中有个参数 spark.deploy.recoveryMode,是当 Master 有问题的时候,重新启动恢复的时候用到的。有几个恢复的方式,从本地文件中恢复,又或者是本文介绍的,利用 ZooKeeper 存储状态,并从中恢复。

3.2.2 ZooKeeperLeaderElectionAgent

 

领导选举机制可以保证集群虽然存在多个 Master,但是只有一个 Master 是 Active 的,其他都会处于 Standby 状态。

 

应用 ZooKeeper 选主,利用 ZooKeeper 创建节点是强一致性的,可以保证在分布式高并发的情况下创建的节点一定是全局唯一的,因此只要 Spark 的一个 Master 被选为 Leader,那么在相应目录下,就一定只有这个 Master 是创建成功的,而其他 Master 会创建一个子节点的 Watcher,用于监控当前 Master 是否还存活,一旦他挂了,那么就会重新启动选主过程。

3.3 Kafka

 

Kafka 中大部分组件都应用了 ZooKeeper。

 

    Broker 注册 `/broker/ids/[0...N] 记录了 Broker 服务器列表记录,这个临时节点的节点数据是 ip 端口之类的信息。Topic 注册 /broker/topcs 记录了 Topic 的分区信息和 Broker 的对应关系生产者负载均衡 生产者需要将消息发送到对应的 Broker 上,生产者通过 Broker 和 Topic 注册的信息,以及 Broker 和 Topic 的对应关系和变化注册事件 Watcher 监听,从而实现一种动态的负载均衡机制。消息消费进度 Offset 记录 消费者对指定消息分区进行消息消费的过程中,需要定时将分区消息的消费进度 Offset 记录到 ZooKeeper 上,以便消费者进行重启或者其他消费者重新阶段该消息分区的消息消费后,能够从之前的进度开始继续系消费

 

3.4 Dubbo

 

Dubbo 基于 ZooKeeper 实现了服务注册中心。哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是 ip 地址和服务名称的对应关系。ZooKeeper 通过心跳机制可以检测挂掉的机器并将挂掉机器的 ip 和服务对应关系从列表中删除。

 

至于支持高并发,简单来说就是横向扩展,在不更改代码的情况通过添加机器来提高运算能力。通过添加新的机器向 ZooKeeper 注册服务,服务的提供者多了能服务的客户就多了。

 

 

 

3.5 Canal

 

Canal 的 HA 分为两部分,Canal server 和 Canal client 分别有对应的 HA 实现。

 

    Canal server: 为了减少对 Mysql dump 的请求,不同 server 上的 instance 要求同一时间只能有一个处于 running,其他的处于 Standby 状态。Canal client: 为了保证有序性,一份 instance 同一时间只能由一个 canal client 进行 get/ack/rollback 操作,否则客户端接收无法保证有序。

 

 

 

    Canal server 要启动某个 Canal instance 时都先向 Zookeeper 进行一次尝试启动判断,通过在 ZooKeeper 里创建临时节点的方式。创建 ZooKeeper 节点成功后,对应的 Canal server 就启动对应的 Canal instance,没有创建成功的 Canal instance 就会处于 Standby 状态,一旦 ZooKeeper 发现 Canal server A 创建的节点消失后,立即通知其他的 Canal server 再次进行步骤1的操作,重新选出一个 Canal server 启动 instance。Canal client 每次进行 connect 时,会首先向 ZooKeeper 询问当前是谁启动了 Canal instance,然后和其建立连接,一旦连接不可用,会重新尝试 connect。

 

4 Summary

 

由于 ZooKeeper 可以很好保证分布式环境中数据的强一致性,也是基于这个特点,使得越来越多的分布式系统将 ZooKeeper 作为核心组件进行封装使用。在以上提到的这些分布式系统的常见的应用场景下,利用 ZooKeeper 可以快速的实现相关的组件,而无需重新造*。

 

很多大型开源的分布式系统中应用 ZooKeeper 来实现组件的时候,一般都会考虑使用 Apache Curator 是 Netflix 公司开源的一个 ZooKeeper 客户端,提供了更高层次和更易用的操作 ZooKeeper 的接口。

 

转:zookeeper 测试应用

https://www.cnblogs.com/IcanFixIt/p/7882107.html

简单代码

HelloZookeeper

package com.zc.demo.zookeeper.sample2;

 

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.ZooKeeper;

public class HelloZooKeeper {

  public static void main(String[] args) throws IOException {

    String hostPort = "localhost:2181,localhost:2182,localhost:2183";

    String zpath = "/";

    List <String> zooChildren = new ArrayList<String>();

    ZooKeeper zk = new ZooKeeper(hostPort, 2000, null);

    if (zk != null) {

      try {

        zooChildren = zk.getChildren(zpath, false);

        System.out.println("Znodes of '/': ");

        for (String child: zooChildren) {

          //print the children

          System.out.println(child);

        }

      } catch (KeeperException e) {

        e.printStackTrace();

      } catch (InterruptedException e) {

        e.printStackTrace();

      }

    }

   }

}

 

发布订阅模式

Watcher接口实例

先运行ClusterMonitor

java -cp Demo1-0.0.1-SNAPSHOT.jar com.zc.demo.zookeeper.sample2.DataWatcher

 

其次运行五个ClusterClient  进程

java -cp Demo1-0.0.1-SNAPSHOT.jar com.zc.demo.zookeeper.sample2.DataUpdater

 

当节点数据变化时,DataWatcher能收到通知并获取节点数据

DataWatcher

package com.zc.demo.zookeeper.sample2;

 

import java.io.IOException;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooDefs;

import org.apache.zookeeper.ZooKeeper;

 

public class DataWatcher implements Watcher, Runnable {

  private static String hostPort = "localhost:2181,localhost:2182,localhost:2183";

  private static String zooDataPath = "/MyConfig";

  byte zoo_data[] = null;

  ZooKeeper zk;

 

  public DataWatcher() {

    try {

      zk = new ZooKeeper(hostPort, 2000, this);

      if (zk != null) {

        try {

          //Create the znode if it doesn't exist, with the following code:

          if (zk.exists(zooDataPath, this) == null) {

            zk.create(zooDataPath, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

          }

        } catch (KeeperException | InterruptedException e) {

          e.printStackTrace();

        }

      }

    } catch (IOException e) {

      e.printStackTrace();

    }

  }

  public void printData() throws InterruptedException, KeeperException {

    zoo_data = zk.getData(zooDataPath, this, null);

    String zString = new String(zoo_data);

    // The following code prints the current content of the znode to the console:

    System.out.printf("\nCurrent Data @ ZK Path %s: %s", zooDataPath, zString);

  }

  @Override

  public void process(WatchedEvent event) {

    System.out.printf(

    "\nEvent Received: %s", event.toString());

    //We will process only events of type NodeDataChanged

    if (event.getType() == Event.EventType.NodeDataChanged) {

      try {

        printData();

      } catch (InterruptedException e) {

        e.printStackTrace();

      } catch (KeeperException e) {

        e.printStackTrace();

      }

    }

  }

  public static void main(String[] args)

  throws InterruptedException, KeeperException {

    DataWatcher dataWatcher = new DataWatcher();

    dataWatcher.printData();

    dataWatcher.run();

  }

  public void run() {

    try {

      synchronized (this) {

        while (true) {

          wait();

        }

      }

    } catch (InterruptedException e) {

      e.printStackTrace();

      Thread.currentThread().interrupt();

    }

  }

}

DataUpdater

package com.zc.demo.zookeeper.sample2;

 

import java.io.IOException;

import java.util.UUID;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooKeeper;

public class DataUpdater implements Watcher {

  private static String hostPort = "localhost:2181,localhost:2182,localhost:2183";

  private static String zooDataPath = "/MyConfig";

  ZooKeeper zk;

 

  public DataUpdater() throws IOException {

    try {

      zk = new ZooKeeper(hostPort, 2000, this);

    } catch (IOException e) {

      e.printStackTrace();

    }

  }

 

// updates the znode path /MyConfig every 5 seconds with a new UUID string.

public void run() throws InterruptedException, KeeperException {

    while (true) {

      String uuid = UUID.randomUUID().toString();

      byte zoo_data[] = uuid.getBytes();

      zk.setData(zooDataPath, zoo_data, -1);

      System.out.printf("\nSet Data @ ZK Path %s: %s", zooDataPath, zoo_data);

      try {

        Thread.sleep(5000); // Sleep for 5 secs

      } catch(InterruptedException e) {

        Thread.currentThread().interrupt();

      }

    }

  }

 

public static void main(String[] args) throws

  IOException, InterruptedException, KeeperException {

    DataUpdater dataUpdater = new DataUpdater();

    dataUpdater.run();

  }

  @Override

  public void process(WatchedEvent event) {

    System.out.printf("\nEvent Received: %s", event.toString());

  }

}

 

示例群集监视器

先运行ClusterMonitor

java -cp Demo1-0.0.1-SNAPSHOT.jar com.zc.demo.zookeeper.sample2.ClusterMonitor localhost:2181,localhost:2182,localhost:2183

 

其次运行五个ClusterClient  进程

java -cp Demo1-0.0.1-SNAPSHOT.jar com.zc.demo.zookeeper.sample2.ClusterClient  localhost:2181,localhost:2182,localhost:2183 2>&1>/dev/null &

 

每启动一个ClusterClient进程是,  日志中显示增加一个成员

Zookeeper 学习-应用场景及对应开发+操作命令+监控指标

 

 

ClusterMonitor

package com.zc.demo.zookeeper.sample2;

 

import java.io.IOException;

import java.util.List;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooDefs.Ids;

import org.apache.zookeeper.ZooKeeper;

public class ClusterMonitor implements Runnable {

private static String membershipRoot = "/Members";

private final Watcher connectionWatcher;

private final Watcher childrenWatcher;

private ZooKeeper zk;

boolean alive=true;

public ClusterMonitor(String HostPort) throws IOException, InterruptedException, KeeperException {

    connectionWatcher = new Watcher() {

      @Override

      public void process(WatchedEvent event) {

        if(event.getType()==Watcher.Event.EventType.None && event.getState() == Watcher.Event.KeeperState.SyncConnected) {

            System.out.printf("\nEvent Received: %s", event.toString());

          }

      }

    };

 

    childrenWatcher = new Watcher() {

      @Override

      public void process(WatchedEvent event) {

        System.out.printf("\nEvent Received: %s", event.toString());

        if (event.getType() == Event.EventType.NodeChildrenChanged) {

            try {

              //Get current list of child znode,

              //reset the watch

              List<String> children = zk.getChildren( membershipRoot, this);

              wall("!!!Cluster Membership Change!!!");

              wall("Members: " + children);

            } catch (KeeperException e) {

              throw new RuntimeException(e);

            } catch (InterruptedException e) {

              Thread.currentThread().interrupt();

              alive = false;

              throw new RuntimeException(e);

            }

          }

      }

    };

 

    zk = new ZooKeeper(HostPort, 2000, connectionWatcher);

 

    // Ensure the parent znode exists

    if(zk.exists(membershipRoot, false) == null) {

      zk.create(membershipRoot, "ClusterMonitorRoot".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

    }

 

    // Set a watch on the parent znode

    List<String> children = zk.getChildren(membershipRoot, childrenWatcher);

    System.err.println("Members: " + children);

  }

 

  public synchronized void close() {

    try {

      zk.close();

    } catch (InterruptedException e) {

      e.printStackTrace();

    }

  }

 

  public void wall (String message) {

    System.out.printf("\nMESSAGE: %s", message);

  }

 

  public void run() {

    try {

      synchronized (this) {

        while (alive) {

          wait();

        }

      }

    } catch (InterruptedException e) {

      e.printStackTrace();

      Thread.currentThread().interrupt();

    } finally {

      this.close();

    }

  }

 

  public static void main(String[] args) throws IOException, InterruptedException, KeeperException {

    if (args.length != 1) {

      System.err.println("Usage: ClusterMonitor <Host:Port>");

      System.exit(0);

    }

    String hostPort = args[0];

    new ClusterMonitor(hostPort).run();

  }

}

ClusterClient

package com.zc.demo.zookeeper.sample2;

import java.io.IOException;

import java.lang.management.ManagementFactory;

import org.apache.zookeeper.CreateMode;

import org.apache.zookeeper.KeeperException;

import org.apache.zookeeper.WatchedEvent;

import org.apache.zookeeper.Watcher;

import org.apache.zookeeper.ZooDefs.Ids;

import org.apache.zookeeper.ZooKeeper;

public class ClusterClient implements Watcher, Runnable {

private static String membershipRoot = "/Members";

ZooKeeper zk;

public ClusterClient(String hostPort, Long pid) {

  String processId = pid.toString();

  try {

    zk = new ZooKeeper(hostPort, 2000, this);

  } catch (IOException e) {

    e.printStackTrace();

  }

  if (zk != null) {

    try {

      zk.create(membershipRoot + '/' + processId, processId.getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

    } catch (

      KeeperException | InterruptedException e) {

        e.printStackTrace();

      }

    }

  }

 

  public synchronized void close() {

    try {

      zk.close();

    }

    catch (InterruptedException e) {

      e.printStackTrace();

        }

  }

 

  @Override

  public void process(WatchedEvent event) {

    System.out.printf("\nEvent Received: %s", event.toString());

  }

 

  public void run() {

    try {

      synchronized (this) {

        while (true) {

          wait();

          }

      }

    } catch (InterruptedException e) {

      e.printStackTrace();

      Thread.currentThread().interrupt();

    } finally {

      this.close();

    }

  }

 

  public static void main(String[] args) {

    if (args.length != 1) {

      System.err.println("Usage: ClusterClient <Host:Port>");

      System.exit(0);

    }

    String hostPort = args[0];

    //Get the process id

    String name = ManagementFactory.getRuntimeMXBean().getName();

    int index = name.indexOf('@');

    Long processId = Long.parseLong(name.substring(0, index));

    new ClusterClient(hostPort, processId).run();

  }

}

 

示例群集监视器

使用zkCli命令能操作zookeeper内部节点

./zkCli.sh -server localhost:2181,localhost:2182,localhost:2183

可执行命令

ls /Configuration

create /Configuration "this is my app1"

set /Configuration myData3333

get /Configuration

delete /Configuration

 

zookeeper 操作命令

服务命令

     在准备好相应的配置之后,可以直接通过zkServer.sh 这个脚本进行服务的相关操作

    1. 启动ZK服务:       sh bin/zkServer.sh start

    2. 查看ZK服务状态: sh bin/zkServer.sh status

    3. 停止ZK服务:       sh bin/zkServer.sh stop

    4. 重启ZK服务:       sh bin/zkServer.sh restart

 

客户端命令

ZooKeeper命令行工具类似于Linux的shell环境,不过功能肯定不及shell啦,但是使用它我们可以简单的对ZooKeeper进行访问,数据创建,数据修改等操作.  使用 zkCli.sh -server 127.0.0.1:2181 连接到 ZooKeeper 服务,连接成功后,系统会输出 ZooKeeper 的相关环境以及配置信息。

 

命令行工具的一些简单操作如下:

 

    1. 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容

    2. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据

    3. 创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串

    4. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串

    5. 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置

    6. 删除文件: delete /zk 将刚才创建的 znode 删除

    7. 退出客户端: quit

    8. 帮助命令: help

 

 

转:zookeeper 监控指标

https://blog.csdn.net/hackerwin7/article/details/43559991

zookeeper自带的 four letter words command 获取各种各样的监控指标

conf:

能够获取到zookeeper的配置信息,包括客户端端口,数据以及日志路径,间隔单位时间,单台server与单个client端的连接数限制,

超时时间,serverId等等信息,选举端口。详细信息如下:

clientPort=2181

dataDir=/export/servers/zookeeper-3.4.6/data/version-2

dataLogDir=/export/servers/zookeeper-3.4.6/logs/version-2

tickTime=2000

maxClientCnxns=60

minSessionTimeout=4000

maxSessionTimeout=40000

serverId=2

initLimit=10

syncLimit=5

electionAlg=3

electionPort=3888

quorumPort=2888

peerType=0

 

 

cons:

连接信息的总览,、连接ip、端口号、该连接的发包数、该连接的收包数、连接的session Id、最后操作方式/命令、连接的时间戳、超时时间(未确认)、最后的zxid、最后的响应时间戳、连接的时间延时信息、等

详细信息如下:

/192.168.147.102:56168[1](queued=0,recved=60,sent=60,sid=0x24b3673bb141d0e,lop=PING,est=1422614959584,to=40000,lcxid=0x9,lzxid=0xffffffffffffffff,lresp=1422615627690,llat=1,minlat=0,avglat=0,maxlat=1) /192.168.162.16:43107[1](queued=0,recved=619,sent=643,sid=0x24b3673bb1419fa,lop=PING,est=1422610618969,to=30000,lcxid=0x7c,lzxid=0xffffffffffffffff,lresp=1422615623122,llat=0,minlat=0,avglat=1,maxlat=296) /192.168.162.16:43110[1](queued=0,recved=411,sent=427,sid=0x14b36741ee41b17,lop=PING,est=1422611808516,to=30000,lcxid=0x6d,lzxid=0xffffffffffffffff,lresp=1422615622028,llat=0,minlat=0,avglat=3,maxlat=444) /192.168.144.107:38698[1](queued=0,recved=2,sent=2,sid=0x24b3673bb141da3,lop=NA,est=1422615628413,to=20000,lcxid=0x1,lzxid=0x68000ad897,lresp=1422615629458,llat=2,minlat=0,avglat=1,maxlat=2) /192.168.162.16:43117[1](queued=0,recved=62,sent=62,sid=0x24b3673bb141d05,lop=PING,est=1422614913239,to=40000,lcxid=0x8,lzxid=0xffffffffffffffff,lresp=1422615620045,llat=1,minlat=0,avglat=1,maxlat=53) /192.168.144.98:34702[1](queued=0,recved=5027,sent=5027,sid=0x24b3673bb14001f,lop=PING,est=1422548712199,to=40000,lcxid=0xc,lzxid=0xffffffffffffffff,lresp=1422615622652,llat=1,minlat=0,avglat=1,maxlat=1151) /192.168.144.98:34135[1](queued=0,recved=7111,sent=7216,sid=0x24b3673bb140007,lop=PING,est=1422548006229,to=30000,lcxid=0x17d,lzxid=0xffffffffffffffff,lresp=1422615626940,llat=1,minlat=0,avglat=1,maxlat=1004) /192.168.162.16:43109[1](queued=0,recved=779,sent=832,sid=0x4b3673ce4a1a4d,lop=PING,est=1422611214674,to=30000,lcxid=0x7db,lzxid=0xffffffffffffffff,lresp=1422615623541,llat=0,minlat=0,avglat=1,maxlat=468) /192.168.147.102:56039[1](queued=0,recved=382437,sent=382437,sid=0x24b3673bb141c7a,lop=GETD,est=1422614382595,to=20000,lcxid=0x5d5e4,lzxid=0x68000ad89b,lresp=1422615629750,llat=0,minlat=0,avglat=0,maxlat=570) /192.168.147.101:44124[1](queued=0,recved=19853228,sent=19853228,sid=0x24b3673bb140000,lop=GETD,est=1422547738803,to=20000,lcxid=0x12eefa9,lzxid=0x68000ad89b,lresp=1422615629750,llat=0,minlat=0,avglat=0,maxlat=8325) /192.168.147.102:39271[1](queued=0,recved=4819,sent=4820,sid=0x24b3673bb1400cc,lop=PING,est=1422551694373,to=40000,lcxid=0x19,lzxid=0xffffffffffffffff,lresp=1422615627807,llat=0,minlat=0,avglat=1,maxlat=893) /192.168.144.107:45476[1](queued=0,recved=18796922,sent=18796922,sid=0x24b3673bb14038c,lop=GETD,est=1422555547627,to=20000,lcxid=0x11ed178,lzxid=0x68000ad89b,lresp=1422615629750,llat=0,minlat=0,avglat=0,maxlat=8325)

 /192.168.162.16:43124[0](queued=0,recved=1,sent=0) /192.168.144.106:47163[1](queued=0,recved=1919891,sent=1919891,sid=0x24b3673bb14003e,lop=GETD,est=1422549512849,to=20000,lcxid=0x1d4b8f,lzxid=0x68000ad897,lresp=1422615629580,llat=1,minlat=0,avglat=0,maxlat=2678) /172.17.36.11:32728[1](queued=0,recved=6009,sent=6021,sid=0x24b3673bb1403ca,lop=PING,est=1422555925304,to=30000,lcxid=0x31,lzxid=0xffffffffffffffff,lresp=1422615622868,llat=0,minlat=0,avglat=1,maxlat=513) /192.168.144.102:34378[1](queued=0,recved=6643,sent=6751,sid=0x24b3673bb1401d2,lop=PING,est=1422553000472,to=30000,lcxid=0x192,lzxid=0xffffffffffffffff,lresp=1422615623376,llat=1,minlat=0,avglat=1,maxlat=880) /192.168.162.16:43108[1](queued=0,recved=379,sent=379,sid=0x24b3673bb141a00,lop=PING,est=1422610718273,to=40000,lcxid=0xa,lzxid=0xffffffffffffffff,lresp=1422615629070,llat=0,minlat=0,avglat=2,maxlat=291) null[0](queued=0,recved=3,sent=2,sid=0x4b305d40f933dd,lop=GETC,est=1422615629686,to=30000,lcxid=0x1934a,lzxid=0x68000ad89b,lresp=1422615629689,llat=0,minlat=0,avglat=0,maxlat=0) /192.168.162.16:43112[1](queued=0,recved=376,sent=386,sid=0x4b3673ce4a1ab7,lop=PING,est=1422612058410,to=30000,lcxid=0x54,lzxid=0xffffffffffffffff,lresp=1422615621245,llat=0,minlat=0,avglat=1,maxlat=483) /192.168.147.102:56038[1](queued=1,recved=382733,sent=382732,sid=0x24b3673bb141c79,lop=GETD,est=1422614380708,to=20000,lcxid=0x5d70b,lzxid=0x68000ad89b,lresp=1422615629748,llat=59,minlat=0,avglat=0,maxlat=570) /192.168.144.103:45100[1](queued=0,recved=6816,sent=6903,sid=0x24b3673bb140040,lop=PING,est=1422549539691,to=30000,lcxid=0xe7,lzxid=0xffffffffffffffff,lresp=1422615623049,llat=0,minlat=0,avglat=1,maxlat=909) /192.168.144.107:45488[1](queued=1,recved=18790392,sent=18790391,sid=0x24b3673bb140391,lop=GETD,est=1422555569021,to=20000,lcxid=0x11eb7f5,lzxid=0x68000ad89b,lresp=1422615629748,llat=56,minlat=0,avglat=0,maxlat=8325) /192.168.144.107:38694[1](queued=0,recved=743,sent=743,sid=0x24b3673bb141da2,lop=GETD,est=1422615626179,to=20000,lcxid=0x2e6,lzxid=0x68000ad89b,lresp=1422615629750,llat=0,minlat=0,avglat=0,maxlat=59) /192.168.162.16:43115[1](queued=0,recved=159,sent=159,sid=0x24b3673bb141c69,lop=PING,est=1422614308831,to=30000,lcxid=0x1b,lzxid=0xffffffffffffffff,lresp=1422615624623,llat=0,minlat=0,avglat=2,maxlat=71) /192.168.144.107:38688[1](queued=0,recved=1442,sent=1442,sid=0x24b3673bb141da1,lop=GETD,est=1422615623769,to=20000,lcxid=0x5a1,lzxid=0x68000ad89b,lresp=1422615629750,llat=0,minlat=0,avglat=0,maxlat=170)

 

 

crst:

重置连接状态,是一个execute 操作 不是一个select 操作

执行后返回一个状态信息:

Connection stats reset.

 

 

dump:

输出所有等待队列中的会话和临时节点的信息

0x24b3673bb140000:

     /magpie/workerbeats/11011599

0x14b36741ee41de4:

     /phenix/servers/px0000000816

     /phenix/myGroups/1

0x14b049fe56b89e5:

     /hbase/rs/hhz111,60021,1422454057830

0x4b305d40f92989:

     /hbase/rs/hhz115,60021,1422521527024

0x14b36741ee41edc:

     /magpie/workerbeats/3502573

0x24b3673bb141dc6:

     /magpie/workerbeats/3002570

 

envi:

当前server的环境信息:

版本信息、主机的host、jvm相关参数:version,classpath,lib等等、os相关参数:name,version等等、当前host用户信息:name,dir等等

Environment:

zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT

host.name=hhz112

java.version=1.7.0_60

java.vendor=Oracle Corporation

java.home=/export/servers/jdk1.7.0_60/jre

java.class.path=/export/servers/zookeeper-3.4.6/bin/../build/classes:/export/servers/zookeeper-3.4.6/bin/../build/lib/*.jar:/export/servers/zookeeper-3.4.6/bin/../lib/slf4j-log4j12-1.6.1.jar:/export/servers/zookeeper-3.4.6/bin/../lib/slf4j-api-1.6.1.jar:/export/servers/zookeeper-3.4.6/bin/../lib/netty-3.7.0.Final.jar:/export/servers/zookeeper-3.4.6/bin/../lib/log4j-1.2.16.jar:/export/servers/zookeeper-3.4.6/bin/../lib/jline-0.9.94.jar:/export/servers/zookeeper-3.4.6/bin/../zookeeper-3.4.6.jar:/export/servers/zookeeper-3.4.6/bin/../src/java/lib/*.jar:/export/servers/zookeeper-3.4.6/bin/../conf:/export/servers/zookeeper-3.4.6/bin/../build/classes:/export/servers/zookeeper-3.4.6/bin/../build/lib/*.jar:/export/servers/zookeeper-3.4.6/bin/../lib/slf4j-log4j12-1.6.1.jar:/export/servers/zookeeper-3.4.6/bin/../lib/slf4j-api-1.6.1.jar:/export/servers/zookeeper-3.4.6/bin/../lib/netty-3.7.0.Final.jar:/export/servers/zookeeper-3.4.6/bin/../lib/log4j-1.2.16.jar:/export/servers/zookeeper-3.4.6/bin/../lib/jline-0.9.94.jar:/export/servers/zookeeper-3.4.6/bin/../zookeeper-3.4.6.jar:/export/servers/zookeeper-3.4.6/bin/../src/java/lib/*.jar:/export/servers/zookeeper-3.4.6/bin/../conf:.:/export/servers/jdk1.6.0_25/lib/dt.jar:/export/servers/jdk1.6.0_25/lib/tools.jar

java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib

java.io.tmpdir=/tmp

java.compiler=<NA>

os.name=Linux

os.arch=amd64

os.version=2.6.32-358.el6.x86_64

user.name=hhz

user.home=/home/hhz

user.dir=/export/servers/zookeeper-3.4.6

 

ruok:

查询当前server状态是否正常 若正常返回imok

imok

 

srst:

同样是一个execute操作而不是select,重置server状态:

Server stats reset.

 

srvr:

server的简要信息:

版本、延时、收包数、发包数、连接数、状态等信息

Zookeeper version: 3.4.6-1569965, built on 02/20/2014 09:09 GMT

Latency min/avg/max: 0/0/182

Received: 97182

Sent: 97153

Connections: 22

Outstanding: 8

Zxid: 0x68000af381

Mode: follower

Node count: 101065

 

 

stat:

一些状态信息和连接信息,是前面一些信息的组合:

Zookeeper version: 3.4.6-1569965, built on 02/20/2014 09:09 GMT

Clients:

 /192.168.147.102:56168[1](queued=0,recved=41,sent=41)

 /192.168.144.102:34378[1](queued=0,recved=54,sent=54)

 /192.168.162.16:43108[1](queued=0,recved=40,sent=40)

 /192.168.144.107:39948[1](queued=0,recved=1421,sent=1421)

 /192.168.162.16:43112[1](queued=0,recved=54,sent=54)

 /192.168.162.16:43107[1](queued=0,recved=54,sent=54)

 /192.168.162.16:43110[1](queued=0,recved=53,sent=53)

 /192.168.144.98:34702[1](queued=0,recved=41,sent=41)

 /192.168.144.98:34135[1](queued=0,recved=61,sent=65)

 /192.168.162.16:43109[1](queued=0,recved=54,sent=54)

 /192.168.147.102:56038[1](queued=0,recved=165313,sent=165314)

 /192.168.147.102:56039[1](queued=0,recved=165526,sent=165527)

 /192.168.147.101:44124[1](queued=0,recved=162811,sent=162812)

 /192.168.147.102:39271[1](queued=0,recved=41,sent=41)

 /192.168.144.107:45476[1](queued=0,recved=166422,sent=166423)

 /192.168.144.103:45100[1](queued=0,recved=54,sent=54)

 /192.168.162.16:43133[0](queued=0,recved=1,sent=0)

 /192.168.144.107:39945[1](queued=0,recved=1825,sent=1825)

 /192.168.144.107:39919[1](queued=0,recved=325,sent=325)

 /192.168.144.106:47163[1](queued=0,recved=17891,sent=17891)

 /192.168.144.107:45488[1](queued=0,recved=166554,sent=166555)

 /172.17.36.11:32728[1](queued=0,recved=54,sent=54)

 /192.168.162.16:43115[1](queued=0,recved=54,sent=54)

 

Latency min/avg/max: 0/0/599

Received: 224869

Sent: 224817

Connections: 23

Outstanding: 0

Zxid: 0x68000af707

Mode: follower

Node count: 101081

 

 

wchs:

有watch path的连接数 以及watch的path数 和 watcher数

13 connections watching 102 paths

Total watches:172

 

wchc:

连接监听的所有path:(考虑吧cons命令 信息整合)

0x24b3673bb14001f

              /hbase/root-region-server

              /hbase/master

 

wchp:

path被那些连接监听:(考虑把cons命令 信息整合)

/dubbo/FeedInterface/configurators

              0x4b3673ce4a1a4d

/dubbo/UserInterface/providers

              0x14b36741ee41b17

              0x4b3673ce4a1a4d

              0x24b3673bb1401d2

              0x4b3673ce4a1ab7

 

mntr:

用于监控zookeeper server 健康状态的各种指标:

版本、延时、收包、发包、连接数、未完成客户端请求数、leader/follower 状态、znode 数、watch 数、临时节点数、近似数据大小 应该是一个总和的值、打开文件描述符 数、最大文件描述符 数、fllower数等等

 

zk_version          3.4.6-1569965, built on 02/20/2014 09:09 GMT

zk_avg_latency  0

zk_max_latency 2155

zk_min_latency 0

zk_packets_received      64610660

zk_packets_sent              64577070

zk_num_alive_connections         42

zk_outstanding_requests             0

zk_server_state leader

zk_znode_count              101125

zk_watch_count              315

zk_ephemerals_count    633

zk_approximate_data_size          27753592

zk_open_file_descriptor_count  72

zk_max_file_descriptor_count    4096

zk_followers      2

zk_synced_followers      2

zk_pending_syncs           0

 

问题

Git pull失败提示用户信息

报错信息如下

[[email protected] myserver]# git pull

[email protected]'s password:

 

*** Please tell me who you are.

 

Run

 

  git config --global user.email "[email protected]"

  git config --global user.name "Your Name"

 

to set your account's default identity.

Omit --global to set the identity only in this repository.

 

fatal: unable to auto-detect email address (got '[email protected](none)')

 

解决方法

设置user.name以及user.email

git config --global user.name "myyiyi"

git config --global user.email "[email protected]"

 

Git pull失败提示合并冲突

报错信息如下

    error: Your local changes to the following files would be overwritten by merge:

              xxx/xxx/xxx.java

Please, commit your changes or stash them before you can merge.

Aborting

 

解决方法:

1、保留本地的修改 的改法

1)直接commit本地的修改

2)通过git stash 

git stash

git pull

git stash pop

通过git stash将工作区恢复到上次提交的内容,同时备份本地所做的修改,之后就可以正常git pull了,git pull完成后,执行git stash pop将之前本地做的修改应用到当前工作区。

git stash: 备份当前的工作区的内容,从最近的一次提交中读取相关内容,让工作区保证和上次提交的内容一致。同时,将当前的工作区内容保存到Git栈中。

git stash pop: 从Git栈中读取最近一次保存的内容,恢复工作区的相关内容。由于可能存在多个Stash的内容,所以用栈来管理,pop会从最近的一个stash中读取内容并恢复。

git stash list: 显示Git栈内的所有备份,可以利用这个列表来决定从那个地方恢复。

git stash clear: 清空Git栈。此时使用gitg等图形化工具会发现,原来stash的哪些节点都消失了。

 

2.放弃本地修改,直接覆盖

    git reset --hard

    git pull

 

 

链接

ZooKeeper 的应用场景

https://zhuanlan.zhihu.com/p/59669985

 

9. 使用ZooKeeper Java API编程

https://www.cnblogs.com/IcanFixIt/p/7882107.html

 

zookeeper 监控指标

https://blog.csdn.net/hackerwin7/article/details/43559991