zookeeper基础学习

一、ZooKeeper简介

ZooKeeper是一个分布式服务框架,是Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。
ZooKeeper是一种分布式协调服务,所谓分布式协调服务可以在分布式系统中共享配置,协调锁资源,提供命名服务。
zookeeper是基于内存同步数据的,所以集群内的节点其内存中的数据结构是完全相同的,因此效率非常高。

二、Zookeeper特性

顺序一致性:从同一个客户端发起的事务请求,最终将会严格按照其发起顺序被应用到zookeeper中
可靠性:消息message被到一台服务器接受,那么它到任何服务器都被接受。
实时性:zk保证在一个时间间隔范围内获得服务器的更新信息,或者服务器失效信息。但是由于网络延时等一些其他原因,zk不能保证两个客户端同事得到跟新或者失效信息。
原子性:更新只能成功或者失败,没有其他中间信息。
单一视图:无论客户端连接的是哪个zookeeper服务器,其看到的服务端数据模型都是一致的

三、 Zookeeper的存储结构

1、Znode
在 Zookeeper中,znode是一个跟Unix文件系统路径相似的节点,可以往这个节点存储 或获取数据。Zookeeper底层是一套数据结构。这个存储结构是一个树形结构,其上的每一个节点, 我们称之为“znode”。zookeeper中的数据是按照“树”结构进行存储的。而且znode节点还分为4中不同的类型。每一个znode默认能够存储1MB的数据(对于记录状态性质的数据来说,够了)。可以使用 zkCli命令,登录到zookeeper上,并通过ls、create、delete、get、set等命令操作这些znode节点
2、Znode节点类型:
ZooKeeper中的节点有两种,分别为临时节点和永久节点。节点的类型在创建时即被确定,并且不能改变。
临时节点:该节点的生命周期依赖于创建它们的会话。一旦会话(Session)结束,临时节点将被自动删除,当然可以也可以手动删除。
虽然每个临时的Znode都会绑定到一个客户端会话,但他们对所有的客户端还是可见的。另外,ZooKeeper的临时节点不允许拥有子节点。
永久节点:该节点的生命周期不依赖于会话,并且只有在客户端显示执行删除操作的时候,他们才能被删除。
顺序节点:临时节点和持久节点都有可以创建顺序节点。顺序节点在创建时可以使用相同的节点名,创建后zookeeper会自动分配一个序号,追加在名字后面,从而保证节点名称唯一性。

四、ZooKeeper的角色

leader(领导者):负责进行投票的发起和决议,更新系统状态。
learner (学习者):包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并向客户端返回结果,在选举过程中参与投票。Observer可以接受客户端连接,将写请求转发给leader,但observer不参与投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
Client(客户端):执行读写请求的发起方

五、ZooKeeper中的选举机制

ZAB(ZooKeeper Atomic Broadcast 原子广播)协议是为分布式协调服务 ZooKeeper专门设计的一种支持崩溃恢复的原子广播协议。
在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议,ZooKeeper实现了一种主备模式的系统架构来保持集群中各个副本之间的数据一致性。
ZAB协议包括两种基本的模式,分别是崩溃恢复消息广播
当整个服务框架在启动过程中,或是当 Leader 服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB 协议就会进人恢复模式并选举产生新的Leader服务器。
当选举产生了新的 Leader 服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。
其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致。
当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个服务框架就可以进人消息广播模式了。
最大ZXID的概念:最大ZXID也就是节点本地的最新事务编号,包含epoch和计数两部分。epoch是纪元的意思,相当于Raft算法选主时候的term。
崩溃恢复过程:
假如Zookeeper当前的主节点挂掉了,集群会进行崩溃恢复。ZAB的崩溃恢复分成三个阶段:
1.Leader election:选举阶段
此时集群中的节点处于Looking状态。它们会各自向其他节点发起投票,投票当中包含自己的服务器ID和最新事务ID(ZXID);
接下来,节点会用自身的ZXID和从其他节点接收到的ZXID做比较,如果发现别人家的ZXID比自己大,也就是数据比自己新,那么就重新发起投票,投票给目前已知最大的ZXID所属节点;
每次投票后,服务器都会统计投票数量,判断是否有某个节点得到半数以上的投票。如果存在这样的节点,该节点将会成为准Leader,状态变为Leading。其他节点的状态变为Following。
2.Discovery:发现阶段
用于在从节点中发现最新的ZXID和事务日志。或许有人会问:既然Leader被选为主节点,已经是集群里数据最新的了,为什么还要从节点中寻找最新事务呢?
这是为了防止某些意外情况,比如因网络原因在上一阶段产生多个Leader的情况。
所以这一阶段,Leader集思广益,接收所有Follower发来各自的最新epoch值。Leader从中选出最大的epoch,基于此值加1,生成新的epoch分发给各个Follower。
各个Follower收到全新的epoch后,返回ACK给Leader,带上各自最大的ZXID和历史事务日志。Leader选出最大的ZXID,并更新自身历史日志。
3.Synchronization:同步阶段
把Leader刚才收集得到的最新历史事务日志,同步给集群中所有的Follower。只有当半数Follower同步成功,这个准Leader才能成为正式的Leader。

六、Zookeeper应用场景

1.分布式锁:这是雅虎研究员设计Zookeeper的初衷。利用Zookeeper的临时顺序节点,可以轻松实现分布式锁。
2.服务注册和发现:利用Znode和Watcher,可以实现分布式服务的注册和发现。最著名的应用就是阿里的分布式RPC框架Dubbo。
3.共享配置和状态信息:Redis的分布式解决方案Codis,就利用了Zookeeper来存放数据路由表和 codis-proxy 节点的元信息。同时 codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy。

此外,Kafka、HBase、Hadoop,也都依靠Zookeeper同步节点信息,实现高可用。

七、环境部署

ZooKeeper的工作模式有三种:单机模式、集群模式、伪集群模式。
Zookeeper单机模式安装
Step1:安装JDK,配置JAVA环境,检验环境:java -version
Step2:下载并解压zookeeper
Step3:重命名配置文件zoo_sample.cfg并修改,主要修改server地址和dataDir、dataLogdDir数据文件地址
Step4:启动zookeeper # bin/zkServer.sh start
Step5:检测是否成功启动
用zookeeper客户端连接下服务端 # bin/zkCli.sh
查看服务状态 # bin/zkServer.sh status

配置文件详解
tickTime=2000 # 这个时间是作为Zookeeper服务器之间或客户端与服务器之间维持心跳的时间间隔,每隔tickTime时间就会发送一个心跳;最小的session过期时间为2倍tickTime
initLimit=10 # 此配置表示,允许follower(相对于Leaderer言的“客户端”)连接并同步到Leader的初始化连接时间,以tickTime为单位。当初始化连接时间超过该值,则表示连接失败。
syncLimit=5 # 此配置项表示Leader与Follower之间发送消息时,请求和应答时间长度。如果follower在设置时间内不能与leader通信,那么此follower将会被丢弃。
dataDir=/data/zookeeper/ # 运行数据的存放路径
dataLogdDir=/path1 # 指定事务日志的存储路径,可以和dataDir在不同设备,这意味着可以使用一个日志的专用磁盘,避免日志IO和快照竞争。
clientPort=2181
server.1=192.168.20.201:2888:38888
server.2=192.168.20.203:2888:38888
server.3=192.168.20.56:2888:38888
# server.myid=ip:leader_port:inner_port
# myid 为服务器编号,用于标识服务器,这个值必须和dataDir目录下myid文件中的值保证一致
# ip 为当前服务器IP,
# leader_port Leader的端口
# inner_port zk服务器之间内部通信端口
# 同一个集群内的服务器,需要把该集群内的服务器列表信息都写在配置文件中。
snapCount 快照文件大小

八、客户端操作命令

客户端常用命令:
ls: 查看当前所有的节点
ls2: 查看当前所有的节点及更新信息
create:创建节点 create /name value
-e:临时节点 create -e /name value
-s:顺序节点 create -s /name value
delete:删除节点(不能有子节点)
rmr:递归删除节点
get:获得一个节点的数据
set:设置一个节点的数据
quit:退出客户端

九、Watcher监听

Zookeeper客户端在请求读操作的时候,可以选择是否设置Watch
Watch:可以理解成是注册在特定Znode上的触发器。当这个Znode发生改变,也就是调用了create,delete,setData方法的时候,将会触发Znode上注册的对应事件,请求Watch的客户端会接收到异步通知。
Watcher数据变更通知:
Zookeeper使用Watcher机制实现分布式数据的发布/订阅功能。
Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。客户端在向Zookeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager当中。
当Zookeeper服务器触发Watcher事件后,会向客户端发送通知,客户端线程从WatcherManager中取出对应的Watcher对象来执行回调逻辑。

十:java相关API

<dependency>
	<groupId>org.apache.zookeeper</groupId>
	<artifactId>zookeeper</artifactId>
	<version>3.5.6</version>
</dependency>

create:创建节点
delete:删除节点(不能有子节点)
exists:判断节点是否存在
getData:获得一个节点的数据
setData:设置一个节点的数据
getChildren:获取节点下的所有子节点
这其中,exists,getData,getChildren属于读操作。

public static void main(String[] args) throws Exception {
		/**
	     * 使用第一个构造器创建会话,刚创建完立刻打印会话状态为 CONNECTING
	     * 线程阻塞5秒,这5秒期间收到了服务端的Watcher通知 SyncConnected
	     * 之后会话状态为 CONNECTED
	     */
		ZooKeeper zookeeper = new ZooKeeper("127.0.0.1:2181", 5000, new Watcher() {
			public void process(WatchedEvent event) {
                // 获取时间的状态
                KeeperState keeperState = event.getState();
                EventType tventType = event.getType();
                // 如果是建立连接
                if (KeeperState.SyncConnected == keeperState) {
                    if (EventType.None == tventType) {
                        // 如果建立连接成功,则发送信号量,让后阻塞程序向下执行
                        System.out.println("zk 建立连接");
                    } else if(EventType.NodeDataChanged == tventType) {
                    	System.out.println("节点"+event.getPath()+"--->节点数据发生变化");
                    }
                }
            }
		});
	    System.out.println(zookeeper.getState());
	    Thread.sleep(2000);
	    System.out.println(zookeeper.getState());
	    //创建节点
	    zookeeper.create("/path", "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
	    
	    //获取节点数据
	    Stat stat=new Stat();
	    byte[] bytes = zookeeper.getData("/path",true, stat);
	    System.out.println("data--->" + new String(bytes));
	    System.out.println("stat--->" + stat);
	    
	    //修改节点数据
	    zookeeper.setData("/path", "data2".getBytes(),-1);//version 为-1 表示不作版本控制
	    
	    //删除节点
	    zookeeper.delete("/path", -1);
	    
	    //获得节点列表
	    List<String> childrens = zookeeper.getChildren("/path", true);
	    System.out.println(childrens);
	    
	}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值